Hello everyone, first-time Flint user here! I just set up my Flint 4 and wrote down every change and why I made it, partly so I can repeat it if necessary, partly because a couple of these cost me an afternoon each. The order below is how I'd do it again.
Transparency: I worked most of this out with an LLM. The logs, commands and outputs below are from my own unit (GL-BE14000, firmware 4.9.1, dnsmasq 2.85).
TL;DR
- Network Acceleration: ON
- AdGuard Home: ON, Handle Client Requests: OFF
- AGH upstream:
tls://dns.quad9.net, with Cloudflare DoT as a fallback only - AGH blocking mode: NXDOMAIN (stops dnsmasq's "possible DNS-rebind attack" warnings for blocked domains)
- Override DNS Settings of All Clients: ON
- DNS Rebinding Attack Protection: ON, whitelisting only what
logreadshows is broken - Tailscale: accept-dns off; GL already sends your tailnet's names to Tailscale's resolver, so AGH needs no rule for them
1. Network Acceleration — ON
NETWORK → Network Acceleration
Moves forwarding of established connections onto a fast path that skips most of the Linux network stack. The panel warns it breaks client speed/traffic statistics, client speed limits, parental control and VPN-with-IPv6. I use none of those, so it's free throughput.
It does not conflict with AdGuard Home. Offloading only applies to traffic the router forwards. DNS queries are addressed to the router itself on port 53, so the CPU handles them either way and there's nothing for the fast path to skip. That includes queries redirected by section 4: after the redirect they're addressed to the router too. AdGuard Home isn't on GL.iNet's list of affected features.
One thing it won't help with: anything crossing a VPN interface still gets encrypted by the CPU, so it does nothing for Tailscale throughput. Don't expect it to.
2. AdGuard Home — ON, "Handle Client Requests" OFF
APPLICATIONS → AdGuard Home
Enable AdGuard Home. I've intentionally left "Handle Client Requests" OFF. That way dnsmasq stays on port 53 and forwards to AGH on port 3053. Filtering is the same either way, but every client shows up as localhost in AGH's query log.
Turning it ON buys you per-client visibility and per-device rules. The cost, per GL.iNet's docs: it "will render domain-based VPN policies and parental control rules ineffective". Domain-based policy routing needs dnsmasq to resolve the names and fill the sets the routing rules match on. It also takes dnsmasq's rebind protection (section 5) out of the path. With it ON, the nip.io test from section 5 returned 192.168.8.1; switched back OFF, it came back empty again.
To reach AGH's own interface, click Settings Page in the panel. It opens on port 3000, and the login is your router admin password.
3. AdGuard Home DNS settings
In AGH: Settings → DNS settings. Everything in this section is on that one page.
Upstream: encrypted, via DoT. The default was plaintext 8.8.8.8 / 9.9.9.9, which means every domain my household looks up leaves the router in the clear for the ISP to read and log. The Upstream DNS servers box now has:
tls://dns.quad9.net
and Fallback DNS servers has:
tls://1dot1dot1dot1.cloudflare-dns.com
Why Quad9, and why Cloudflare only as fallback. I dropped Google. It works fine, it's just the provider with the most commercial interest in the query stream, which defeats the point of the exercise. Quad9 is a Swiss non-profit that doesn't log client IPs, and it blocks known malware domains. Cloudflare only gets used when Quad9 stops responding, so one provider's outage doesn't take the house offline. Neither sends EDNS Client Subnet, and AGH's own EDNS client subnet option stays off (the default).
I first had Cloudflare as a second upstream, thinking of it as a failover. It isn't one. In the default load-balancing mode AGH "uses a weighted random algorithm to select servers with the lowest number of failed lookups and the lowest average lookup time", so whichever answers faster gets most of your queries. And since Quad9 blocks malware and plain 1.1.1.1 doesn't, malware blocking became a coin toss. If you want two upstreams anyway, pair Quad9 with tls://security.cloudflare-dns.com, Cloudflare's malware-blocking resolver, so the policy matches. Avoid parallel mode: it sends every query to every upstream, handing each provider your complete history.
DoT rather than DoH, because on a home line there's no reason to hide DNS inside port 443. DoH's advantage is surviving networks that block port 853 (hotel Wi-Fi, censored countries), which doesn't apply here, and DoT is slightly lighter.
What this doesn't hide: your ISP still sees which IPs you connect to, and for most sites the hostname in the TLS handshake (SNI). Encrypted DNS takes away the easiest log, not every log.
Also on that page:
- Bootstrap DNS servers: leave them as plain IPs. Mine are Quad9's unfiltered
9.9.9.10/149.112.112.10. AGH needs them to look updns.quad9.netbefore an encrypted channel exists. A plaintext bootstrap is fine: a spoofed answer would fail the TLS certificate check fordns.quad9.net. - Hit Test upstreams before applying.
- DNSSEC: enabled, but it's visibility, not protection. AGH doesn't validate locally. The toggle sets the DO bit on upstream queries and marks answers that came back with the AD flag in the query log. The protection itself (SERVFAIL instead of a forged answer for a signed domain) comes from Quad9 and Cloudflare, which validate every query whether or not this box is ticked. That's also why the encrypted channel matters: their validation only helps if nobody can tamper with the answer on its way to you. Costs next to nothing, so on it goes.
- Blocking mode: NXDOMAIN. Set it now; section 5 explains why.
Don't use an ad-blocking upstream. If your upstream also blocks ads, you'll eventually hit a blocked domain that appears in none of your AGH lists and waste an hour hunting for it. Quad9's malware blocking can do the same, just rarely.
4. Override DNS Settings of All Clients — ON
NETWORK → DNS
Force-redirects plaintext port 53 back to the router. Without it, any device with a hardcoded resolver skips AdGuard Home entirely: a phone set to 8.8.8.8, a TV that ignores DHCP-supplied DNS. Filtering you can bypass by typing an IP into a settings screen isn't really filtering.
It doesn't catch encrypted DNS: browser DoH on port 443, or DoT on port 853 (for example Android's Private DNS set to a hostname). Blocking those properly is a separate job I haven't done.
5. DNS Rebinding Attack Protection — ON
NETWORK → DNS
Off by default on mine. It rejects answers pointing at private addresses, which blocks the attack where a malicious page re-resolves its own domain to 192.168.8.1 and uses your browser as a channel into your router admin panel, NAS or cameras. It only works while dnsmasq is in the path (see section 2).
Quick test from a laptop on the LAN:
nslookup 192.168.8.1.nip.io 8.8.8.8
nip.io answers with whatever IP is in the name, so Google would return 192.168.8.1. Mine came back with Can't find 192.168.8.1.nip.io: No answer, and logread on the router showed possible DNS-rebind attack detected: 192.168.8.1.nip.io. That also proves section 4 works: the query never reached Google.
Why blocking mode has to be NXDOMAIN. Once this was on, my system log filled up with:
daemon.warn dnsmasq[9027]: possible DNS-rebind attack detected: nrdp.logs.netflix.com
once a second, plus Amazon and analytics domains. I assumed an upstream was returning private IPs. It wasn't: nslookup against Quad9 returned perfectly ordinary public AWS addresses.
What's actually happening: AGH blocks those telemetry domains and, in its default blocking mode, answers 0.0.0.0. dnsmasq sits in front of AGH and treats it as an upstream, and dnsmasq has counted 0.0.0.0/8 as a rebinding target since version 2.76, because 0.0.0.0 reaches the local host. So dnsmasq rejects the router's own ad blocker's answer, logs a warning, and hands the client an empty reply with no SOA record. There's nothing to cache, so the client asks again straight away.
Switching AGH's blocking mode to NXDOMAIN fixes it. AGH answers "no such domain" with no address at all, so dnsmasq has nothing to inspect and the log noise stops. The NXDOMAIN carries an SOA record, so it gets cached instead of re-asked.
If you run AGH behind dnsmasq with rebind protection on, do this.
Version note: on my dnsmasq 2.85, 0.0.0.0 gets flagged even with rebind_localhost on, which it is here. From 2.86, dnsmasq treats 0.0.0.0 like 127.0.0.0/8 and rebind_localhost exempts it, so newer firmware may not show these warnings at all. NXDOMAIN is still the better answer: a client handed 0.0.0.0 tries to connect to itself.
Whitelist only what's actually broken. Don't pre-emptively whitelist from a list you found online. Let the router tell you:
logread | grep rebind
If it's a domain you actually use and it's genuinely broken, whitelist it. If it's telemetry you've never heard of, leave it blocked (with NXDOMAIN blocking you shouldn't see those at all). For me that's just plex.direct. Plex deliberately resolves hostnames like 192-168-8-50.hash.plex.direct to your LAN address so local streaming gets a valid TLS cert. Blocked, local playback falls back to relay.
Via SSH, which is more reliable than hunting for the field across LuCI versions:
uci add_list dhcp.@dnsmasq[0].rebind_domain='plex.direct' uci commit dhcp /etc/init.d/dnsmasq restart
Or in LuCI (SYSTEM → Advanced Settings → Go To LuCI, port 8080, user root, password = admin password): Network → DHCP and DNS, field called Domain whitelist, "List of domains to allow RFC1918 responses for".
Other domains that legitimately do this: myunraid.net (plus unraid.net on older Unraid), remotewd.com, and dev conveniences like nip.io and sslip.io. Netflix is not one, despite appearing in my logs. That was the blocking-mode problem above.
6. Tailscale
accept-dns. With it on, Tailscale takes over the router's own resolver settings and points them at 100.100.100.100 instead of dnsmasq/AGH. Check yours:
tailscale debug prefs | grep -i CorpDNS
Mine was already false out of the box, and there's no "Accept DNS" toggle in the panel. If yours is true, use tailscale set --accept-dns=false rather than tailscale up --accept-dns=false. up wants every non-default flag restated (it refuses and prints the full command otherwise); set changes just the one.
Resolving tailnet names: GL already does it. With accept-dns off you'd expect *.ts.net names not to resolve, but GL's Tailscale integration handles your tailnet in dnsmasq instead. It sets dnsmasq's domain to your tailnet name (uci show dhcp | grep domain shows domain='tail1234.ts.net') and forwards that domain straight to Tailscale's resolver. With dnsmasq's query logging switched on, a lookup of the router's own tailnet name shows both halves of that:
query[A] gl-be14000.tail1234.ts.net from 127.0.0.1 /tmp/hosts/dhcp.cfg01411c gl-be14000.tail1234.ts.net is 192.168.8.1 query[AAAA] gl-be14000.tail1234.ts.net from 127.0.0.1 forwarded gl-be14000.tail1234.ts.net to 100.100.100.100
So tailnet lookups never reach AGH, and AGH needs no rule for them. I originally had [/ts.net/]100.100.100.100 in AGH's upstream box; it never got used. If your firmware doesn't do this and the check below fails, adding [/tail1234.ts.net/]100.100.100.100 to AGH's upstream box does the same job one hop later.
To verify, tailscale status --json | grep DNSName lists your devices' full names. Pick one that isn't the router (e.g. nas.tail1234.ts.net) and run nslookup nas.tail1234.ts.net 127.0.0.1. A 100.x answer means it works. (busybox nslookup then prints Can't find ...: No answer. It asks for AAAA too, and Tailscale's resolver on my router returns none; asking 100.100.100.100 directly gives the same result. Ignore it.)
Why not the router: dnsmasq expands local hostnames with its domain, which is now your tailnet. So the router's own name comes out of dnsmasq's hosts file as its LAN address (the 192.168.8.1 line above), not its 100.x address. Harmless for LAN devices, which reach the router directly, but confusing when you're testing. The same change means .lan names stop resolving: nslookup gl-be14000.lan returns NXDOMAIN on mine. A GL forum thread reports the same domain change.
Rebind protection doesn't interfere, for now. dnsmasq 2.85 only rebind-checks IPv4 answers, and tailnet addresses (100.64.0.0/10) aren't in its private list. dnsmasq 2.92 adds 100.64.0.0/10, so if a firmware update brings a newer dnsmasq, tailnet names will stop resolving and logread | grep rebind will list them. The fix is one more whitelist entry:
uci add_list dhcp.@dnsmasq[0].rebind_domain='tail1234.ts.net' uci commit dhcp /etc/init.d/dnsmasq restart
Advertise LAN Subnets is the option you may want if you need to reach home devices remotely. I left it off.
7. What I deliberately didn't do
AdGuard VPN. No WireGuard or OpenVPN configs, so it won't go in the GL.iNet VPN client UI. AdGuard does document router setups (IKEv2 on some routers, and a command-line client for OpenWrt using their own TrustTunnel protocol), but nothing you manage from the GL panel. If you want a router-level VPN you can run from the panel, pick a provider that publishes WireGuard configs.
AdGuard's paid apps (e.g. the Family plan). Per-device only, there's no router build, and they unlock nothing in AdGuard Home, which is free and open source. The paid apps do real things DNS can't (cosmetic filtering, YouTube ads in browsers, in-app ads on Android). They're a per-device complement to the router, not an upgrade to it.
Per-client DNS logging and parental controls. Both would have cost me something. Per-client logging needs Handle Client Requests (section 2), and parental controls don't work with Network Acceleration (section 1) or with Handle Client Requests.
Source: r/GlInet · by /u/tvelichkov