Community discussions

MikroTik App
 
User avatar
erkexzcx
Member Candidate
Member Candidate
Topic Author
Posts: 264
Joined: Mon Oct 07, 2019 11:42 pm

How to configure Mikrotik for Pi-Hole with automatic failover

Thu Apr 25, 2024 11:13 am

Problem

You have a Mikrotik router and some server at home. Your family expects 100% high availability for the internet access, but you want to go extra step and install Pi-Hole or alike (I prefer Blocky) on home server. However, that home server crashed and DNS is no longer working for everyone at home! Or you wanted to reboot it, or upgrade something and Pi-Hole is no longer accessible.

While having 2nd server for Pi-Hole is an idea - it's actually an overkill...

Naturally you pick one out of 2 options:
  • Configure DHCP server to issue DHCP lease with DNS value pointing directly to Pi-Hole.
  • Configure Mikrotik's DNS server to Pi-Hole, and configure DHCP server to issue DHCP lease with DNS value pointing to Mikrotik router.
2nd option is somewhat "meh", since you would use 2 DNS forwarding servers and your DNS queries would be slower than using just 1 DNS forwarding server. Either way, bringing down your Pi-Hole will end up with (at least partial) downtime!

Solution

Thanks to Mikrotik's scripting functionality and freedom of configuration, we can achieve an automatic failover, while still using Pi-Hole directly. Here is the idea:
  • Mikrotik "port-forwards" DNS query traffic to Pi-Hole if Pi-Hole is working.
  • Mikrotik serves DNS queries by itself (e.g. from 1.1.1.2,1.0.0.2) if Pi-Hole is not working.
This allows us to have best of both worlds - use Pi-Hole directly if it's working, or use Mikrotik's DNS server as a temporary "workaround" until Pi-Hole is up and running.

Instructions

FYI for below steps, I am using "Blocky", therefore in comments I have this keyword :)

1. Configure router

First, point each of your network device to use router as DNS server.

Then disable the Mikrotik's DNS server:
/ip/dns/set allow-remote-requests=no
Now, create NAT rules, so tcp/udp traffic, coming to port 53 to router would be port-forwarded to your server that runs pi-hole (in my case it's 192.168.72.10):
/ip firewall nat add action=dst-nat chain=dstnat comment=Blocky dst-port=53 protocol=tcp src-address-list=LANs dst-address-list=LANs to-addresses=192.168.72.10
/ip firewall nat add action=dst-nat chain=dstnat comment=Blocky dst-port=53 protocol=udp src-address-list=LANs dst-address-list=LANs to-addresses=192.168.72.10
Now test if DNS is working:
$ nslookup mikrotik.com 192.168.72.1
Server:         192.168.72.1
Address:        192.168.72.1#53

Non-authoritative answer:
...
If it doesn't work (times out or rejected) - you are missing hairpin NAT rules. This is what I have in my case:
/ip firewall mangle add action=mark-connection chain=prerouting comment="Mark connections for hairpin NAT - LAN IP" dst-address-list=LANs new-connection-
mark="Hairpin NAT" passthrough=yes src-address-list=LANs
/ip firewall nat add action=masquerade chain=srcnat comment="Hairpin NAT" connection-mark="Hairpin NAT"
and try again - it should be working. Trying to resolve DNS query by using router's DNS you would actually use pi-hole instead of router.

If it's working, enable router's DNS server back:
/ip/dns/set allow-remote-requests=yes
And move to the next section...

2. Add scheduled script

Add this script to /system/scheduler (by using GUI). Modify it accordingly:
# Specify search filters for NAT rules
:local tcpRuleId [/ip firewall nat find comment="Blocky" protocol="tcp"]
:local udpRuleId [/ip firewall nat find comment="Blocky" protocol="udp"]

# Find Blocky IP from NAT rule
:local toAddresses [/ip firewall nat get $tcpRuleId to-addresses]

# Specify query domain
:local queryDomain "www.google.com"

:if ([/ip firewall nat get $tcpRuleId disabled] = false) do={
    :do {
        :resolve $queryDomain server=$toAddresses
    } on-error={
        /ip firewall nat set $tcpRuleId disabled=yes
        /ip firewall nat set $udpRuleId disabled=yes
    }
} else={
    :do {
        :resolve $queryDomain server=$toAddresses
        /ip firewall nat set $tcpRuleId disabled=no
        /ip firewall nat set $udpRuleId disabled=no
    } on-error={}
}
Notice the logic - if NAT rules are disabled, then Mikrotik's DNS server is used. If NAT rules are enabled - traffic is port-forwarded to Pi-Hole DNS server.

Schedule this script to run every 10-30 seconds and forget about complains when Pi-Hole is temporarily not working. :)

Who is online

Users browsing this forum: No registered users and 6 guests