Skip to content

Sync Behavior

This page explains how each part of a Zabbix host is built from NetBox data, and how to control it. For a list of all settings, see Configuration.

Many features read the zabbix key in NetBox config context. Because config context can be assigned to sites, regions, roles, platforms, tags and more, you can set things like the interface type or proxy for whole groups of devices at once.

How a sync works

Each run reads the selected devices and VMs from NetBox and handles them one by one. The link between a NetBox object and its Zabbix host is the host ID stored in the zabbix_hostid custom field.

For each object, the script:

  1. Deletes the Zabbix host if the object has a removal status, and stops there.
  2. Determines the IP address, templates and hostgroups. If one of them is missing, the object is skipped with a warning.
  3. Creates the host in Zabbix if the object has no host ID yet, and stores the new ID in NetBox.
  4. Otherwise, compares the existing Zabbix host with NetBox and updates everything that differs: name, hostgroups, status, IPMI settings, proxy, inventory, usermacros, tags, interfaces and templates.

An error on one object is logged and the sync continues with the next one. Run the script with -v to see every change, or -vv to see why an object is skipped.

Some situations need attention:

  • The host name already exists in Zabbix, but the NetBox object has no host ID. The script does not take over existing hosts, and logs an error. To link them, enter the Zabbix host ID in the custom field by hand.
  • The host was deleted in Zabbix by hand, but NetBox still has its ID. The script logs an error. Clear the custom field to let the script create a new host.
  • The object was deleted in NetBox, or no longer matches the filter. The script only handles the objects it reads from NetBox, so the Zabbix host is left alone. Set a removal status in NetBox and run a sync before deleting the object.

Filtering

nb_device_filter and nb_vm_filter select which objects are synced. They are passed to the NetBox API as filters, so any filter that the NetBox API supports for devices or VMs can be used. The default, {"name__n": "null"}, selects every object that has a name.

# Only devices with the tag "zabbix"
nb_device_filter = {"tag": "zabbix"}

# Devices in site HQ-AMS or HQ-FRA
nb_device_filter = {"site": ["HQ-AMS", "HQ-FRA"]}

# Devices in site HQ-AMS with the tag zabbix, except PDUs and console servers
nb_device_filter = {"site": "HQ-AMS", "tag": "zabbix", "role__n": ["PDU", "console-server"]}

# No filter
nb_device_filter = {}

Device and VM status

The NetBox status of a device or VM decides what happens to its Zabbix host:

NetBox status Zabbix host Setting
Decommissioning, Inventory Deleted zabbix_device_removal
Offline, Planned, Staged, Failed Created or kept, but disabled zabbix_device_disable
Any other status, such as Active Created or kept, and enabled

Change the lists in config.py to match your own workflow. The values are the status labels as shown in NetBox, and are case-sensitive.

When a host is deleted, the script also clears the zabbix_hostid custom field in NetBox.

Virtual machines

By default only devices are synced. To also sync virtual machines:

  1. Assign the zabbix_hostid custom field (or the field set in device_cf) to Virtual machine objects in NetBox.
  2. Set sync_vms = True in config.py.

Virtual machines differ from devices in a few ways:

  • Templates always come from config context, since VMs have no device type.
  • The hostgroup layout is set with vm_hostgroup_format, which defaults to cluster_type/cluster/role. See Hostgroups for the available fields.
  • Without interface config context, VMs get a Zabbix agent interface instead of SNMP.
  • Out-of-band interfaces and IPMI settings are not supported for VMs.
  • VMs are selected with nb_vm_filter. Not every filter that works for devices works for VMs, and the other way around; see the NetBox API documentation for the filters each object type supports.

Hostgroups

Each host is placed in one or more hostgroups that are built from NetBox data, using a layout you define.

With create_hostgroups = True (the default), missing hostgroups are created in Zabbix, including all parent groups. For instance, the region Berlin with parent region Germany creates both Germany and Germany/Berlin. Creating hostgroups requires a Super admin account; see Permissions. With create_hostgroups = False, you need to create every hostgroup yourself, otherwise new hosts are skipped.

Note

