Source of Truth with NetBox
Building Your Network Source of Truth — Click by Click

Networks in modern enterprises and service providers are becoming more complex. Network teams handle Cisco IOS, Juniper Junos, Nokia SR OS, firewalls, wireless networks, cloud connectivity, and virtual infrastructure.
Traditional documentation methods, like spreadsheets and static diagrams, are no longer effective at scaling.
This is why modern network automation depends heavily on a Source of Truth.
What is source of truth ?
A Source of Truth is a centralized platform that stores authoritative infrastructure information.
Instead of using:
spreadsheets
text files
Visio diagrams
disconnected databases
All infrastructure data is stored centrally. This includes:
Devices
IP addresses
VLANs
Interfaces
Sites
Racks
VRFs
The Source of Truth serves as the reliable inventory for monitoring systems, automation tools, CI/CD pipelines, and validation frameworks.
Why is a Source of Truth Required?
Manual Documentation Fails - Spreadsheets and manually maintained inventories quickly become outdated.
Automation Requires Reliable Data - Automation frameworks such as Ansible, Nornir , pyATS and Terraform depend on accurate infrastructure information.
Multivendor Environments Increase Complexity - A Source of Truth normalizes infrastructure information across vendors.
Better Operational Visibility - Network teams can quickly identify Device Locations , Interface usage , IP allocations and VLAN assignments to name a few
What is Netbox ?
NetBox is a purpose-built "source of truth" (SoT) for network and infrastructure inventory, intended to be the definitive system for DCIM (data center infrastructure management) and IPAM (IP address management). It provides a structured data model, a REST + GraphQL API, change logging, webhooks, and a rich UI — all of which make it ideal as the authoritative dataset driving automation and operational workflows.
What Makes NetBox Unique?
API-First Design - NetBox was designed for automation from the beginning. Everything in NetBox can be accessed using APIs.
Excellent IPAM Capabilities - NetBox provides IPv4 management , IPv6 management, VRFs , VLAN tracking and Prefix management. This reduces IP conflicts , Duplicate allocations and poor subnet tracking.
Powerful Infrastructure Modeling - NetBox models real infrastructure relationships.
Dynamic Inventory Generation - NetBox allows dynamic inventory generation automatically. New devices become available immediately to automation frameworks.
Why Should Network Teams Use NetBox?
Better Documentation - NetBox replaces spreadsheets, disconnected inventories and static diagrams with centralized live documentation.
Improved Automation - NetBox enables Dynamic inventories , Configuration generation , Compliance validation and Automated provisioning
Faster Troubleshooting - Engineers can quickly identify Device ownership , Interface mappings , VLAN relationships and Rack locations
Scalable Operations - As networks grow, manual tracking becomes impossible. NetBox enables scalable operational workflows.
Populating Data in NetBox
| Method | Description |
|---|---|
| Manual Object Creation | The easiest and most straightforward method to populate data in NetBox is by using the object creation forms available in the user interface (UI). |
| Bulk Import (CSV/YAML) | NetBox supports the bulk import and updating of objects using CSV-formatted data. This method is ideal for importing spreadsheet data, which can be easily converted to CSV. You can import CSV data either as raw text in the form field or by uploading a correctly formatted CSV file. |
| Scripting | You will find that data you need to populate in NetBox can be easily reduced to a pattern. A simple custom script to automatically populate this information can be created |
| REST API | The REST API can also be used to populate data in NetBox, providing full programmatic control over object creation while adhering to the same validation rules as the UI forms. Furthermore, it supports the bulk creation of multiple objects with a single request. |
Rather than jumping straight into code, we start where every network team should — with the NetBox GUI. Getting your data model right in the UI first means your automation scripts will query clean, consistent, well-structured data.
The principle of "garbage in, garbage out" is especially relevant to network automation.
Lab Topology
| Device | Vendor | Os | Site | Mgmt IP | Loopback |
|---|---|---|---|---|---|
| core-rtr-01 | Cisco | IOS-XR | DC-Auckland | 192.168.10.1 | 10.10.10.3/32 |
| core-rtr-02 | Juniper | Junos | DC-Sydney | 192.168.20.1 | 10.10.10.4/32 |
| pe-rtr-01 | Nokia | SR OS | DC-Queenstown | 192.168.30.1 | 10.10.10.2/32 |
| pe-rtr-02 | Nokia | SR OS | DC-Queenstown | 192.168.30.2 | 10.10.10.1/32 |
Install NetBox and Access the GUI
NetBox operates as a web application supported by PostgreSQL and Redis. The quickest method to obtain a fully functional instance is by using netbox-docker, an officially maintained Docker Compose stack that automatically manages all dependencies.
Installation
Clone netbox-docker and Configure Environment
# Clone the official netbox-docker repo — always use the release branch
git clone -b release https://github.com/netbox-community/netbox-docker.git
cd netbox-docker
Create docker-compose.override.yml to set port and credentials:
cat > docker-compose.override.yml << 'EOF'
services:
netbox:
ports:
- "8080:8080"
environment:
- SUPERUSER_NAME=admin
- SUPERUSER_EMAIL=devplayground.gmail.com
- SUPERUSER_PASSWORD=CodedNetbox2026!
- ALLOWED_HOSTS=*
EOF
Pull Images and Start NetBox
# Pull all required images (netbox, postgres, redis, nginx)
docker compose pull
# Start all services in detached mode
docker compose up -d
# Watch startup logs — wait for 'Listening at: http://0.0.0.0:8080'
docker compose logs -f netbox
# Check all containers are healthy
docker compose ps
Expected output of docker compose ps :
NAME STATUS PORTS
netbox-docker-netbox-1 Up (healthy) 0.0.0.0:8080->8080/tcp
netbox-docker-postgres-1 Up (healthy) 5432/tcp
netbox-docker-redis-1 Up (healthy) 6379/tcp
netbox-docker-worker-1 Up (healthy)
netbox-docker-housekeeping-1 Up (healthy)
Access the NetBox GUI
Open your browser and navigate to:
http://localhost:8080
# If running on a remote server, replace localhost with the server IP:
http://<host-ip>:8080
You will see the NetBox login page
What You See After Logging In
The NetBox dashboard displays a summary of all object counts, including devices, IPs, prefixes, and VLANs. Upon first login, all values will be zero, which is normal. The top navigation bar features six main menus:
| Menu | What Lives Here |
|---|---|
| Organization | Sites, racks, tenants, contacts, locations |
| Devices | Devices, device types, manufacturers, roles, platforms, cables |
| IPAM | IP addresses, prefixes, VLANs, RIRs, aggregates, services |
| Circuits | Providers, circuits, circuit terminations |
| Virtualization | Clusters, virtual machines, VM interfaces |
| Operations | Webhooks, event rules, scripts, reports, changelog |
| Customization | Custom fields, custom links, export templates, tags |
| Admin | Users, groups, API tokens, object permissions |
Generate an API Token (Required for Later Automation)
GUI : Admin → API Tokens → + Add
Although this post emphasizes the GUI, creating a token now will set you up for future automation
| Field | Value |
|---|---|
| User | admin (your superuser) |
| Key | (leave blank — auto-generated) |
| Write Enabled | ✓ Checked |
| Expires | (leave blank for lab, set expiry for production) |
| Description | Lab automation token |
Click Save. The token will be displayed only once, so make sure to copy and store it securely.
# Quick API test
curl -X GET \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json; indent=4" \
http://<local-host>:8080/api/status/
# Successful response
{
"django-version": "6.0.5",
"hostname": "4ba0dd1e9137",
"installed_apps": {
"django_filters": "25.2",
"django_prometheus": "2.4.0",
"django_rq": "4.1.0",
"django_tables2": "2.8.0",
"drf_spectacular": "0.29.0",
"drf_spectacular_sidecar": "2026.5.1",
"mptt": "0.18.0",
"rest_framework": "3.17.1",
"social_django": "5.9.0",
"taggit": "6.1.0",
"timezone_field": "7.2.1"
},
"netbox-version": "4.6.1",
"netbox-full-version": "4.6.1-Docker-5.0.1",
"plugins": {},
"python-version": "3.14.4",
"rq-workers-running": 1
Useful Docker Management Commands
| Task | Command |
|---|---|
| Stop NetBox | docker compose down |
| Start NetBox | docker compose up -d |
| View live logs | docker compose logs -f netbox |
| Check container health | docker compose ps |
| Restart a single service | docker compose restart netbox |
| Access the NetBox shell | docker compose exec netbox /bin/bash |
| Backup the database | docker compose exec postgres pg_dump -U netbox netbox > netbox_backup.sql |
Organization - Sites , Racks and Location
Create Sites
GUI : Organization → Sites → + Add
Fill in the form for DC-Auckland :
| Field | Value |
|---|---|
| Name | DC-Auckland |
| Slug | dc-auckland (auto-fills) |
| Status | Active |
| ASN | 65000 |
| Time Zone | Pacific/Auckland |
| Description | Primary data centre — Auckland |
| Physical Address | Auckland, New Zealand |
Click Save . Repeat the same process for other sites
Create Rack Groups and Racks
GUI : Organization → Racks → Rack Groups → + Add
| Field | Value |
|---|---|
| Name | AKL-ROW-A |
| Slug | akl-row-a |
| Site | DC-Auckland |
GUI : Organization → Racks → + Add
| Field | Value |
|---|---|
| Name | AKL-RACK-01 |
| Site | DC-Auckland |
| Rack Group | AKL-ROW-A |
| Status | Active |
| Type | 4-post enclosed |
| Height (U) | 42U |
Device Types & Manufacturers - Hardware Models, Roles, and Platforms
Add Manufacturers
GUI : Device → Device Types → Manufacturers → + Add
Add Device Types — Cisco xrv9k (IOS-XR)
GUI : Device → Device Types → + Add
| Field | Value |
|---|---|
| Manufacturer | Cisco |
| Model | cisco_xrv9000 |
| Slug | cisco_xrv9000 |
| Part Number | 8HE03685AARA01 |
| Height (U) | 1 |
| Full Depth | ✓ Checked |
| Comments | Virtual IOS-XR router |
After saving, click the Interfaces tab → Add Interface Template:
| Interface Name | Type | Management Only |
|---|---|---|
| GigabitEthernet1 | 1000BASE-T (1GE) | ✓ Yes |
| GigabitEthernet2 | 1000BASE-T (1GE) | No |
| GigabitEthernet3 | 1000BASE-T (1GE) | No |
| Loopback0 | Virtual | No |
device.interfaces.all() to find consistent, vendor-accurate interface names, eliminating the need for guessing or hard-coding.Add Device Roles
GUI : Device → Device Roles → + Add
Add Platforms
GUI : Device → Platforms → + Add
Devices
Add core-rtr-01 — Cisco IOS-XR (DC-Auckland)
GUI : Device → Devices → + Add
| Field | Value |
|---|---|
| Name | core-rtr-01 |
| Device Role | Core Router |
| Device Type | cisco_xrv9000 |
| Platform | Cisco IOS-XR |
| Site | DC-Auckland |
| Status | Active |
| Rack | AKL-RACK-01 |
Click Save to navigate to the device detail page. Leave the Primary IP blank for now; it will be assigned after creating the IP address record.
IPAM - RIRs, Prefixes, IP Addresses, and Primary IPs
Create RIRs
GUI : IPAM → Aggregates → RIR → + Add
Create Prefix Roles and Prefixes
GUI : IPAM → Prefixes → Prefix & VLAN Roles → + Add
GUI : IPAM → Prefixes → + Add
Add IP Addresses and Assign to Interfaces
GUI : IPAM → IP Addresses → + Add
Set Primary IP on Each Device
GUI : Devices → Devices → Edit
| Field | Value |
|---|---|
| Primary IPv4 | Select the management IP from the dropdown |
Custom Fields - Extending Netbox for Automation
Create Custom Fields
GUI : Customization → Custom Fields → + Add
Populate Custom Fields on Each Device
GUI : Devices → Devices → Edit → (scroll to Custom Fields)
Tags - Flexible Multi-Dimensional Grouping
Create Tags
GUI : Customization → Tags → + Add
nb.dcim.devices.filter(tag="bgp-peer")Apply Tags to Devices
GUI : Devices → Devices → Edit → Tags Field
nb.dcim.devices.filter(tag='bgp-peer') retrieves only BGP-speaking routers. This allows you to write targeted playbooks, such as 'push new BGP password to all devices tagged as bgp-peer,' without needing separate manual lists.Cables - Documenting Physical Connectivity
Add a Cable Between core-rtr-01 and pe-rtr-01
GUI : Devices → Devices (choose site) → Interfaces Tab → Connect (cable-icon)
Webhooks & Event Rules - GUI Configured Event-Driven Automation
Create a Webhook
GUI : Integrations → Webhook → + Add
| Field | Value |
|---|---|
| Name | device-change-to-automation |
| URL | http://your-automation-host:9000/webhook/netbox |
| HTTP Method | POST |
| HTTP Content Type | application/json |
| Secret | |
| SSL Verification | Unchecked for lab ✓ Checked for production |
Create Event Rules
GUI : Integrations → Event Rules → + Add
Rule 2 — Device Status Changed to Active (with Condition):
In the Conditions field, the below JSON is used to filter on status change:
{
"and": [
{
"attr": "status.value",
"value": "active"
}
]
}
Test the Webhook with a Quick Listener
In a terminal, start a one-liner HTTP listener:
python3 -c "
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get('Content-Length', 0))
raw = self.rfile.read(length)
data = json.loads(raw)
print(json.dumps(data, indent=2))
self.send_response(200)
self.end_headers()
def log_message(self, *args):
pass
print('Listening on port 9000...')
HTTPServer(('', 9000), Handler).serve_forever()
"
In the NetBox GUI, edit pe-rtr-02, change Status from Active → Planned → Active. Expected output:
Listening on port 9000...
{
"event": "updated",
"timestamp": "2026-05-27T01:53:21.485685+00:00",
"object_type": "dcim.device",
"username": "admin",
"request_id": "21724c08-cb44-4961-bde1-f76fd4d9fd89",
"data": {
"id": 4,
"url": "/api/dcim/devices/4/",
"display_url": "/dcim/devices/4/",
"display": "pe-rtr-02",
"name": "pe-rtr-02",
"device_type": {
"id": 3,
"url": "/api/dcim/device-types/3/",
"display": "7750 SR-1",
"manufacturer": {
"id": 2,
"url": "/api/dcim/manufacturers/2/",
"display": "nokia",
"name": "nokia",
"slug": "nokia",
"description": ""
},
"model": "7750 SR-1",
"slug": "7750-sr-1",
"description": "",
"device_count": 2
},
My personal opinion about NetBox
For a long time, I assumed NetBox was exclusively for production use, primarily employed by enterprise teams to document campus networks and validate their IPAM budgets. I considered it unnecessary for my lab, thinking it was "just a lab."
Then I began using containerlab in a more serious manner.
The Problem Nobody Talks About
Containerlab is truly impressive. You create a YAML topology file, execute containerlab deploy, and in less than a minute, you have a fully connected network of Cisco XRv9000s, Juniper vMX routers, and Nokia SR OS nodes communicating seamlessly. The first experience feels magical.
But here's what happens after the first time.
You create a topology for BGP testing, then another for MPLS, followed by one for SR-MPLS, and a data center fabric. When someone requests you to replicate a production issue, you quickly set up a topology that somewhat resembles it. Soon, you find yourself with six topology files in different stages of completion, a folder full of configurations with names like final_v2_actually_final.cfg, and no clear idea of which IP addresses were used where.
You SSH into something and get a different device than you expected. You run an Ansible playbook and it hits the wrong node. You try to reproduce a test from two weeks ago and spend an hour figuring out what the management IPs were.
This is the source-of-truth problem. And it doesn't only affect production networks.
Why Netbox matters ?
A Source of Truth is now essential in modern networking. NetBox offers the centralized, automation-ready infrastructure platform needed for multi-vendor environments in my case. Modern automation starts with reliable infrastructure data, and NetBox provides that foundation.



