The goal here is to send DNS from the router to upstream resolvers through DNS over TLS (DoT) with Unbound. I decide first whether dnsmasq will give up its DNS role or keep port 53 and forward to Unbound; the two models use different configuration blocks.[27]
Goals and prerequisites
The OpenWrt page describes DoT for encrypted DNS, reduced DNS leak/hijacking exposure, and optional public providers. I need LuCI or SSH access, package/service/log administration, and a console fallback in case a DNS change breaks resolution.[27]
Option A: Unbound as the primary resolver
Disable dnsmasq's DNS role (its DHCP role can optionally remain with odhcpd), then install Unbound:[27]
1
2
3
4
5
6
7
8
9
# Install packagesopkg update
opkg install unbound-daemon
# Enable DNS encryptionuci set unbound.fwd_google.enabled="1"uci set unbound.fwd_google.fallback="0"uci commit unbound
service unbound restart
In this model, LAN clients and the local system use Unbound as their primary resolver, assuming dnsmasq no longer owns port 53.[27]
Test the resolver and protocol
Check resolution through localhost:[27]
1
nslookup openwrt.org localhost
The source lists provider tests for Cloudflare, AdGuard, NextDNS, Mullvad, Quad9, and OpenDNS, together with DNS Leak and DNSSEC tests. CLI checks include:[27]
1
2
3
4
dig +short txt proto.on.quad9.net.
# should print: doh. or dot. or doq.curl -SL https://test.nextdns.io/
A useful NextDNS result can contain "status": "ok" and "protocol": "DOT". I do not treat one successful nslookup as sufficient; I also check the provider result and the real path.[27]
Troubleshooting and runtime audit
When DNS fails, restart logging/Unbound and collect runtime and persistent configuration:[27]
1
2
3
4
5
6
7
8
9
10
11
12
# Restart servicesservice log restart; service unbound restart
# Log and statuslogread -e unbound; netstat -l -n -p | grep -e unbound
# Runtime configurationpgrep -f -a unbound
head -v -n -0 /etc/resolv.* /tmp/resolv.* /tmp/resolv.*/*
# Persistent configurationuci show unbound
I check the listening port, resolver files, and uci show unbound before adding firewall rules; blindly changing a service that already owns the expected port makes recovery harder.[27]
Manage Unbound through LuCI
Install the integration:[27]
1
2
3
4
# Install packagesopkg update
opkg install luci-app-unbound
service rpcd restart
Then open LuCI → Services → Recursive DNS to configure Unbound.[27]
Switch the provider to Cloudflare
1
2
3
4
5
6
# Configure DoT provideruci set unbound.fwd_google.enabled="0"uci set unbound.fwd_cloudflare.enabled="1"uci set unbound.fwd_cloudflare.fallback="0"uci commit unbound
service unbound restart
Use another provider or Cloudflare Family
Disable both presets and create a root forward_zone:[27]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Configure DoT provider (example: "Cloudflare Family Protection")uci set unbound.fwd_google.enabled="0"uci set unbound.fwd_cloudflare.enabled="0"while uci -q del unbound.@zone[4];do :;doneuci add unbound zone
uci set unbound.@zone[-1].enabled="1"uci set unbound.@zone[-1].fallback="0"uci set unbound.@zone[-1].zone_type="forward_zone"uci add_list unbound.@zone[-1].zone_name="."uci add_list unbound.@zone[-1].server="1.1.1.3"uci add_list unbound.@zone[-1].server="1.0.0.3"uci add_list unbound.@zone[-1].server="2606:4700:4700::1113"uci add_list unbound.@zone[-1].server="2606:4700:4700::1003"uci set unbound.@zone[-1].tls_upstream="1"uci set unbound.@zone[-1].tls_index="family.cloudflare-dns.com"uci commit unbound
service unbound restart
Multiple resolvers improve fault tolerance, but the provider addresses and TLS hostname must match the actual service; do not change tls_index arbitrarily.[27]
Enable DNSSEC
1
2
3
4
# Enforce DNSSEC validationuci set unbound.@unbound[0].validator="1"uci commit unbound
service unbound restart
The source warns that DNSSEC has fault-tolerance and performance trade-offs. I enable it after basic DoT works so I can identify which layer caused a failure.[27]
Option B: keep dnsmasq on port 53 and forward to Unbound:5353
If dnsmasq should remain the LAN resolver, move Unbound and configure dnsmasq:[27]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Change unbound port to 5353, because dnsmasq is running already on port 53sed -i "s/option listen_port '53'/option listen_port '5353'/g" /etc/config/unbound
sed -i "s/option add_local_fqdn '2'/option add_local_fqdn '0'/g" /etc/config/unbound
# configure dnsmasq to forward to localhost 5353service dnsmasq stop
uci set dhcp.@dnsmasq[0].noresolv="1"uci set dhcp.@dnsmasq[0].cachesize='0'uci -q delete dhcp.@dnsmasq[0].server
uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#5353"uci add_list dhcp.@dnsmasq[0].server="::1#5353"uci commit dhcp
service dnsmasq start
service unbound restart
Optional steps for the forwarding model
If NTP must work before DNS is ready:[27]
1
2
3
4
5
6
7
# Optional - ensure, that the NTP server can work without DNSuci del system.ntp.server
uci add_list system.ntp.server='194.177.4.1'# 0.openwrt.pool.ntp.orguci add_list system.ntp.server='213.222.217.11'# 1.openwrt.pool.ntp.orguci add_list system.ntp.server='80.50.102.114'# 2.openwrt.pool.ntp.orguci add_list system.ntp.server='193.219.28.60'# 3.openwrt.pool.ntp.orguci commit system
Disable ISP-provided DNS:[27]
1
2
3
4
# Optional: Disable ISP's DNS serveruci set network.wan.peerdns='0'uci set network.wan6.peerdns='0'uci commit network
Force LAN clients away from public DNS:[27]
1
2
3
4
5
6
7
8
# Optional: Force LAN clients to send DNS queries to dnsmasq (that later will be going to unbound):uci add firewall rule
uci set firewall.@rule[-1].name='Block-Public-DNS'uci set firewall.@rule[-1].src='lan'uci set firewall.@rule[-1].dest='wan'uci set firewall.@rule[-1].dest_port='53 853 5353'uci set firewall.@rule[-1].target='REJECT'uci commit firewall
When an internal DNS server listens on another port, the source also includes a redirect example. Do not use it with an mDNS server:[27]
1
2
3
4
5
6
7
8
9
10
11
12
13
## 2. Optional: Redirect queries for DNS servers running on non-standard ports. For example: 5353## Warning: don't use this one if you run an mDNS serveruci add firewall redirect
uci set firewall.@redirect[-1].dest='lan'uci set firewall.@redirect[-1].target='DNAT'uci set firewall.@redirect[-1].name='Divert-DNS, port 5353'uci set firewall.@redirect[-1].src='lan'uci set firewall.@redirect[-1].src_dport='5353'uci set firewall.@redirect[-1].dest_port='53'uci commit firewall
# On the end/etc/init.d/firewall reload
Practical conclusion
I choose one of the two designs: Unbound owns the resolver role, or dnsmasq keeps port 53 and forwards to Unbound on 5353. After each change I check nslookup, the provider protocol, Unbound logs, listening ports, uci show unbound, and the firewall. If a redirect, public-DNS block, or DNSSEC setting breaks access, I revert one logical group through the console instead of resetting the whole router.[27]
Source
Original source: [DoT with Unbound]1, published/updated 2025-02-28.[27]
Góp Ý / Bình Luận / Đánh giá