The script sets the complete list of hostgroups on every run, so hostgroups added to a host by hand in Zabbix are removed.

Warning

Hostgroups are never deleted, even when no host uses them anymore.

Layout

The layout is set with hostgroup_format for devices and vm_hostgroup_format for VMs. The default for devices is site/manufacturer/role. Separate the fields with /:

hostgroup_format = "tenant/site/location/role"

To put each host in multiple hostgroups, use a list:

hostgroup_format = ["region/site_group/site", "role", "tenant_group/tenant"]

The following fields are available:

Devices and virtual machines

Field Description
role Role of the device or VM
site Site name
region Region of the site. See Group traversal
site_group Site group of the site. See Group traversal
tenant Tenant name
tenant_group Tenant group name
platform Platform name
Custom fields See Custom fields

Devices only

Field Description
manufacturer Manufacturer of the device type
location Location name
rack Rack name

Virtual machines only

Field Description
cluster Cluster name
cluster_type Cluster type name

The layout is checked when the sync starts. If it contains an unknown field, the sync stops with an error.

Fixed text

To add fixed text to a hostgroup name, put it between quotes:

hostgroup_format = "'MyDevices'/location/role"

All hostgroups generated with this layout start with MyDevices.

Group traversal

By default, region is only the region the site is directly assigned to. With traverse_regions = True, the full region path is used instead, for example Europe/Germany/Berlin instead of Berlin. traverse_site_groups does the same for site groups.

Custom fields

The value of a custom field can be used in the hostgroup name, by using the custom field name as a field in the layout. This allows for more freedom, up to a completely static mapping instead of a generated hostgroup name.

The custom field must be assigned to devices (or VMs, for vm_hostgroup_format) and be of the type Text, Selection or Object. For Object fields, the name of the linked object is used.

For instance, a custom field mycustomfieldname has the following values for 2 devices:

Device A has the value Train for custom field mycustomfieldname.
Device B has the value Bus for custom field mycustomfieldname.
Both devices are located in the site Paris.

With the layout site/mycustomfieldname the following hostgroups are generated:

Device A: Paris/Train
Device B: Paris/Bus

Empty fields

If a field has no value for a host, that level is left out of the hostgroup name.

For example, take 2 devices with the role PDU in the site HQ-AMS. Only one of them has a tenant.

hostgroup_format = "site/tenant/role"

This generates the following hostgroups:

  • Device A, without a tenant: HQ-AMS/PDU
  • Device B, with the tenant "Fork Industries": HQ-AMS/Fork Industries/PDU

The same applies to custom fields. With the layout site/mycustomfieldname, a device with the value ABC123 gets HQ-AMS/ABC123, and a device without a value gets HQ-AMS.

If none of the fields in a layout have a value, no hostgroup can be generated and the host is skipped:

hostgroup_format = "mycustomfieldname"

NetBox-Zabbix-sync - WARNING - Host ESXI1: Generating hostgroup name for 'mycustomfieldname' failed. This is most likely due to fields that have no value.
NetBox-Zabbix-sync - WARNING - Host ESXI1: has no valid hostgroups, Skipping this host...

Template source

Templates are linked by name, and every template must exist in Zabbix. If a template cannot be found, or a host has no template at all, the host is skipped.

Note

The script sets the complete list of templates on every run. Templates linked to a host by hand in Zabbix are unlinked and cleared.

For devices, templates come from a custom field on the device type, from config context, or from both. Virtual machines always use config context.

Custom field (default). The template is read from the zabbix_template custom field on the device type. This allows one template per device type.

Config context. To link multiple templates, or to choose templates per site, role, tag and so on, use config context:

templates_config_context = True

Make sure every host has at least one template in its config context, in this format:

{
    "zabbix": {
        "templates": [
            "TemplateA",
            "TemplateB"
        ]
    }
}

A single template can also be given as a string: "templates": "TemplateA".

Both. To use the device type custom field by default, but use config context templates instead for devices that have them:

templates_config_context_overrule = True

Keep in mind that config context is merged from all contexts that apply to a device. If a template is set in a context with a broad scope, such as a site or region, it overrules the custom field for every device in that scope.

