How to Deploy MasterDnsVPN Server with Docker on MikroTik RouterOS
MasterDnsVPN runs a custom DNS-tunnel server in a multi-architecture Docker container that requires only a persistent /data volume and a DOMAIN environment variable to deploy on MikroTik RouterOS v7+ using the native container subsystem.
MasterDnsVPN is an open-source DNS tunneling solution written in Go by masterking32/MasterDnsVPN. The project distributes a multi-architecture Docker image (ghcr.io/masterking32/masterdnsvpn:latest) that encapsulates the compiled server binary and initialization logic from docker/docker-entrypoint.sh. When deploying on MikroTik RouterOS v7 or newer, you leverage the native /container subsystem to run the image directly on the router hardware, eliminating the need for separate server infrastructure.
Prerequisites for RouterOS Container Deployment
Before starting, ensure your MikroTik device meets these requirements:
- RouterOS v7+ with the
containerpackage enabled (/system package enable container) - Writable storage (e.g.,
/disk1) for persistent configuration data - Delegated DNS subdomain (e.g.,
v.example.com) with NS records pointing to your router - Port 53 availability (UDP and TCP) for the DNS tunnel
The container image automatically initializes a default configuration from server_config.toml.simple if no existing configuration is found in the persistent data directory.
Creating the Persistent Storage Mount
MasterDnsVPN stores its server_config.toml and encrypt_key.txt in /data inside the container. You must create a host directory and mount list before creating the container.
Create the host directory and mount configuration:
/file make-dir name=masterdnsvpn-data
/container mounts
add dst=/data list=MasterDnsVPN src=/disk1/masterdnsvpn-data
This mount list named MasterDnsVPN maps the host's /disk1/masterdnsvpn-data to the container's /data path, ensuring your encryption keys and server configuration persist across container restarts and upgrades.
Configuring the Environment Variable
The server requires the DOMAIN environment variable on first startup to determine which DNS zone it will serve. Create an environment list in RouterOS:
/container envs
add key=DOMAIN list=MasterDnsVPN value=v.example.com
Replace v.example.com with the subdomain you delegated to the server. According to the docker/docker-entrypoint.sh script in the repository, this value is injected into the server configuration only during the initial bootstrap when /data/server_config.toml is missing.
Deploying the Container on RouterOS
With the mount list and environment variables configured, create the container definition using the official GitHub Container Registry image:
/container add \
check-certificate=no \
dns=1.1.1.1 \
envlists=MasterDnsVPN \
hostname=MasterDnsVPN \
interface=MasterDnsVPN \
layer-dir="" \
mountlists=MasterDnsVPN \
name=MasterDnsVPN \
remote-image=ghcr.io/masterking32/masterdnsvpn:latest \
root-dir=/containers/data/MasterDnsVPN \
start-on-boot=yes
This command references the MasterDnsVPN mount list and environment list created in previous steps. The start-on-boot=yes parameter ensures the DNS tunnel server automatically launches after router reboots.
Forwarding DNS Traffic to the Container
RouterOS requires destination NAT rules to redirect external DNS queries (port 53) to the container's internal interface:
/ip firewall nat add chain=dstnat protocol=tcp dst-port=53 action=dst-nat to-addresses=127.0.0.1 to-ports=53
/ip firewall nat add chain=dstnat protocol=udp dst-port=53 action=dst-nat to-addresses=127.0.0.1 to-ports=53
If the router runs another DNS service (such as the built-in DNS cache), disable or reconfigure it to free port 53. The container binds to UDP/TCP port 53 to accept DNS tunnel traffic as implemented in the server source code.
Verification and Container Management
Verify the container status:
/container print
Look for status=running in the output. Inspect server logs using:
/container log print where name=MasterDnsVPN
The docker/Dockerfile in the repository defines the entrypoint that launches the server binary. If the container fails to start, check that the DOMAIN variable is set correctly and that the /data mount point has sufficient permissions.
Alternative Docker Compose Deployment
For testing on non-RouterOS environments, use the provided docker/docker-compose.yml structure:
services:
masterdnsvpn:
image: ghcr.io/masterking32/masterdnsvpn:latest
restart: unless-stopped
environment:
- DOMAIN=v.example.com
volumes:
- ./data:/data
ports:
- "53:53/tcp"
- "53:53/udp"
Run with docker compose up -d. This uses the same DOMAIN variable and volume mapping logic as the RouterOS deployment, making migration between platforms straightforward.
Summary
- MasterDnsVPN runs as a multi-arch Docker container available at
ghcr.io/masterking32/masterdnsvpn:latestaccording to the masterking32/MasterDnsVPN source code - RouterOS v7+ requires a mount list for
/datapersistence and an env-list for theDOMAINvariable as documented inREADME.MD(lines 90-102) - The container initializes
server_config.tomlfromserver_config.toml.simpledefaults on first run if the persistent volume is empty - Port 53 must be forwarded via NAT rules to reach the container's DNS tunnel server
- Key files referenced:
docker/Dockerfile,docker/docker-entrypoint.sh, andserver_config.toml.simple
Frequently Asked Questions
How does MasterDnsVPN handle first-time configuration inside Docker?
According to the docker/docker-entrypoint.sh script in the repository, the container checks for /data/server_config.toml on startup. If the file is missing, it copies the template from server_config.toml.simple and injects the DOMAIN environment variable into the configuration before launching the server binary.
Can I run MasterDnsVPN on RouterOS versions older than v7?
No. The /container subsystem required to run OCI-compliant Docker images is only available in RouterOS v7 and newer. Earlier versions lack the container engine necessary to execute the ghcr.io/masterking32/masterdnsvpn:latest image.
What happens if I don't mount a persistent volume for /data?
Without a persistent mount, the container loses its encrypt_key.txt and server_config.toml after reboots or upgrades. This forces the server to regenerate cryptographic keys and reinitialize configuration, breaking existing client connections and requiring reconfiguration of the DNS delegation.
Why does the container need port 53 specifically?
MasterDnsVPN operates as a DNS-tunnel server, intercepting DNS queries to encapsulate VPN traffic. The server binary listens on UDP and TCP port 53 by design, as this is the standard port for DNS traffic. Delegating your subdomain's NS record to the router ensures client DNS queries reach the container.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →