AdGuard Home on OPNsense¶
AdGuard Home is the client-facing DNS server for the network — every device queries it on port 53, it filters ads/trackers/malware, then forwards clean queries upstream to Unbound. This page covers installing and configuring the AdGuard Home plugin; for how it slots into the wider resolver chain see the DNS Stack guide.
Where AdGuard fits
Client → AdGuard Home :53 → Unbound :5335 → dnsmasq (.<YOUR_LOCAL_DOMAIN>) / root DNS
(filtering) (recursion/DNSSEC) (local names)
AdGuard only filters and forwards — it never resolves recursively itself. That's Unbound's job.
There's also a thorough external write-up worth keeping handy: windgate.net — AdGuard Home on OPNsense.
1. Install the plugin¶
The AdGuard Home plugin lives in the community repository.
- System → Firmware → Settings → set Community (unsupported) plugins and save.
- System → Firmware → Plugins → search
os-adguardhome-maxit→ click + to install. - After it installs, a new Services → AdGuardHome menu appears.
2. Free up port 53¶
AdGuard needs to bind port 53 on the interfaces clients use. Two things commonly squat on 53:
- Unbound — move it to
5335(Services → Unbound DNS → General → Listen Port). - dnsmasq — if used for DHCP, move its DNS to
53053and let AdGuard own 53.
See the DNS Stack page — this repo runs AdGuard on 53, Unbound on 5335, dnsmasq on 53053 so nothing collides.
3. Enable and run the setup wizard¶
- Services → AdGuardHome → General → Enable, then Apply.
- Open the dashboard (a link is on the plugin page, or
http://<opnsense-ip>:3000). - Run the first-time wizard:
- Admin web interface: an unused port (e.g.
3000) on All interfaces. - DNS server: port
53on the interfaces clients query (your VLAN gateways, or All interfaces). - Create the admin account.
4. Point AdGuard at Unbound¶
Settings → DNS settings → Upstream DNS servers:
That's it — a single upstream. Everything (public and .<YOUR_LOCAL_DOMAIN>) goes to Unbound,
which decides whether to resolve recursively or hand .<YOUR_LOCAL_DOMAIN> to dnsmasq.
Bootstrap DNS servers (used only to look up upstreams at startup):
Test upstreams
Use the Test upstreams button. If it fails, Unbound isn't listening on
5335 or a firewall rule is blocking loopback — fix that before going further.
5. Filtering (blocklists)¶
Filters → DNS blocklists → Add blocklist. AdGuard ships with AdGuard DNS filter enabled. Sensible additions:
- AdGuard DNS filter (default) — general ads/trackers
- OISD Big — large, well-maintained, low false positives
- HaGeZi Multi Pro — aggressive ads + tracking + malware
Don't over-block
Stacking many aggressive lists breaks logins, shortened links, and shopping
sites. Start with one or two, then add per-domain allowlist entries under
Filters → Custom filtering rules (@@||domain^) as things break.
6. Local domains — DNS Rewrites¶
To make internal services (<SERVICE>.<YOUR_LOCAL_DOMAIN>, served by Nginx Proxy Manager) resolve on the LAN and
over Tailscale, one wildcard rewrite does it:
Filters → DNS Rewrites → Add DNS rewrite:
| Field | Value |
|---|---|
| Domain | *.<YOUR_LOCAL_DOMAIN> (wildcard covers every subdomain) |
| Answer | NPM's LAN IP (e.g. <YOUR_SERVER_IP>) |
A new service then only needs a proxy host in NPM. Pair it with a certificate from a private CA so the names get real HTTPS: Internal TLS.
Keep service names on their own sub-zone
Put services under a sub-zone (e.g. *.lab.home.arpa) rather than straight under the domain your DHCP host
names live in (server1.home.arpa). A wildcard rewrite answers before Unbound/dnsmasq ever see the query, so a
wildcard on the host-name domain would send every host name to NPM.
See Tailscale → DNS for the tailnet for using this to resolve local names remotely.
6a. Rate limit: raise it for server subnets¶
AdGuard Home rate-limits per client subnet by default (20 queries per second for a whole /24). Every server and container on a server VLAN shares that one bucket, and queries over the limit are dropped without an answer. A reverse proxy that resolves its upstreams per request hits that quickly and starts returning random 502s.
Settings → DNS settings → Rate limit: raise it (I use 300) or set 0 to disable. Don't rely on the rate-limit
allowlist to exempt servers; test that it actually works in your version first. The full story and a burst test:
DNS rate limiting a whole server subnet.
7. Per-client settings (optional)¶
Settings → Client settings lets you treat devices differently by IP/MAC — e.g. stricter blocking for kids' devices, or disabling filtering for a smart TV that misbehaves. Clients show up by IP; give them names here for readable logs.
8. Enforce it — Force DNS via NAT¶
Filtering only works if clients actually use AdGuard. A device with a hardcoded
8.8.8.8 bypasses everything. Redirect all rogue DNS back to AdGuard with a NAT
port-forward per VLAN — see DNS Stack → Force DNS via NAT.
Maintenance¶
- Query Log (dashboard) — see exactly what each client asks for and what got blocked; the fastest way to diagnose "site won't load."
- Clear cache — Settings → DNS settings → Clear cache after changing rewrites or when stale records linger.
- Back it up separately. The plugin keeps its config in
/usr/local/AdGuardHome/AdGuardHome.yaml, not in OPNsense'sconfig.xml, so a normal OPNsense config backup doesn't include it. Copy that file off the box on a schedule (I pull it nightly together withconfig.xml), see Maintenance.