Clustering

NetBox virtual chassis group several devices, such as stacked switches or a firewall cluster, that are managed as one. By default, every member device becomes its own Zabbix host. With clustering = True, the whole virtual chassis becomes a single Zabbix host instead:

  • The master device of the virtual chassis is synced, using the name of the virtual chassis as the host name. Its IP address, templates and other settings are used for the host.
  • The other members are skipped.
  • A virtual chassis without a master is skipped with a warning. Set the master in NetBox.

When the master changes, for example after a failover, the new master has no host ID yet. If exactly one other member still holds a host ID, the new master takes it over and keeps the existing Zabbix host and its history. If more than one member holds an ID, nothing is transferred and a warning is logged. The removal status of a member that is not the master never deletes the cluster host.

By default, only basic virtual chassis data such as the name is available for inventory, tag and usermacro maps. With extended_virtual_chassis = True, all virtual chassis properties and its members are fetched as well, at the cost of extra API calls.

Set Interface parameters within NetBox

Every Zabbix host gets one interface on the primary IP address of the device or VM. Hosts without a primary IP address (or a DNS name) are skipped.

Without config context, the following interface is used:

Devices Virtual machines
Type SNMPv2 Zabbix agent
Port 161 10050
Details Bulk requests enabled, community {$SNMP_COMMUNITY}

To use a different interface, set interface_type and optionally interface_port in config context. The type can be agent, snmp, ipmi or jmx, or the Zabbix type number (1 to 4). Without a port, the default port of the type is used: 10050 for agent, 161 for SNMP, 623 for IPMI and 12345 for JMX.

Config context lets you choose the interface per group of devices. For example, you could:

  • Set the config context on a device role or platform
  • Set the config context on a site or region
  • Set the config context on a tag, which you then add to devices (for instance, an snmpv3 tag)
  • Set the config context directly on a device

The script manages all interfaces of the host. Interfaces added to the host by hand in Zabbix are removed.

Important

Zabbix does not allow changing the type of an interface that is used by template items. Changing the interface type in NetBox for an existing host is therefore not supported, and results in an error:

NetBox-Zabbix-sync - ERROR - Host Device: Changing interface type to 1 is not supported.
To change the type, delete the host in Zabbix, clear its zabbix_hostid in NetBox, and let the script recreate it.

Agent interface configuration example

Configures a Zabbix agent interface on the default port.

{
    "zabbix": {
        "interface_type": "agent",
        "interface_port": 10050
    }
}

SNMPv2 interface configuration example

Configures an SNMPv2 interface. version is required. bulk defaults to 1, and community defaults to {$SNMP_COMMUNITY}. Use "version": 1 for SNMPv1.

{
    "zabbix": {
        "interface_type": "snmp",
        "interface_port": 161,
        "snmp": {
            "version": 2,
            "community": "{$SNMP_COMMUNITY}",
            "bulk": 1
        }
    }
}

SNMPv3 interface configuration example

Configures an SNMPv3 interface. The supported options are securityname, securitylevel, authpassphrase, privpassphrase, authprotocol, privprotocol and contextname. See the Zabbix API reference for their values.

{
    "zabbix": {
        "interface_type": "snmp",
        "interface_port": 161,
        "snmp": {
            "version": 3,
            "bulk": 1,
            "securityname": "MySecurityName",
            "securitylevel": 1,
            "authpassphrase": "{$SNMP_AUTH}"
        }
    }
}

Data in NetBox config context is stored in plain text. We recommend using usermacros for sensitive values such as community strings and passphrases, as in the examples above.

IPMI interface configuration example

Note

Added in v4.1. Only supported for devices.

Configures an IPMI interface, together with the IPMI credentials of the host. username and password are required; authtype and privilege are optional.

{
    "zabbix": {
        "interface_type": "ipmi",
        "interface_port": 623,
        "ipmi": {
            "username": "{$IPMI.USERNAME}",
            "password": "{$IPMI.PASSWORD}",
            "authtype": "md5",
            "privilege": "operator"
        }
    }
}

You can use usermacros for the username and password, so the secrets can be stored in Zabbix secret macros or a vault instead of in NetBox.

