Updated May 2026: This guide has been revised to support RouterOS 7.22.
Starting with RouterOS v7.5, MikroTik introduced the ability to run Linux containers directly on supported devices. This opens up a world of possibilities from running ad-blockers like Pi-hole to local DNS resolvers such as DNSCrypt-proxy.
In this guide, I’ll show how I migrated my Pi-hole setup from a Raspberry Pi Zero to a MikroTik router. So far it’s been running smoothly.
Prerequisites
Before we start, make sure you have:
- MikroTik RouterOS v7.5+
- ARM64-based device
- External storage (USB or M.2, formatted as
ext3orext4) - Physical access to the device (you’ll need to reboot it manually)
We’ll install two containers:
- Pi-hole: ad-blocking DNS server
- DNSCrypt-proxy: encrypted DNS resolver
Step-by-Step Instructions
Connect via SSH or WebFig terminal to your router.
Step 1. Add CA Root Certificates
Fetch and import CA root certificates:
/tool/fetch https://curl.se/ca/cacert.pem
/certificate/import file-name=cacert.pem
Step 2. Enable Container Mode
/system/device-mode/update container=yes
You’ll be prompted to reboot your router. Do it manually.
Step 3. Configure Networking
Create a veth interface for PI-hole and assign it an IP address:
/interface/veth/add name=veth1 address=172.17.0.2/24 gateway=172.17.0.1
Create a bridge for containers:
/interface/bridge/add name=containers
/ip/address/add address=172.17.0.1/24 interface=containers
Add the veth interface to the bridge:
/interface/bridge/port add bridge=containers interface=veth1
Add NAT masquerade for outbound traffic:
/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24
Step 4. Configure Environment Variables for Pi-hole
/container/envs/add list=ENV_PIHOLE key=TZ value="UTC"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_webserver_api_password value="mysecurepassword"
/container/envs/add list=ENV_PIHOLE key=DNSMASQ_USER value="root"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_dns_upstreams value="172.17.0.3#5053"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_dns_listeningMode value="ALL"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_dns_queryLogging value="false"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_ntp_sync_active value="false"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_ntp_sync_interval value=0
Step 5. Prepare Storage
Format your USB drive:
/disk format usb1 file-system=ext4 mbr-partition-table=no
Create mounted volumes for Pi-hole:
/container/mounts/add list=MOUNT_PIHOLE_PIHOLE src=usb1/volumes/pihole/pihole dst=/etc/pihole
/container/mounts/add list=MOUNT_PIHOLE_DNSMASQD src=usb1/volumes/pihole/dnsmasq.d dst=/etc/dnsmasq.d
Set the container registry and image directory:
/container/config/set registry-url=https://registry-1.docker.io tmpdir=usb1/container/images
Step 6. Deploy Pi-hole Container
Add and configure the Pi-hole container:
/container/add remote-image=pihole/pihole interface=veth1 root-dir=usb1/images/pihole mountlists=MOUNT_PIHOLE_PIHOLE,MOUNT_PIHOLE_DNSMASQD envlist=ENV_PIHOLE name=pihole
Forward Pi-hole’s web port:
/ip firewall nat add action=dst-nat chain=dstnat dst-address=192.168.88.1 dst-port=8080 protocol=tcp to-addresses=172.17.0.2 to-ports=80
Access Pi-hole at: http://192.168.88.1:8080/admin/
Forward DNS port:
/ip firewall nat add action=dst-nat chain=dstnat dst-address=192.168.88.1 dst-port=53 protocol=udp to-addresses=172.17.0.2 to-ports=53
Step 7. Configure DNSCrypt
Create another veth interface for DNSCrypt:
/interface/veth/add name=veth2 address=172.17.0.3/24 gateway=172.17.0.1
/interface/bridge/port add bridge=containers interface=veth2
Add a mounted volume for DNSCrypt:
/container/mounts/add list=MOUNT_DNSCRYPT src=usb1/volumes/dnscrypt/config dst=/config
Add the DNSCrypt container:
/container/add remote-image=klutchell/dnscrypt-proxy:2.1.14 interface=veth2 root-dir=usb1/images/dnscrypt mountlists=MOUNT_DNSCRYPT name=dnscrypt
Step 8. Configure and Start Containers
Start and stop containers to generate volume structure:
/container/start pihole
/container/start dnscrypt
# Wait for a few seconds
/container/stop pihole
/container/stop dnscrypt
Use SFTP to upload configuration files(if needed):
- create on local machine file
dnscrypt-proxy.tomlwith following contentserver_names = ['cloudflare', 'google'] listen_addresses = ['0.0.0.0:5053'] max_clients = 250 ipv4_servers = true ipv6_servers = false dnscrypt_servers = true doh_servers = true require_dnssec = true require_nolog = true require_nofilter = true force_tcp = false timeout = 2500 keepalive = 30 use_syslog = true cert_refresh_delay = 240 bootstrap_resolvers = ['9.9.9.11:53', '8.8.8.8:53'] ignore_system_dns = true netprobe_timeout = 30 netprobe_address = '9.9.9.9:53' log_files_max_size = 10 log_files_max_age = 7 log_files_max_backups = 1 block_ipv6 = false cache = true cache_size = 4096 cache_min_ttl = 2400 cache_max_ttl = 86400 cache_neg_min_ttl = 60 cache_neg_max_ttl = 600 [query_log] format = 'tsv' [nx_log] format = 'tsv' [blacklist] [ip_blacklist] [whitelist] [schedules] [sources] [sources.public-resolvers] urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md'] cache_file = 'public-resolvers.md' minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' refresh_delay = 72 prefix = '' [sources.relays] urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/relays.md'] cache_file = 'relays.md' minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' refresh_delay = 72 prefix = '' [broken_implementations] fragments_blocked = ['cisco', 'cisco-ipv6', 'cisco-familyshield', 'cisco-familyshield-ipv6', 'cleanbrowsing-adult', 'cleanbrowsing-adult-ipv6', 'cleanbrowsing-family', 'cleanbrowsing-family-ipv6', 'cleanbrowsing-security', 'cleanbrowsing-security-ipv6'] [static] - create another file
adlists.listwith following content:http://sysctl.org/cameleon/hosts https://v.firebog.net/hosts/AdguardDNS.txt https://v.firebog.net/hosts/Easyprivacy.txt https://adaway.org/hosts.txt https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt - navigate into
usb1/volumes/pihole/piholeand remove everything - copy
dnscrypt-proxy.tomlintousb1/volumes/dnscrypt/config - rnavigate into
usb1/volumes/dnscrypt/configand remove everything - copy
adlists.listintousb1/volumes/pihole/pihole
Then restart both containers:
/container/start pihole
/container/start dnscrypt
Step 9. Verify DNS Functionality
From your PC:
nslookup google.com 192.168.88.1
dig google.com @192.168.88.1
Step 10. Configure Auto-Start and Memory Limits
Make containers start automatically after reboot:
/container/set 0 start-on-boot=yes
/container/set 1 start-on-boot=yes
Limit container memory usage:
/container/config/set memory-high=200M
Troubleshooting Tips
- Ensure your external storage is mounted and formatted as ext4.
- Check logs with
/container/logs print follow=yes. - If DNS doesn’t resolve, verify that your bridge and veth interfaces are configured properly and default DNS is disabled on the router.
- Confirm that Pi-hole is using DNSCrypt.
Conclusion
Running Pi-hole and DNSCrypt on MikroTik RouterOS v7 is a powerful way to consolidate your home network setup.
No extra Raspberry Pi or external machine required just your router.
You now have:
- Encrypted DNS (via DNSCrypt)
- Ad-blocking and analytics (via Pi-hole)
- Centralized configuration and startup automation
MikroTik’s container support may be limited, but with a bit of setup, it’s incredibly flexible. Give it a try!
