Skip to content

OPNsense

OPNsense runs as a VM on Proxmox and handles routing, firewalling, and several network services for the homelab.

Plugin / Service Role
AdGuard Home Network-wide DNS server with ad and tracker blocking
Unbound Internal DNS resolver, upstream of AdGuard Home for local queries
dnsmasq DHCP server
HAProxy Reverse proxy for internal services
ACME client Let's Encrypt certificate management
Tailscale Subnet router for remote access

DNS

DNS resolution is handled by a split setup, with AdGuard Home in front:

                        ┌─ Quad9 (DoT / DoH)     internet queries
Client → AdGuard Home ──┤
                        └─ Unbound (:5353)       local + reverse queries

AdGuard Home runs as an OPNsense plugin and is the DNS server for all clients on the network, listening on the standard port 53. It filters ads and trackers at the DNS level, then routes queries by domain:

# Upstream DNS servers
tls://dns.quad9.net
https://dns.quad9.net/dns-query
[/tielinen.me/]127.0.0.1:5353
[/in-addr.arpa/]127.0.0.1:5353

# Private reverse DNS servers
127.0.0.1:5353

The [/domain/]server syntax is a conditional forwarding rule: those domains go to the listed upstream, everything else falls through to the default (Quad9). This gives a split-horizon setup where the same DNS server answers differently depending on the query:

Query Matches Resolved by
www.example.com no domain rule Quad9 over DoT / DoH — encrypted, ads filtered
service.tielinen.me [/tielinen.me/] Unbound 127.0.0.1:5353 (local host overrides)
reverse PTR lookup [/in-addr.arpa/] Unbound 127.0.0.1:5353 (internal device names)

Internet-bound queries stay encrypted and never leak to the ISP, while internal names resolve locally — so a hostname like service.tielinen.me points straight at HAProxy's LAN address instead of leaving the network. The same hostname works from inside and outside, but from inside the traffic never round-trips through the internet.

Unbound handles internal name resolution. Internal services exposed through HAProxy are configured as host overrides in Unbound, pointing their hostnames to HAProxy's address.

dnsmasq handles DHCP and pushes AdGuard Home's address to clients as their DNS server.


Certificates

The ACME client fetches Let's Encrypt certificates automatically. Certificates are used in two places:

  • OPNsense itself — for the web UI and other OPNsense services
  • HAProxy — for TLS termination of internal services

HAProxy

HAProxy acts as a reverse proxy for internal services, terminating HTTPS using the Let's Encrypt certificates from the ACME client. This allows internal services to be reached over HTTPS with valid certificates without exposing them to the internet.


Tailscale

Tailscale runs as a subnet router, making the entire homelab network accessible remotely through the Tailscale VPN. This avoids opening any ports to the internet — remote access goes through Tailscale's encrypted tunnel instead.

My experience

I had previously run OPNsense on a dedicated hardware appliance, so the software itself was familiar. For the Proxmox VM installation I followed a ServeTheHome guide and it went smoothly. The part that required the most care was mapping the network interfaces correctly between Proxmox and OPNsense — getting that wrong would mean no connectivity at all.

Before AdGuard Home I ran Pi-hole as an LXC container on Proxmox. Switching to the AdGuard Home plugin inside OPNsense reduced maintenance and felt like a more modern solution. The split DNS configuration took some work to get right, but I got there with a combination of AI assistance, documentation and trial and error.

HAProxy and Let's Encrypt certificates have worked well. One thing to remember is to add a service restart action to the ACME automation so that renewed certificates actually take effect. HAProxy configuration is quite manual, though — a declarative reverse proxy would be easier to maintain.

Tailscale runs as a subnet router on OPNsense. It works well for a homelab where access control isn't a major concern.