Option Allowed values
authtype default, none, md2, md5, straight, OEM, rmcp+
privilege callback, user, operator, admin, OEM

If they are not set, Zabbix uses the authentication type default and the privilege user.

Out-of-band interfaces

Note

Added in v4.1. Only supported for devices.

NetBox lets you assign an out-of-band (OOB) IP address to devices. With oob_sync = True, the script adds a second Zabbix interface on that address. Configure it in config context with oob_interface_type and oob_interface_port, which work like interface_type and interface_port:

{
    "zabbix": {
        "oob_interface_type": "ipmi",
        "oob_interface_port": 623
    }
}

The primary and OOB interfaces must be of different types. For example:

  • primary: agent, OOB: SNMP
  • primary: agent, OOB: IPMI
  • primary: SNMP, OOB: IPMI

Two interfaces of the same type result in an error, and the host is skipped. Without oob_interface_type, the OOB interface defaults to SNMPv2, so set it explicitly when the primary interface also uses SNMP.

The snmp and ipmi settings in config context are shared by both interfaces. This example uses a Zabbix agent on the primary IP and IPMI on the OOB IP:

{
    "zabbix": {
        "interface_type": "agent",
        "interface_port": 10050,
        "oob_interface_type": "ipmi",
        "oob_interface_port": 623,
        "ipmi": {
            "username": "{$IPMI.USERNAME}",
            "password": "{$IPMI.PASSWORD}",
            "authtype": "md5",
            "privilege": "operator"
        }
    }
}

IP address selection

Note

Added in v4.1.

When a device or VM has both an IPv4 and an IPv6 primary address, preferred_ip decides which one the interface uses:

Value Address used
auto (default) The primary IP that NetBox reports. NetBox prefers IPv6 unless its PREFER_IPV4 setting is enabled
ipv4 The primary IPv4 address, or the IPv6 address if there is no IPv4 address
ipv6 The primary IPv6 address, or the IPv4 address if there is no IPv6 address

Syncing DNS names

Note

Added in v4.1.

With extended_ips = True, the script fetches the DNS name of the primary and OOB IP addresses and adds it to the interfaces.

Zabbix connects to the IP address by default. Set prefer_dns = True to connect to the DNS name instead, when one is known. Hosts that have a DNS name but no IP address always use the DNS name.

Advanced interface configuration

Note

Added in v4.1.

You can override the IP address and DNS name of the interfaces in config context with interface_ip and interface_dns, or oob_interface_ip and oob_interface_dns for the OOB interface. For example, to let a Zabbix proxy that runs on the host itself reach the agent on localhost:

{
    "zabbix": {
        "proxy": "yourawesomeproxy.local",
        "interface_type": "agent",
        "interface_port": 10050,
        "interface_ip": "127.0.0.1",
        "interface_dns": "localhost"
    }
}

This also makes it possible to monitor devices or VMs without an IP address in NetBox, such as a device with a dynamic IP and a dynamic DNS name. With Jinja2 rendering (experimental) enabled, the value can be built from NetBox data. For example, this config context derives the DNS name from the host name:

{
    "zabbix": {
        "interface_dns": "{{ data['name'] | lower() }}.mydomain.com"
    }
}

Zabbix proxy

A host can be monitored by a Zabbix proxy or, on Zabbix 7.0 and later, by a proxy group. The proxy can be set in config context or in a custom field. If the proxy cannot be found in Zabbix, a warning is logged and the host is synced without one.

By default, the script only adds and changes proxies. When no proxy is configured in NetBox but the Zabbix host has one, the proxy is left in place and a warning is logged. Set full_proxy_sync = True to remove the proxy from those hosts instead. Make sure every host that needs a proxy has one configured in NetBox before you enable this.

Config Context

Set the proxy for a host with the proxy key:

{
    "zabbix": {
        "proxy": "yourawesomeproxy.local"
    }
}

On Zabbix 7.0 and later, you can use a proxy group with the proxy_group key. Older Zabbix releases ignore this key.

{
    "zabbix": {
        "proxy_group": "yourawesomeproxygroup.local"
    }
}

