Skip to content

Instantly share code, notes, and snippets.

@marfillaster
Last active May 16, 2026 12:35
Show Gist options
  • Select an option

  • Save marfillaster/d34bd199b9e265ccd74af6d31fd9df85 to your computer and use it in GitHub Desktop.

Select an option

Save marfillaster/d34bd199b9e265ccd74af6d31fd9df85 to your computer and use it in GitHub Desktop.
MikroTik RouterOS v7: DoH + ULA DNS via IPv6 RA RDNSS

MikroTik RouterOS v7: DoH + IPv6 RA RDNSS with ULA DNS

Self-contained paste for a RouterOS v7 LAN that already has IPv6 SLAAC working. It makes the router the LAN DNS resolver, sends upstream DNS through Cloudflare DoH, advertises the router's own ULA as DNS via RA RDNSS, and stops DHCPv4 from advertising 192.168.88.1 as DNS while keeping admin@192.168.88.1 management working.

Full write-up with topology, rationale, and the rest of the build: https://marfillaster.github.io/mikrotik-home-network

DNS companion/update for:

Three things changed from the earlier revision of this gist, and the write-up explains why each:

  • DoH bootstrap is A-only on purpose. IPv4 is up the moment the WAN is; IPv6 only becomes reachable after the WireGuard tunnel (and BFD) converge. Pinning AAAA records for cloudflare-dns.com would push the first DoH query onto a half-warm or broken tunnel while the IPv4 path is direct to a nearby Cloudflare PoP. Once DoH is up, normal client queries still resolve and use AAAA records.
  • RA RDNSS uses advertise-dns=self, not a hardcoded dns=. The router advertises whatever address it holds on the interface, so the RDNSS can never point at a stale or wrong address and it survives a renumber with nothing to keep in sync.
  • dns-none=yes is uniform. No VLAN hands out a DHCPv4 resolver anymore; DNS is uniformly the ND RDNSS and the router resolves upstream over DoH. Trade-off: a client with no RFC 8106 RDNSS support gets no DNS — acceptable here because every VLAN carries a ULA and the device population supports it.

Replace:

  • <LAN_BRIDGE> with your LAN bridge, usually bridge
  • <LAN_ULA> with the router's LAN ULA, for example fd96:7d0b:7dc2:1::1
# Import CA roots before enabling DoH.
/tool/fetch url=https://curl.se/ca/cacert.pem dst-path=cacert.pem
/certificate/import file-name=cacert.pem passphrase=""

# Router DNS resolver + Cloudflare DoH.
/ip dns
set allow-remote-requests=yes \
    max-concurrent-queries=200 \
    use-doh-server=https://cloudflare-dns.com/dns-query \
    verify-doh-cert=yes

# DoH endpoint bootstrap (A-only on purpose) + local router name.
/ip dns static
add address=104.16.248.249 name=cloudflare-dns.com comment="DoH bootstrap"
add address=104.16.249.249 name=cloudflare-dns.com comment="DoH bootstrap"
# Reachable as the FQDN `router.lan` from any client whose resolver is the
# router. No search-domain magic; type the dot-lan suffix.
add address=<LAN_ULA>      name=router.lan type=AAAA comment="LAN ULA"

# Add stable LAN ULA and advertise self as DNS via RA RDNSS.
/ipv6 address
add address=<LAN_ULA>/64 advertise=yes interface=<LAN_BRIDGE> comment="ULA - RFC 4193"

# advertise-dns=self: the router advertises whatever address it holds on the
# interface, so RDNSS survives a renumber with nothing to keep in sync.
/ipv6/nd
add interface=<LAN_BRIDGE> \
    advertise-dns=self \
    managed-address-configuration=no other-configuration=no \
    ra-interval=20s-200s

# Stop DHCPv4 from advertising 192.168.88.1 as DNS; clients use RDNSS instead.
# This does not remove 192.168.88.1 from the bridge.
/ip dhcp-server network
set [find address=192.168.88.0/24] dns-none=yes

Test on the router:

:put [:resolve "cloudflare.com"]
/log/print where message~"DoH|dns"

Test on macOS:

scutil --dns | grep -i 'nameserver\['
dig @<LAN_ULA> cloudflare.com
dig @<LAN_ULA> ipv6.google.com AAAA

Expected macOS DNS:

nameserver[0] : <LAN_ULA>

192.168.88.1 should no longer appear as DNS after the Mac renews DHCP or Wi-Fi reconnects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment