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:
- Deletes the Zabbix host if the object has a removal status, and stops there.
- Determines the IP address, templates and hostgroups. If one of them is missing, the object is skipped with a warning.
- Creates the host in Zabbix if the object has no host ID yet, and stores the new ID in NetBox.
- 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:
- Assign the
zabbix_hostidcustom field (or the field set indevice_cf) to Virtual machine objects in NetBox. - Set
sync_vms = Trueinconfig.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 tocluster_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 /:
To put each host in multiple hostgroups, use a list:
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:
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:
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.
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:
Make sure every host has at least one template in its config context, in this format:
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:
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
snmpv3tag) - 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:
To change the type, delete the host in Zabbix, clear itszabbix_hostid in NetBox, and let the script recreate it.
Agent interface configuration example¶
Configures a Zabbix agent interface on the default port.
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:
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 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:
On Zabbix 7.0 and later, you can use a proxy group with the proxy_group key. Older Zabbix releases ignore this key.
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.
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:
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:
- A proxy group, before a proxy
- The custom field of the device or VM
- The custom field of the site
- 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.
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:
- NetBox tags of the device or VM
- Config context
- NetBox fields
To enable tag sync:
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.
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:
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:
Usermacros¶
The script can use NetBox as the source for host usermacros:
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:
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:
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.
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.