RouterOS has supported Linux containers since v7.4beta, and the feature has matured significantly through v7.16+ and into 2026’s v7.18 releases. You can pull container images from Docker Hub, GCR, Quay, or any OCI-compatible registry and run them directly on your MikroTik router — no separate server required.
Think about it: your MikroTik router sits at the edge of your network with a direct view of all traffic. Running lightweight containers like Pi-hole, AdGuard Home, Tailscale, or NetBird on the router itself eliminates an extra hop, reduces power consumption, and simplifies your stack.
This guide covers the full setup from scratch: enabling container mode, configuring networking, pulling images, setting up persistent storage, and practical real-world use cases.
Requirements and Limitations
Before diving in, check that your hardware is compatible.
Hardware Support
The container package works on arm, arm64, and x86 architectures. Not all RouterBOARD models support it:
- ARM64 (recommended): RB5009, CCR2116, CCR2216, hAP ax³/l³, L009, Chateau 5G — these have enough RAM and storage
- ARM (32-bit): hEX Refresh (RB750Gr3) — only arm32v5 images, limited selection
- x86: CHR and x86 installations — full support with external storage
- Not supported: Older MIPSBE, MIPSBLE, and Tile-based devices (RB7xx, RB9xx, RB1100, and most pre-2019 hardware)
Storage Requirements
Containers consume significant storage. RouterOS internal flash (usually 16MB–512MB) is not enough. You must attach external storage:
- USB flash drive or SSD
- SATA SSD (on models with SATA ports like RB5009 or CCR series)
- microSD card (on hAP ax³ or L009 — use A2-rated for speed)
Recommendation: at least 8GB, preferably 16GB+ for multiple containers. The filesystem should be ext4, which RouterOS supports natively.
Performance Considerations
Each container consumes CPU and RAM. A RouterBOARD RB5009 with its 4-core Cortex-A72 can comfortably run 3–5 lightweight containers (Pi-hole, Tailscale, Node Exporter). Resource-heavy containers like databases or media transcoders are not suitable.
MikroTik recommends external storage with at least 100 MB/s sequential read/write and 10K random IOPS — easily met by a USB 3.0 SSD.
Step 1 — Enable Container Mode
Container mode is gated behind device-mode for security reasons. Physical access to the router is required for the first step.
On ARM/ARM64 Devices
From a terminal session on the router (SSH or serial):
/system/device-mode/update container=yes
The router will prompt you to press the physical reset button within 30 seconds. Press and hold the button until the LED pattern changes. The device reboots with container mode enabled.
On x86 / CHR
For x86 and CHR installations, cold-reboot the VM or machine instead of the reset button:
/system/device-mode/update container=yes
Then reboot:
/system/reboot
Install the Container Package
RouterOS packages are managed via the package menu:
/system/package/update/set channel=stable
/system/package/update/install
After updating, verify the container package is available:
/container/config/print
If you see output like registry-url: https://lscr.io, the
package is installed and ready.
If not, install it from the packages menu at System > Packages > Available Packages in WinBox, or use:
/system/package/install container
/reboot
Step 2 — Configure Container Networking
Containers need a virtual Ethernet (veth) interface and a bridge to communicate with the rest of your network.
Create the Bridge
/interface/bridge/add name=containers
/ip/address/add address=172.17.0.1/24 interface=containers
Create a Veth Interface
/interface/veth/add name=veth1 address=172.17.0.2/24 gateway=172.17.0.1
Attach Veth to Bridge
/interface/bridge/port add bridge=containers interface=veth1
Masquerade Outbound Traffic
Containers need NAT to reach the internet:
/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24
Enable IP Forwarding (if not already)
/ip/settings/set forward=yes
At this point, any container attached to this veth interface will have outbound internet access through the router’s WAN.
Multiple Containers per Veth
You can attach multiple containers to the same veth interface if they listen on different ports. Alternatively, create isolated veth pairs per container:
/interface/veth/add name=veth-pihole address=172.17.0.3/24 gateway=172.17.0.1
/interface/veth/add name=veth-tailscale address=172.17.0.4/24 gateway=172.17.0.1
/interface/bridge/port add bridge=containers interface=veth-pihole
/interface/bridge/port add bridge=containers interface=veth-tailscale
Step 3 — Configure the Container Registry
RouterOS supports multiple registries. Set Docker Hub as your primary source:
/container/config/set \
registry-url=https://registry-1.docker.io \
tmpdir=disk1/tmp
Replace disk1 with your external drive label. Find yours:
/disk/print
The tmpdir is where container images are extracted. Point it
to external storage to avoid filling the internal flash.
Step 4 — Set Up Persistent Storage
Containers are ephemeral by default. For stateful services like Pi-hole (which stores DNS logs and blocklists), mount directories from your external disk.
Create Mount Directories
From the RouterOS shell:
/file/print
/file/mkdir disk1/containers/pihole
/file/mkdir disk1/containers/pihole-dnsmasq
/file/mkdir disk1/containers/adguard/work
/file/mkdir disk1/containers/adguard/conf
Register Mounts for Pi-hole
/container/mounts/add \
list=MOUNT_PIHOLE \
src=disk1/containers/pihole \
dst=/etc/pihole
/container/mounts/add \
list=MOUNT_PIHOLE_DNSMASQ \
src=disk1/containers/pihole-dnsmasq \
dst=/etc/dnsmasq.d
On first start, the container will populate the mount directory with its default files.
Step 5 — Deploy Pi-hole
Pi-hole is the most common container on RouterOS and one of the most practical — it turns your router into a network-wide ad blocker with a web dashboard.
Set Environment Variables
/container/envs/add list=ENV_PIHOLE key=TZ value="America/Santo_Domingo"
/container/envs/add list=ENV_PIHOLE key=FTLCONF_webserver_api_password value="your-secure-password"
/container/envs/add list=ENV_PIHOLE key=DNSMASQ_USER value="root"
/container/envs/add list=ENV_PIHOLE key=WEBPASSWORD value="your-admin-password"
Add the Container
/container/add \
remote-image=pihole/pihole:latest \
interface=veth1 \
root-dir=disk1/images/pihole \
envlist=ENV_PIHOLE \
mountlists=MOUNT_PIHOLE,MOUNT_PIHOLE_DNSMASQ \
start-on-boot=yes \
logging=no \
name=pihole
Wait for the Pull and Extract
Monitor progress:
/container/print detail
Wait until status changes to stopped. This means the image
has been pulled and extracted. Then start it:
/container/start pihole
Enable DNS Forwarding
Configure RouterOS to forward DNS queries to the container:
/ip/dns/set allow-remote-requests=yes servers=172.17.0.2
Expose the Web Interface
Add a destination NAT rule to access the Pi-hole admin panel:
/ip/firewall/nat/add \
chain=dstnat \
dst-address=192.168.88.1 \
dst-port=80 \
protocol=tcp \
action=dst-nat \
to-addresses=172.17.0.2 \
to-ports=80
Replace 192.168.88.1 with your router’s LAN IP. Now access
the admin panel at http://192.168.88.1/admin/.
Step 6 — Deploy AdGuard Home (Alternative)
AdGuard Home is a popular Pi-hole alternative with a more modern interface and built-in DHCP server support.
Environment Variables
/container/envs/add list=ENV_ADGUARD key=TZ value="America/Santo_Domingo"
Mounts
/container/mounts/add \
list=MOUNT_ADGUARD_WORK \
src=disk1/containers/adguard/work \
dst=/opt/adguardhome/work
/container/mounts/add \
list=MOUNT_ADGUARD_CONF \
src=disk1/containers/adguard/conf \
dst=/opt/adguardhome/conf
Add and Start
/container/add \
remote-image=adguard/adguardhome:latest \
interface=veth1 \
root-dir=disk1/images/adguard \
envlist=ENV_ADGUARD \
mountlists=MOUNT_ADGUARD_WORK,MOUNT_ADGUARD_CONF \
start-on-boot=yes \
name=adguard
DNS and Port Forwarding
/ip/firewall/nat/add \
chain=dstnat \
dst-address=192.168.88.1 \
dst-port=80 \
protocol=tcp \
action=dst-nat \
to-addresses=172.17.0.2 \
to-ports=80
/ip/dns/set servers=172.17.0.2
AdGuard Home listens on port 3000 for the initial setup wizard. Forward it temporarily:
/ip/firewall/nat/add \
chain=dstnat \
dst-address=192.168.88.1 \
dst-port=3000 \
protocol=tcp \
action=dst-nat \
to-addresses=172.17.0.2 \
to-ports=3000
After initial configuration, AdGuard Home runs its admin interface on port 80.
Step 7 — Deploy Tailscale on MikroTik
Tailscale in a container on your MikroTik router creates a mesh VPN endpoint without any additional hardware. This is useful for accessing management interfaces from outside your LAN.
/container/envs/add \
list=ENV_TAILSCALE \
key=TS_AUTHKEY value="tskey-auth-xxxxxxxx"
/container/envs/add \
list=ENV_TAILSCALE \
key=TS_STATE_DIR value="/var/lib/tailscale"
/container/mounts/add \
list=MOUNT_TAILSCALE \
src=disk1/containers/tailscale \
dst=/var/lib/tailscale
/container/add \
remote-image=tailscale/tailscale:latest \
interface=veth1 \
root-dir=disk1/images/tailscale \
envlist=ENV_TAILSCALE \
mountlists=MOUNT_TAILSCALE \
start-on-boot=yes \
name=tailscale
Important: the Tailscale container needs --privileged-like
capabilities to create the WireGuard tunnel. RouterOS containers
have limited support for the devices property. On some RouterOS
versions, you may need to add:
/container/set devices=tun tailscale
After starting the container and authorizing the node, your router becomes part of your Tailscale tailnet.
Step 8 — Management and Monitoring
View Running Containers
/container/print detail
Key fields: status (running/stopped), uptime, cpu-load,
memory-current, and root-dir usage.
Container Shell Access
Enter a running container’s shell:
/container/shell pihole
This drops you into an interactive shell inside the container.
Exit with Ctrl+D or type exit.
Stop and Start
/container/stop pihole
/container/start pihole
Update a Container Image
/container/update pihole
This pulls the latest image, extracts it, and replaces the existing one. The container will restart automatically.
View Container Logs
/log/print where topics~"container"
Or enable logging per container:
/container/set logging=yes pihole
Disable it afterward to avoid log noise:
/container/set logging=no pihole
Resource Limits
Prevent a container from consuming all RAM:
/container/set memory-max=134217728 pihole # 128 MB limit
/container/set memory-high=67108864 pihole # 64 MB soft limit
Troubleshooting
Container Fails to Start
/container/print detail
Look for status and last-error fields. Common causes:
- Storage full — check
/disk/printand free up space - Image not fully extracted — wait and check
status=extracting - veth interface missing — verify
/interface/veth/print
DNS Resolution Inside Container
If the container cannot resolve domain names, set explicit DNS:
/container/set dns=1.1.1.1 pihole
Pull Timeout for Large Images
Large images may time out on slow connections. Increase the timeout by adjusting the pull settings (not directly configurable in older ROS versions). Alternatively, download the image on a PC and import it manually:
/container/add file=pihole.tar.gz name=pihole-local
Container Image Compatibility
Use the architecture tag matching your CPU:
- ARM64 (RB5009, CCR):
arm64v8/or generic:latest - ARM32 (hEX Refresh):
arm32v5/— very limited library - x86/CHR:
amd64/or generic:latest
Summary
MikroTik Container support in RouterOS is a powerful feature that turns your network edge device into a lightweight application host. For homelab use cases like DNS filtering (Pi-hole / AdGuard Home), mesh VPN (Tailscale / NetBird), or monitoring (Node Exporter), running a container directly on the router is more efficient than spinning up a separate machine.
Key takeaways:
- External storage is mandatory — USB SSD or SATA, ext4 formatted, at least 8 GB
- Container mode requires physical access once, then remote management works normally
- Use the registry cache — repeated
container/updatecalls reuse the extracted image layer to save bandwidth - Monitor memory — RouterOS has limited RAM on most boards;
set
memory-maxper container - Start with Pi-hole — it is the most tested, well-documented container image for RouterOS
The same setup works for dozens of other lightweight Docker images. Just ensure the architecture matches your RouterBOARD and keep resource limits tight. Your router is now a router and a container host.