Skip to content
Infrastructure

Giving every homelab device a readable name in Pi-hole

By Victor Da Luz
Pi-hole DNS Ansible homelab networking
Giving every homelab device a readable name in Pi-hole

For a while, my Pi-hole client list was a wall of IP addresses. Thirty-some entries, most of them showing raw IPs. Monitoring query logs meant cross-referencing every address against the DHCP lease table to figure out which device was making requests. That’s friction I mostly lived with until I sat down to fix it.

The root cause trips a lot of people up: DNS records and DHCP leases are separate things. Pi-hole resolves client names by looking up the querying IP in its local DNS. If there’s no matching record, it shows the raw IP. A DHCP lease that assigns 10.0.x.x to a Steam Deck doesn’t automatically tell Pi-hole to call that IP steamdeck.internal - that requires an explicit DNS record.

Why the client list matters

The client list is a diagnostic tool. When a device starts making unusual queries - phoning home to something unexpected, a spike in blocked requests - you need to identify it immediately. Having to cross-reference an IP against a DHCP table adds friction to exactly the moment when you want clarity.

Naming conventions

Before adding records, I had to settle on a naming scheme. For most devices it’s straightforward: ps4.internal, mac-mini.internal. The wrinkle is when you have multiple devices of the same type.

I have five Apple TV 4K units spread across different rooms. Numbered names like appletv03.internal require you to remember which number lives where. Room-based names are more useful: appletv.office.internal, appletv.bedroom.internal, appletv.kitchen.internal.

HomePod mini units follow the same pattern. The stereo pair in the office gets homepod01.office.internal and homepod02.office.internal; the bedroom one gets homepod01.bedroom.internal.

For the Mac mini, I have both wired and Wi-Fi interfaces active. Both get records: mini01.internal for the wired interface and mini01-wifi.internal for the wireless one. Without that, one or the other shows as an anonymous IP depending on which interface is active in Pi-hole’s view.

The Ansible playbook

My homelab already maintains a network.yaml state file with every device’s hostname, reserved IP, and MAC address. Rather than managing Pi-hole DNS records as a separate list, I wrote an Ansible playbook that generates them directly from those state files.

The playbook reads all devices from network.yaml and services from services.yaml, builds a deduplicated list of hostname → IP pairs, then applies them to Pi-hole via the v6 API:

  1. POST to /api/auth to get a session token
  2. GET current dns.hosts entries from Pi-hole
  3. Diff against desired state - determine what to add, update, or remove
  4. DELETE stale entries, PUT new ones
  5. POST to /api/action/restartdns to apply
  6. Run Nebula-Sync to replicate to all five replica instances

One encoding gotcha: Pi-hole v6 expects spaces in URL paths encoded as %20. Ansible’s urlencode filter produces + for spaces (query-string convention), which the Pi-hole API rejects silently. The fix is to chain a replace after urlencode:

url: "{{ api_url }}/api/config/dns/hosts/{{ entry | urlencode | replace('+', '%20') }}"

Pi-hole v6 also requires app_sudo to be enabled for API write access. The playbook checks the current setting and enables it automatically if it’s off - I ran into this requirement earlier when setting up Nebula-Sync and built the check in from the start.

What got added

The batch that prompted this included:

I also cleaned up some stale entries. Dashy had been retired, so its DNS record came out too. The office LG TV was pulled from VLAN 30 internet access and removed from the DNS records at the same time.

Lessons

  • Pi-hole doesn’t inherit hostnames from DHCP. The records are managed separately, which means they drift unless you automate the sync.
  • Room-based naming beats numbered naming for multi-device setups. appletv.office.internal tells you what you’re looking at without a cheat sheet.
  • Not every VLAN 30 device needs a DNS record. If a device has no path to Pi-hole, it never appears in the client list - only the ones with internet access need entries.
  • A single state file as the source of truth pays off. Adding a device to network.yaml once covers DHCP config, DNS records, and documentation in a single playbook run.

Related reading

Ready to Transform Your Career?

Let's work together to unlock your potential and achieve your professional goals.