When both are set, the proxy group takes priority, since groups are more resilient. This also makes it easy to migrate from a proxy to a proxy group: add the group, and the host moves to it.

{
    "zabbix": {
        "proxy": "yourawesomeproxy.local",
        "proxy_group": "yourawesomeproxygroup.local"
    }
}

In this example, the host uses the proxy group on Zabbix 7 and the proxy on Zabbix 6.

Custom Field

You can also set the proxy or proxy group in a custom field on devices and VMs. Use a Text field with the name of the proxy, or an Object field. Configure the names of your custom fields in config.py:

proxy_cf = "zabbix_proxy"
proxy_group_cf = "zabbix_proxy_group"

The custom fields can also be assigned to sites, to configure the same proxy for every device and VM in a site. This requires extended_site_properties = True.

The proxy is chosen in this order:

  1. A proxy group, before a proxy
  2. The custom field of the device or VM
  3. The custom field of the site
  4. Config context

Zabbix Inventory

The script can enable the inventory of Zabbix hosts and fill inventory fields with NetBox data.

Set the inventory mode with inventory_mode: disabled, manual or automatic. To fill the inventory from NetBox, also set inventory_sync = True. Inventory sync needs manual or automatic mode.

inventory_mode = "manual"
inventory_sync = True

Use device_inventory_map and vm_inventory_map to choose which NetBox field goes into which Zabbix inventory field. The key is the NetBox field, and nested fields are separated with /. The value is the inventory field. For example, to put the custom field mycustomfield in the alias inventory field:

device_inventory_map = {"custom_fields/mycustomfield": "alias"}
vm_inventory_map = {"custom_fields/mycustomfield": "alias"}

For a custom field of type Object, add the property of the linked object, for example custom_fields/mycustomfield/name.

See config.py.example for an extensive default map. Inventory fields that are not in the map are not touched by the script, so you can still fill them by hand or with items. Fields in the map that are empty in NetBox are cleared in Zabbix.

Tags

The script can sync host tags to Zabbix, for use in filtering, SLA calculations and event correlation. Tags can come from three sources:

  1. NetBox tags of the device or VM
  2. Config context
  3. NetBox fields

To enable tag sync:

tag_sync = True

Note

Syncing tags replaces all tags on the host, so tags set by hand in Zabbix are removed. NetBox is the single source of truth for tags.

By default, tag names and values are converted to lowercase. Set tag_lower = False to keep them as they are. Tags with an empty value are skipped.

NetBox tags

NetBox tags have no name/value pair, so each NetBox tag becomes a Zabbix tag with a fixed name, set with tag_name. The value is the name, slug or display property of the NetBox tag, set with tag_value.

tag_name = "NetBox"
tag_value = "name"

Set tag_name = False to not sync NetBox tags.

Tags from config context

You can add tags in config context, as a list of name/value pairs:

{
    "zabbix": {
        "tags": [
            {
                "MyTagName": "MyTagValue"
            },
            {
                "environment": "production"
            }
        ]
    }
}

This lets you assign tags with the config context rules.

Tags from NetBox fields

NetBox fields can also be used as tags, in the same way as the inventory map. The key is the NetBox field and the value is the tag name:

device_tag_map = {"site/name": "site",
                  "rack/name": "rack",
                  "platform/name": "target"}

vm_tag_map = {"site/name": "site",
              "cluster/name": "cluster",
              "platform/name": "target"}

The maps above are the defaults. To turn off tags from fields, set the maps to empty dictionaries:

device_tag_map = {}
vm_tag_map = {}

Usermacros

The script can use NetBox as the source for host usermacros:

usermacro_sync = True

Warning

Enabling this option clears any usermacros set by hand on the managed hosts, and replaces them with the usermacros from NetBox.

Usermacros can come from two sources:

  1. Config context
  2. NetBox fields

Macro names must follow the Zabbix format: {$NAME}, using capital letters, numbers, . and _, with an optional context. Macros with an invalid name, or a value longer than 2048 characters, are skipped with a warning.

Usermacros from config context

