You know the feeling. You’re staring at a half-remembered spreadsheet, trying to figure out which IP you gave the new NAS last Tuesday. Column D says "reserved," column F says "in use," and neither matches reality. Your /etc/hosts file has 60 entries and you stopped trusting it six months ago. That VLAN you carved out for IoT devices? No idea what’s in it anymore.
This is the classic homelab documentation death spiral, and it gets worse the more gear you add. The fix isn’t more spreadsheet tabs — it’s a proper IPAM/DCIM tool, running locally, owned by you.
This article covers two serious contenders: NetBox and Nautobot. Both are open-source, both run perfectly on a single VM or spare server, and both will make you feel like you’re running a real NOC instead of a pile of cables in a closet.
What IPAM and DCIM Actually Are
IPAM — IP Address Management — tracks your IP space. Prefixes, addresses, VLANs, VRFs. Which addresses are allocated, which are free, which belong to which device.
DCIM — Data Center Infrastructure Management — tracks the physical and logical inventory. Rack positions, device types, interfaces, cables, power feeds, rack diagrams.
In enterprise environments these are million-dollar licensed products. For your basement, they’re free Docker containers.
NetBox: The OG
NetBox was built by Jeremy Stretch at DigitalOcean and open-sourced in 2016. It’s the de facto standard for network documentation in the open-source world. GitHub repo: https://github.com/netbox-community/netbox
The core model is straightforward: Sites → Racks → Devices → Interfaces → IP Addresses. Every object links to related objects. A cable goes between two interfaces. An interface gets an IP. That IP lives in a prefix. That prefix lives in a VRF or the global table. The whole thing is queryable via a REST API and a GraphQL endpoint.
NetBox 4.x added a significant plugin ecosystem, webhooks, event rules, and a much-improved UI. It’s PostgreSQL-backed, Redis for caching/queuing, and Django under the hood.
Nautobot: The Fork That Grew Up
Nautobot started as a NetBox fork in 2021, driven by Network to Code. GitHub: https://github.com/nautobot/nautobot
The key difference: Nautobot is explicitly designed as a network automation platform, not just a documentation database. It has a proper plugin framework (called Apps), a built-in job scheduler, Git datasource integration, and first-class support for workflows and automation. If you want to generate configs from your source of truth, Nautobot is the more natural fit.
For a homelab that’s purely documentation-focused, NetBox is simpler. For a homelab where you want to script against your inventory and drive Ansible or Nornir from it, Nautobot’s architecture is a better long-term bet.
Deploying NetBox with Docker Compose
The netbox-community/netbox-docker project maintains a production-grade compose setup. Don’t write your own from scratch.
git clone https://github.com/netbox-community/netbox-docker.git
cd netbox-docker
Generate an override file:
tee docker-compose.override.yml <<'EOF'
services:
netbox:
ports:
- "8000:8080" # expose on host port 8000
environment:
SUPERUSER_NAME: admin
SUPERUSER_EMAIL: [email protected]
SUPERUSER_PASSWORD: changeme_immediately
EOF
Pull and start:
docker compose pull
docker compose up -d
First boot takes 2–3 minutes while Django runs migrations. Check progress:
docker compose logs -f netbox | grep -E "Starting|Ready|Error"
Once it’s up, hit http://<your-host>:8000 and log in with the superuser credentials you set above.
Gotcha: The default
docker-compose.ymldoesn’t bind any host port. You need the override or the UI is unreachable. The project README mentions this, but people miss it constantly.
Persisting Data
The compose file mounts named volumes for PostgreSQL and media. That’s fine for getting started, but for anything you care about, bind-mount to a real directory:
# docker-compose.override.yml — add to your existing override
services:
postgres:
volumes:
- /srv/netbox/postgres:/var/lib/postgresql/data
netbox:
volumes:
- /srv/netbox/media:/opt/netbox/netbox/media
- /srv/netbox/reports:/opt/netbox/netbox/reports
- /srv/netbox/scripts:/opt/netbox/netbox/scripts
Create those directories before running compose:
sudo mkdir -p /srv/netbox/{postgres,media,reports,scripts}
sudo chown -R 999:999 /srv/netbox/postgres # postgres container uid
Deploying Nautobot with Docker Compose
Nautobot ships its own compose-based development environment. For a homelab install, the quickest path is their nautobot-docker-compose community project: https://github.com/nautobot/nautobot-docker-compose
git clone https://github.com/nautobot/nautobot-docker-compose.git
cd nautobot-docker-compose
cp environments/local.env.example environments/local.env
Edit environments/local.env — at minimum set:
# environments/local.env
NAUTOBOT_SUPERUSER_NAME=admin
NAUTOBOT_SUPERUSER_PASSWORD=changeme_immediately
[email protected]
SECRET_KEY=replace_this_with_a_real_50char_random_string
ALLOWED_HOSTS=*
Generate a proper SECRET_KEY:
python3 -c "import secrets; print(secrets.token_urlsafe(50))"
Start it:
docker compose up -d
Nautobot runs on port 8080 by default inside the container. Add a port binding if needed:
# docker-compose.override.yml
services:
nautobot:
ports:
- "8001:8080"
Gotcha: Nautobot’s startup is slower than NetBox. The celery workers, Redis, and the Django app all need to be healthy before the UI is responsive. Give it 4–5 minutes on first boot. If the UI 502s, the workers probably aren’t ready yet.
Modeling Your Homelab in NetBox
Here’s a real workflow for getting your homelab into NetBox from scratch.
Step 1 — Define your site and racks
Go to Organization → Sites, create "Home" or "Basement Lab." Then DCIM → Rack Groups (optional, for organizing multiple racks), then DCIM → Racks. Set the rack height in U. Even if you don’t have a proper rack, create a virtual one — it keeps the model consistent.
Step 2 — Import device types
Don’t manually enter every device. The community maintains a massive library of device type definitions: https://github.com/netbox-community/devicetype-library
Install the import tool:
pip install netbox-device-type-importer
Clone the library and import what you need:
git clone https://github.com/netbox-community/devicetype-library.git
cd devicetype-library
# Import a specific vendor's devices
netbox-dt-import \
--url https://cd-linux.club:8000 \
--token <your-api-token> \
--vendors Ubiquiti Mikrotik "Dell EMC"
Your API token lives under your profile in the NetBox UI → API Tokens.
Step 3 — Add your prefix space
Go to IPAM → Prefixes. Add your RFC 1918 blocks:
10.0.0.0/8— role: Container, mark as a supernet192.168.1.0/24— role: Active, your main LAN192.168.10.0/24— VLAN 10, IoT192.168.20.0/24— VLAN 20, Servers
Within each prefix, use IPAM → IP Addresses to document individual assignments. Or use the "Available IPs" button inside a prefix to grab and assign the next free address.
Step 4 — Add VLANs
IPAM → VLAN Groups → create a group for your switch. Then IPAM → VLANs — add each VLAN with its ID and name. Link prefixes to VLANs on the prefix edit page.
The API Is the Point
Once your data is in, the REST API is how you actually get value out of it at scale.
Grab all IP addresses in a specific prefix:
curl -s \
-H "Authorization: Token <your-token>" \
"https://cd-linux.club:8000/api/ipam/ip-addresses/?parent=192.168.1.0/24&format=json" \
| jq '.results[] | {address: .address, device: .assigned_object.device.name}'
Find all interfaces with no IP assigned:
curl -s \
-H "Authorization: Token <your-token>" \
"https://cd-linux.club:8000/api/dcim/interfaces/?has_primary_ip=false&type=1000base-t" \
| jq '.results[].name'
This is where NetBox pays off. Instead of grepping /etc/hosts, you query a real database through a structured API.
For Python, pynetbox is the canonical client:
import pynetbox
nb = pynetbox.api("https://cd-linux.club:8000", token="your-token")
# Get all active devices in your homelab site
devices = nb.dcim.devices.filter(site="home", status="active")
for device in devices:
print(f"{device.name}: {device.primary_ip}")
Nautobot’s Automation Angle
Where Nautobot pulls ahead is Jobs — Python scripts you write and run from the UI or API, with full access to the Nautobot data model.
A simple example: a Job that checks all devices in your inventory and flags any that have no primary IP set.
# jobs/check_primary_ip.py
from nautobot.apps.jobs import Job, register_jobs
class CheckPrimaryIP(Job):
class Meta:
name = "Check Devices Missing Primary IP"
description = "Flags all active devices without a primary IP"
def run(self):
from nautobot.dcim.models import Device
devices = Device.objects.filter(status__name="Active", primary_ip4__isnull=True)
for device in devices:
self.logger.warning(f"{device.name} has no primary IPv4 address", obj=device)
self.logger.info(f"Checked {Device.objects.count()} devices total")
register_jobs(CheckPrimaryIP)
Put that file in your jobs directory, enable it in the UI, and run it on demand or on a schedule. The output shows in Nautobot’s job results with links to each device.
This is the pattern that scales: your inventory drives your automation, not the other way around.
NetBox vs. Nautobot: Which One
Pick NetBox if:
- You want the simplest possible documentation tool
- Your team (or just you) needs something with minimal setup overhead
- You don’t plan to drive automation from inventory data
- Plugin ecosystem maturity matters more than workflow features
Pick Nautobot if:
- You want to automate network config generation from your source of truth
- You’re already using or plan to use Nornir/Ansible driven by inventory
- You want Git-based config management integrated into your IPAM tool
- You’re comfortable with a slightly more complex initial setup
They’re not mutually exclusive in principle — some shops run both — but for a homelab, pick one and commit to it. Divided inventory is worse than no inventory.
Gotchas
Secret key rotation in Nautobot will log out all active sessions and invalidate tokens. Don’t rotate it casually. Treat it like a DB password.
NetBox’s "Active" status on IP addresses is not automatically enforced. Nothing stops you from marking an IP as "Active" when nothing uses it. The tool documents your intent, not ground truth. You still need to audit periodically.
Backup before upgrading. Both projects move fast. NetBox 4.x → 4.y upgrades are generally smooth but run Django migrations that aren’t rollback-friendly. Snapshot your PostgreSQL volume before docker compose pull && docker compose up -d.
The devicetype-library lags behind real hardware. If you have a device that’s not in the library, you’ll need to write a YAML definition manually. It’s not hard — look at any existing definition in the repo as a template — but budget 15 minutes per novel device.
Nautobot’s celery workers must be healthy for Jobs to run. If a job submission hangs, check docker compose logs celery_worker. A stale worker that didn’t restart cleanly will silently drop job messages.
Production-Ready Practices
Put a reverse proxy in front. Running NetBox directly on port 8000 in HTTP is fine for local access, but if you’re exposing it on your LAN even partially, throw Nginx or Caddy in front with a self-signed cert from your local CA. The compose projects have examples for this.
Set up automated PostgreSQL backups with pg_dump:
#!/bin/bash
# /etc/cron.daily/netbox-backup
BACKUP_DIR=/srv/backups/netbox
mkdir -p "$BACKUP_DIR"
docker exec netbox-docker-postgres-1 \
pg_dump -U netbox netbox \
| gzip > "$BACKUP_DIR/netbox-$(date +%Y%m%d).sql.gz"
# Keep 30 days
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete
Use API tokens with minimal scope. NetBox lets you create read-only tokens — use those for scripts that only query data, and keep the write-capable token locked down.
Enable webhooks for change notifications. Both tools can POST to a URL when objects change. Wire that to a Discord webhook or a Gotify instance and you get a live changelog of who changed what in your inventory.
Tag everything consistently from day one. Retrofitting tags onto 200 IP addresses is miserable. Decide your taxonomy upfront: homelab, production, deprecated, temp, whatever fits your environment. Tags are how you filter at scale.
Getting Real Value Quickly
The fastest path to actually using these tools: spend one focused evening entering all your current prefixes and devices. Don’t wait until the documentation is perfect — get the skeleton in. Imperfect data in the tool is infinitely more useful than perfect data in your head.
Then the next time you add a device, open NetBox first. Allocate the IP, create the device record, document the interface. It takes three minutes. After a month of that habit, you’ll have a real source of truth instead of a spreadsheet that lies to you.
That’s the whole point. Not to have a fancy tool — to stop losing track of your own infrastructure.