Case study · Networking & services
DNS, HTTPS and service routing with Pi-hole, Unbound, Nginx Proxy Manager and Cloudflare Tunnel
A containerised stack that gives the homelab its own recursive DNS with DNSSEC validation, HTTPS routing for internal services, and controlled external publishing through Cloudflare Tunnel rather than direct exposure.
At a glance
Key facts
- Internal DNS
- Pi-hole and Unbound in Docker
- Resolution
- Full recursion with DNSSEC validation
- Routing
- Nginx Proxy Manager with TLS certificates
- External access
- Cloudflare DNS and Cloudflare Tunnel
- Published this way
- This website and the blog
- Docker
- Pi-hole
- Unbound
- Nginx Proxy Manager
- Cloudflare Tunnel
- TLS
Context
DNS underpins everything else in the environment. Running it locally gives control over internal names, visibility of what is being resolved, and independence from an upstream public resolver. The routing layer then decides how each service is reached, internally and from the internet.
Internal resolution
Clients query Pi-hole. Pi-hole provides filtering, local records and query visibility, and forwards to Unbound. Unbound performs full recursive resolution against the root, TLD and authoritative servers with DNSSEC validation, rather than forwarding to a public resolver.
Core services use consistent IP assignments so that DNS does not depend on DHCP and the resolver is always where clients expect it to be.
HTTPS routing
Nginx Proxy Manager sits in front of the Docker services and provides host-based routing, TLS certificates and HTTP-to-HTTPS redirection. Internal names resolve to the proxy, and the proxy knows which service each name belongs to. DNS and proxy configuration have to be kept aligned, or a service becomes reachable by one path and not another.
External publishing
Public services follow a different path: Cloudflare DNS, then Cloudflare Tunnel into the environment, then Nginx Proxy Manager, then the target container. The tunnel provides the path in; the proxy does the routing. Containers are never exposed to the internet directly. This website and the blog are both published this way.
Problems encountered
Not every container followed the same DNS path as the host. Depending on configuration, a container might use Docker's embedded DNS, inherit the host's settings, or use explicitly defined servers, so some containers could not resolve internal records that the host resolved fine. The fix was to make DNS behaviour explicit per service rather than relying on defaults, after verifying which resolver each container was actually using.
Scope
What this does not claim
- The environment uses bridged networking with consistent IP assignments. No VLAN or network segmentation design is claimed.
- The routing layer is described exactly as built: reverse proxy, TLS certificates and tunnel.
Further reading
Related technical write-ups
Articles on my blog that cover this work in more detail.
More