Define a usermacros dictionary in the zabbix key of config context. This way you can set usermacros for anything you can target with config contexts.

A macro can be a plain value, which creates a text macro, or a dictionary with these keys:

Key Description
value The value. Required
type text (default), secret or vault, in lowercase
description Description of the macro in Zabbix
{
    "zabbix": {
        "usermacros": {
            "{$USER_MACRO}": "test value",
            "{$CONTEXT_MACRO:\"test\"}": "test value",
            "{$CONTEXT_REGEX_MACRO:regex:\".*\"}": "test value",
            "{$SECRET_MACRO}": {
                "type": "secret",
                "value": "PaSsPhRaSe"
            },
            "{$VAULT_MACRO}": {
                "type": "vault",
                "value": "secret/vmware:password"
            },
            "{$USER_MACRO2}": {
                "type": "text",
                "value": "another test value",
                "description": "Set by NetBox"
            }
        }
    }
}

The Zabbix API does not return the value of secret macros, so the script cannot compare them with NetBox. By default, secret macros are only written when they are created or when other macros change. To update a secret macro, remove it from the host in Zabbix, and the new value is synced on the next run. Alternatively, update secret macros on every run with:

usermacro_sync = "full"

Keep in mind that NetBox shows config context, including secrets, in plain text. If secrecy is required, use vault macros.

Usermacros from NetBox fields

NetBox fields can be used as usermacros with device_usermacro_map and vm_usermacro_map, in the same way as the inventory map. The key is the NetBox field and the value is the macro name. Only text macros can be created this way.

usermacro_sync = True
device_usermacro_map = {"serial": "{$HW_SERIAL}",
                        "role/name": "{$DEV_ROLE}",
                        "display_url": "{$NB_URL}",
                        "id": "{$NB_ID}"}
vm_usermacro_map = {"memory": "{$TOTAL_MEMORY}",
                    "role/name": "{$DEV_ROLE}",
                    "display_url": "{$NB_URL}",
                    "id": "{$NB_ID}"}

These maps are used by default, so enabling usermacro_sync adds these macros to every host. Set the maps to empty dictionaries to only use config context. display_url is the link to the object in the NetBox UI; url is the link to the object in the NetBox API.

Zabbix host description

The description of new Zabbix hosts is set with the description setting:

Value Description
"static" (default) Host added by NetBox sync script.
"dynamic" Host by owner {owner} added by NetBox sync script on {datetime}.
Any other text Your own text, which can use the flags below
False No description

You can also set a description per object in config context. This overrides the description setting.

{
    "zabbix": {
        "description": "This is the host description"
    }
}

The following flags can be used in the description:

Flag Description Example
{owner} The owner of the NetBox object. Needs NetBox 4.5 or later Sysadmins
{datetime} The date and time the host was created. Change the format with description_dt_format 2026-02-01 14:00:00

If a description contains an unknown flag, the static description is used instead and a warning is logged.

The description is only set when the host is created. Changing the setting or the config context does not change the description of existing hosts.

Journal entries

With create_journal = True, the script adds a journal entry to the NetBox object whenever it changes the Zabbix host: when the host is created, updated or deleted, when an interface is changed, and when a cluster host is taken over. This lets users see what happened in Zabbix without leaving NetBox. The NetBox account needs permission to add journal entries.

Extended site properties

By default, NetBox only returns the following site properties for a device or VM:

  • id
  • (API) url
  • display name
  • name
  • slug
  • description

With extended_site_properties = True, the script fetches all site properties, such as the latitude, longitude and custom fields. You can then use them in inventory, tag and usermacro maps, for example site/latitude. It is also required to read proxy custom fields from the site.

Keep in mind that this option increases the number of API calls to NetBox, which can slow down large syncs. extended_virtual_chassis and extended_ips work in the same way for virtual chassis and IP addresses.

Host names with special characters

Zabbix only allows letters, numbers, spaces, dots, dashes and underscores in host names. If a NetBox name contains German umlauts (ä, ö, ü), ß or Cyrillic characters, the script uses NETBOX_ID<id> as the technical host name, for example NETBOX_ID42, and sets the NetBox name as the visible name of the host.