Run BIND9 DNS in a Container on MikroTik RouterOS
This guide shows how to run a BIND9 DNS server in a container on MikroTik RouterOS, using external storage and RouterOS container support. The setup was tested on the MikroTik RB5009UG+S+IN, but should work on most MikroTik routers that support containers.
The container runs BIND independently from RouterOS DNS and uses mounted storage for configuration, zones, and cache data.
Why Run BIND Instead of RouterOS DNS?
For many years I ran BIND on dedicated hardware—first repurposed thin clients and later Raspberry Pis.
A couple of years ago, I simplified my home network by removing those servers and relying on RouterOS DNS forwarding with static host entries. That worked well, but eventually I began expanding my home lab again and wanted the full flexibility of a real DNS server:
- authoritative zones
- advanced caching configuration
- DNSSEC control
- full configuration flexibility
Running BIND in a container on the router turned out to be a simple and efficient solution.
Requirements
To run a BIND container on RouterOS you need:
- A MikroTik device that supports RouterOS containers
- External USB storage
- A compatible container image
- A dedicated container subnet
The RB5009 hardware is more than capable of handling a small DNS container.
Storage for RouterOS Containers
RouterOS containers require external storage.
I initially tested using a USB thumb drive, but those are not designed for continuous disk activity. Instead I connected an NVMe SSD through a USB enclosure and formatted it on the router.
After connecting the disk:
- Navigate to System → Disks
- Select the device (for example
usb1) - Format it using ext4
RouterOS will then expose the disk through the Files interface.
Installing Container Support on RouterOS
Download the container package from:
Make sure the package matches:
- RouterOS version
- CPU architecture
Upload the package through WinBox → Files, then reboot the router.
Next enable container support:
/system/device-mode/update container=yes
Perform a cold reboot (power cycle) after enabling containers.
Preparing the BIND Directory Structure
Create the following directories on the USB disk:
usb1/bind9
usb1/bind9/cache
usb1/bind9/etc
usb1/bind9/hints
usb1/bind9/lib
usb1/bind9/log
These correspond to the directories used inside the container:
| Container Directory | Purpose |
|---|---|
| /etc/bind | BIND configuration |
| /var/cache/bind | DNS cache |
| /var/lib/bind | zone storage |
| /var/log | logging |
| /usr/share/dns | DNS hints |
If you already run BIND elsewhere, you can copy your existing configuration into the /etc/bind directory.
Selecting a BIND Container Image
RouterOS can download container images directly from Docker Hub.
After some experimentation I found a container built specifically for MikroTik:
https://hub.docker.com/r/tecspace/bind9-mikrotik
This avoids architecture compatibility issues that sometimes occur with official images.
Creating Container Mount Points
Container mounts connect RouterOS directories to the container filesystem.
Create mounts mapping the RouterOS directories to the container paths:
| List | Src | Dst |
|---|---|---|
| MOUNT_BIND9 | /usb1/bind9/cache | /var/cache/bind |
| MOUNT_BIND9 | /usb1/bind9/etc | /etc/bind |
| MOUNT_BIND9 | /usb1/bind9/hints | /usr/share/dns |
| MOUNT_BIND9 | /usb1/bind9/lib | /var/lib/bind |
| MOUNT_BIND9 | /usb1/bind9/log | /var/log |
Environment Variables
Environment variables can override container defaults.
Example configuration:
| List | Key | Value |
|---|---|---|
| ENV_BIND9 | BIND9_STAY_ON | 1 |
| ENV_BIND9 | BIND9_CMD_OPTS | -g -4 -u named |
| ENV_BIND9 | BIND9_CFG_OPTS | version “hidden”;directory “/var/cache/bind”;listen-on {any;};listen-on-v6 {none;};recursion yes;allow-query {0.0.0.0/0;};d/system/device-mode/update container=yesnssec-validation yes;max-cache-size 64M; |
Most configuration should still live in standard BIND configuration files.
Container Networking Configuration
Create a dedicated bridge for containers:
/interface/bridge/add name=bridge_containers
/ip/address/add address=172.16.0.1/24 interface=bridge_containers
Create a virtual Ethernet interface:
/interface/veth/add name=veth1 address=172.16.0.2/24 gateway=172.16.0.1
/interface/bridge/port/add bridge=bridge_containers interface=veth1
Enable NAT so the container can reach the internet:
/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.16.0.0/24
Creating the BIND Container
Configure the container registry:
/container/config/set registry-url=https://registry-1.docker.io tmpdir=usb1/tmp
Create the container:
/container/add \
remote-image=tecspace/bind9-mikrotik:1.0 \
interface=veth1 \
root-dir=usb1/images/bind9 \
mountlists=MOUNT_BIND9 \
envlist=ENV_BIND9 \
start-on-boot=yes \
name=bind9
Monitor the container download:
/container/print
Once the status shows stopped, start the container:
/container/start bind9
Using RouterOS to Forward DNS to the BIND Container
Once the server is operational, you may want the router itself to use the container.
Example RouterOS configuration:
/ip dns
set servers=172.16.0.2 allow-remote-requests=yes
Performance Observations
The BIND container uses minimal resources and has no noticeable impact on router performance.
In testing, DNS responses from BIND were actually slightly faster than RouterOS DNS forwarding—only by a few milliseconds, but consistently measurable.
Running BIND directly on the router turned out to be an elegant solution.
Testing DNS Performance
For DNS benchmarking I recommend:
https://www.grc.com/dns/benchmark.htm
GRC DNS Benchmark remains one of the best tools for comparing resolver performance.
Posted: March 9th, 2026 under Draft.
Comments: none