What changed
My first version of this guide downloaded an AdGuard Home tarball into /opt, installed its own service, and made dnsmasq forward to port 5353. That worked on my old Belkin RT3200, but it is no longer how I run the network.
The current router is a GL.iNet GL-MT6000 running a recent OpenWrt snapshot. AdGuard Home now comes from OpenWrt's package repository, runs as its own unprivileged user, and is upgraded with the router's package manager. No hand-managed binary or custom init script remains.
When I audited the live router for this rewrite, it was running AdGuard Home 0.107.79. The package occupied about 32 MiB, the query data used about 20 MiB, and the process held roughly 95 MiB of RAM. That is comfortable on this router's 1 GiB of memory, but worth checking before installing it on smaller hardware.
53. OpenWrt's firewall redirects those requests to AdGuard Home on port 54. dnsmasq stays on port 53 for DHCP and local hostnames.This split matters. AdGuard Home sees the original client address, while dnsmasq remains available for .lan names and reverse lookups. It also avoids the resolver loop that can happen when dnsmasq forwards everything to AdGuard Home and AdGuard Home sends local names back to dnsmasq.
Install the OpenWrt package
OpenWrt has shipped an official AdGuard Home package since 21.02. OpenWrt 25.12 and newer use apk:
apk update
apk add adguardhomeOpenWrt 21.02 through 24.10 use opkg instead:
opkg update
opkg install adguardhomeEnable the service and start it:
service adguardhome enable
service adguardhome start
service adguardhome statusThe package owns the service and keeps its files in predictable places:
| Purpose | Path |
|---|---|
| Binary | /usr/bin/AdGuardHome |
| Configuration | /etc/adguardhome/adguardhome.yaml |
| Query log and statistics | /var/lib/adguardhome |
| OpenWrt service | /etc/init.d/adguardhome |
Complete the first-run wizard
Open http://<router-ip>:3000 from the LAN. The AdGuard Home wizard will ask where the web interface and DNS server should listen.
Use these values for this layout:
- Web interface: all interfaces, port
3000 - DNS server: all interfaces, port
54 - Admin account: a unique username and strong password
Port 54 is intentional: dnsmasq already owns port 53. Keep both ports closed to the WAN. My router has no WAN rule for either port and its WAN input policy is REJECT; access to the dashboard comes from trusted networks only. AdGuard's security guide covers stricter bind and access rules if the service could be reached from outside the router.
Confirm that the service is listening after the wizard finishes:
service adguardhome status
netstat -lntup | grep -E '(:54|:3000)'Send client DNS to AdGuard Home
Clients already receive the router as their DNS server through DHCP, so I do not change dnsmasq's upstream server. Instead, an OpenWrt firewall redirect moves incoming DNS from port 53 to AdGuard Home on port 54.
Run this once for each client firewall zone. Start with lan:
zone="lan"
rule="force_dns_${zone}"
uci -q delete "firewall.${rule}"
uci set "firewall.${rule}=redirect"
uci set "firewall.${rule}.name=Force-DNS-${zone}"
uci set "firewall.${rule}.src=${zone}"
uci set "firewall.${rule}.src_dport=53"
uci set "firewall.${rule}.dest_port=54"
uci set "firewall.${rule}.proto=tcp udp"
uci set "firewall.${rule}.target=DNAT"
uci set "firewall.${rule}.family=any"
uci set "firewall.${rule}.enabled=1"
uci commit firewall
service firewall restartMy router has a separate iot zone, so I run the same block again with zone="iot". Because that zone rejects input to the router, it also has an explicit DNS allowance:
uci -q delete firewall.allow_dns_iot
uci set firewall.allow_dns_iot="rule"
uci set firewall.allow_dns_iot.name="Allow-DNS-IoT"
uci set firewall.allow_dns_iot.src="iot"
uci set firewall.allow_dns_iot.dest_port="53"
uci set firewall.allow_dns_iot.proto="tcp udp"
uci set firewall.allow_dns_iot.target="ACCEPT"
uci commit firewall
service firewall restartDo not add 127.0.0.1#54 as a dnsmasq forwarding server in this design. AdGuard Home sends local names back to dnsmasq, so forwarding dnsmasq back to AdGuard Home would create a loop.
53, including devices that hard-code a public resolver. It cannot intercept DNS-over-HTTPS, DNS-over-TLS, or DNS-over-QUIC; those require a separate browser or network policy.Configure DNS upstreams
Under Settings → DNS settings, my current default upstreams are one DNS-over-QUIC resolver and one DNS-over-TLS resolver:
quic://dns10.quad9.net
tls://one.one.one.one
[/lan/]127.0.0.1The last line sends local .lan names to dnsmasq. I also set Private reverse DNS servers to 127.0.0.1, which lets AdGuard Home show names learned by dnsmasq instead of only client addresses. AdGuard Home documents the same domain-specific upstream syntax.
The rest of the settings reflect a private home network rather than a public resolver:
- Upstream mode: parallel requests
- DNSSEC: enabled
- Cache: 4 MiB
- Optimistic caching: disabled
- Rate limit:
0 - Query log retention: one day
- Statistics retention: one day
I currently route a small set of Google service domains back to dnsmasq as part of a separate network policy. That exception is specific to my router, so it is deliberately absent from the reusable configuration above.
Add one blocklist
Under Filters → DNS blocklists, I use only OISD Big. One maintained list is easier to reason about than a pile of overlapping lists, produces fewer duplicate rules, and has been enough for this network.
More lists do not automatically mean better protection. Add another only when it blocks something your current list demonstrably misses, then check the query log for false positives.
Verify the path
From a device on the LAN, query the router normally:
dig @<router-ip> example.orgThe request should appear in AdGuard Home's query log under that device's address. A direct query to port 54 helps separate AdGuard Home problems from firewall problems:
dig @<router-ip> -p 54 example.orgIf the direct query works but the normal one does not, inspect the redirect. If neither works, inspect the service:
service adguardhome status
logread -e AdGuardHome
netstat -lntup | grep -E '(:53|:54|:3000)'Update and back up safely
The OpenWrt service starts AdGuard Home with its built-in updater disabled. Keep the package manager in charge of /usr/bin/AdGuardHome:
apk update
apk upgrade adguardhomeUse opkg update && opkg upgrade adguardhome on older OpenWrt releases.
Upgrade this package deliberately; do not turn it into a blanket apk upgrade or opkg upgrade for the whole router. OpenWrt recommends a firmware sysupgrade when the base system needs updating so its packages stay ABI-compatible.
OpenWrt preserves /etc/adguardhome/adguardhome.yaml during a sysupgrade. The data under /var/lib/adguardhome is not part of that package keep-list, so back it up separately only if historical query logs and statistics matter to you.
The result is simpler than my old installation: OpenWrt owns the binary and service, dnsmasq keeps doing the local jobs it is good at, and the firewall sends client DNS through AdGuard Home without changing what DHCP advertises.
