Container
Container
Section titled “Container”The RouterOS Container feature lets you run Linux containers directly on your MikroTik device alongside its normal networking functions. Containers are compatible with images from Docker Hub, GitHub Container Registry (GHCR), Quay, and other OCI-compliant registries.
:::danger Security Warning Containers require elevated system access and introduce significant security considerations:
- Compromised routers can run malicious containers
- Third-party images may contain vulnerabilities
- Containers can potentially gain root access to RouterOS
- Backdoors may persist even after container removal
Use only trusted images from verified publishers and isolate containers with firewall rules. :::
Overview
Section titled “Overview”Key Capabilities
Section titled “Key Capabilities”- Pull and run standard Docker-compatible images directly from registries
- Configure flexible container networking using virtual ethernet (veth) interfaces
- Bind-mount router storage into containers for persistent data
- Pass environment variables to configure containerized applications
- Auto-restart and start-on-boot support for always-on services
Architecture
Section titled “Architecture”| Component | Purpose |
|---|---|
| Container package | Separate RouterOS package enabling container functionality |
| Device Mode | System-level flag that must be enabled before containers can run |
| veth interfaces | Virtual ethernet connecting containers to the router network |
| Container config | Global registry URL, temp storage, and RAM limit settings |
| envs | Named lists of environment variables attached to containers |
| mounts | Persistent host↔container directory bindings |
Requirements
Section titled “Requirements”Hardware
Section titled “Hardware”| Requirement | Details |
|---|---|
| Architecture | arm, arm64, or x86 |
| RouterOS version | v7.4 or later |
| Storage | External disk (USB, SATA, NVMe) strongly recommended — internal flash will wear out quickly |
| RAM | 256 MB minimum; 512 MB+ recommended for most containers |
Software
Section titled “Software”Install the Container package from the MikroTik package repository for your device architecture before proceeding.
Initial Setup
Section titled “Initial Setup”Step 1: Enable Device Mode
Section titled “Step 1: Enable Device Mode”Containers require device mode to be enabled. Run the command below, then confirm with the reset button (or cold reboot on x86):
/system/device-mode/update container=yesVerify it is active:
/system/device-mode/printStep 2: Configure Registry and Storage
Section titled “Step 2: Configure Registry and Storage”Set the registry URL and a temporary extraction directory on external storage:
/container/config/set registry-url=https://registry-1.docker.io tmpdir=disk1/tmpFor private registries or alternate sources (GHCR, Quay, LinuxServer):
/container/config/set registry-url=https://ghcr.io tmpdir=disk1/tmpFor authenticated registries (RouterOS v7.8+):
/container/config/set registry-url=https://registry-1.docker.io username=myuser password=mypasswordConfiguration Properties Reference
Section titled “Configuration Properties Reference”| Property | Description | Default |
|---|---|---|
registry-url | OCI registry base URL | https://lscr.io/ |
tmpdir | Temporary extraction directory | — |
memory-high | Soft RAM limit applied to all containers | unlimited |
username | Registry auth username (v7.8+) | — |
password | Registry auth password (v7.8+) | — |
Networking
Section titled “Networking”Containers connect to the router network through veth (virtual ethernet) interfaces. Each container gets its own veth with an IP address and gateway.
Basic: NAT Bridge (Recommended)
Section titled “Basic: NAT Bridge (Recommended)”Most use cases — containers share outbound internet access through NAT, and ports are forwarded inbound as needed:
# Create veth for the container/interface/veth/add name=veth1 address=172.17.0.2/24 gateway=172.17.0.1
# Create a bridge to attach veth interfaces to/interface/bridge/add name=containers
# Assign a host IP on the bridge (this is the container gateway)/ip/address/add address=172.17.0.1/24 interface=containers
# Add veth to bridge/interface/bridge/port/add bridge=containers interface=veth1
# NAT for outbound internet access/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24
# Example: forward port 80 to container/ip/firewall/nat/add action=dstnat chain=dstnat dst-address=192.168.88.1 dst-port=80 protocol=tcp to-addresses=172.17.0.2 to-ports=80Isolated Networks
Section titled “Isolated Networks”Run separate container groups with no cross-traffic:
/interface/veth/add name=veth1 address=172.17.0.2/24 gateway=172.17.0.1/interface/veth/add name=veth2 address=172.18.0.2/24 gateway=172.18.0.1/interface/bridge/add name=containers1/interface/bridge/add name=containers2/ip/address/add address=172.17.0.1/24 interface=containers1/ip/address/add address=172.18.0.1/24 interface=containers2/interface/bridge/port/add bridge=containers1 interface=veth1/interface/bridge/port/add bridge=containers2 interface=veth2/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.18.0.0/24Layer 2 (Bridge) Mode
Section titled “Layer 2 (Bridge) Mode”Attaches a container directly to an existing LAN bridge so it gets a LAN IP address:
/interface/veth/add name=veth1 address=192.168.88.2/24 gateway=192.168.88.1/interface/bridge/port/add bridge=bridge interface=veth1Layer 2 mode exposes all container ports to the LAN. Only use when broadcast-based service discovery is required (e.g. mDNS-dependent apps).
Dual Stack (IPv4 + IPv6)
Section titled “Dual Stack (IPv4 + IPv6)”/ip/address/add address=172.17.0.1/24 interface=containers/ipv6/address/add address=fd8d:5ad2:24:2::1 interface=containers/interface/veth/add address=172.17.0.2/24,fd8d:5ad2:24:2::2/64 gateway=172.17.0.1 gateway6=fd8d:5ad2:24:2::1 name=veth1/ip/firewall/nat/add action=masquerade chain=srcnat src-address=172.17.0.0/24/ipv6/firewall/nat/add action=masquerade chain=srcnat src-address=fd8d:5ad2:24:2::/64Environment Variables
Section titled “Environment Variables”Environment variables configure containerized applications without modifying images. They are organized into named lists attached to containers at creation.
# Create a named env list with key/value pairs/container/envs/add list=myapp-env key=TZ value=Europe/Riga/container/envs/add list=myapp-env key=DB_HOST value=172.17.0.3/container/envs/add list=myapp-env key=DB_PASSWORD value=secret
# View configured variables/container/envs/printAttach the list when creating the container using envlist=myapp-env.
Persistent Storage (Mounts)
Section titled “Persistent Storage (Mounts)”Mounts bind a directory on the router’s filesystem into the container, so data survives container removal and updates.
# Create named mount points/container/mounts/add name=myapp-data src=disk1/volumes/myapp dst=/data/container/mounts/add name=myapp-config src=disk1/volumes/myapp-config dst=/config
# View configured mounts/container/mounts/printAttach mounts when creating the container using mounts=myapp-data,myapp-config.
Adding Container Images
Section titled “Adding Container Images”Pull from Registry (Recommended)
Section titled “Pull from Registry (Recommended)”/container/config/set registry-url=https://registry-1.docker.io tmpdir=disk1/tmp/container/add remote-image=pihole/pihole:latest interface=veth1 root-dir=disk1/images/pihole name=piholeImport from Local File
Section titled “Import from Local File”Transfer a .tar image archive to the router via SFTP, then import:
/container/add file=disk1/myimage.tar interface=veth1 root-dir=disk1/images/myapp name=myappBuild and Import Custom Image
Section titled “Build and Import Custom Image”# On a workstation (match arch to your router)podman pull --arch=arm64 docker.io/myimage:tagpodman save myimage > myimage.tarUpload to router, then import with the file= method above.
Container Properties Reference
Section titled “Container Properties Reference”| Property | Description |
|---|---|
remote-image | Registry image name and tag to pull |
file | Path to local .tar image archive |
interface | veth interface for network connectivity |
root-dir | Directory where container layers are extracted |
envlist | Named environment variable list to inject |
mounts | Comma-separated list of named mount points |
start-on-boot | Auto-start after reboot (yes/no) |
logging | Forward container stdout/stderr to RouterOS log |
hostname | Container hostname |
dns | Override DNS servers (comma-separated IPs) |
user | UID:GID for the container process (e.g. 0:0 for root) |
cmd | Command to run (overrides image default) |
entrypoint | Entrypoint executable |
workdir | Working directory inside the container |
auto-restart-interval | Restart delay on failure (e.g. 10s) |
memory-high | Per-container RAM hard limit |
cpu-list | CPU core affinity (e.g. 0,1) |
devices | Host device passthrough (e.g. /dev/ttyUSB0) |
Managing Containers
Section titled “Managing Containers”Start, Stop, Restart
Section titled “Start, Stop, Restart”/container/start pihole/container/stop pihole/container/restart piholeView Status
Section titled “View Status”/container/print detailAccess Container Shell
Section titled “Access Container Shell”/container/shell piholeWith a specific user and command:
/container/shell myapp user=www-data cmd="php /var/www/html/cron.php" no-shModify Running Container
Section titled “Modify Running Container”/container/set pihole logging=yes start-on-boot=yesRemove a Container
Section titled “Remove a Container”/container/remove piholeComplete Example: Pi-hole
Section titled “Complete Example: Pi-hole”Pi-hole is a DNS-based ad blocker that runs well on most MikroTik hardware.
Prerequisites
Section titled “Prerequisites”- RouterOS v7.4+ with Container package installed
- External USB/SATA/NVMe storage mounted as
disk1 - Device mode enabled
Configuration
Section titled “Configuration”# 1. Enable device mode (requires reset button confirmation)/system/device-mode/update container=yes
# 2. Configure registry/container/config/set registry-url=https://registry-1.docker.io tmpdir=disk1/tmp
# 3. Create container network/interface/veth/add name=veth1 address=172.17.0.2/24 gateway=172.17.0.1/interface/bridge/add name=containers/ip/address/add address=172.17.0.1/24 interface=containers/interface/bridge/port/add bridge=containers interface=veth1/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24/ip/firewall/nat/add action=dstnat chain=dstnat dst-address=192.168.88.1 dst-port=80 protocol=tcp to-addresses=172.17.0.2 to-ports=80
# 4. Environment variables/container/envs/add list=ENV_PIHOLE key=TZ value="Europe/Riga"/container/envs/add list=ENV_PIHOLE key=FTLCONF_webserver_api_password value="mysecurepassword"/container/envs/add list=ENV_PIHOLE key=DNSMASQ_USER value="root"
# 5. Mounts for persistent data/container/mounts/add name=MOUNT_PIHOLE src=disk1/volumes/pihole/pihole dst=/etc/pihole/container/mounts/add name=MOUNT_PIHOLE_DNSMASQ src=disk1/volumes/pihole/dnsmasq.d dst=/etc/dnsmasq.d
# 6. Create and start container/container/add remote-image=pihole/pihole interface=veth1 root-dir=disk1/images/pihole \ mounts=MOUNT_PIHOLE,MOUNT_PIHOLE_DNSMASQ envlist=ENV_PIHOLE \ name=pihole logging=yes start-on-boot=yes
/container/start piholeAccess the Pi-hole web interface at http://192.168.88.1/admin/.
Troubleshooting
Section titled “Troubleshooting”Container Stuck in “Extracting” State
Section titled “Container Stuck in “Extracting” State”- Verify
tmpdiris set to a path on external storage with sufficient free space - Check disk space:
/system/resource/print - Review logs:
/log print
Container Will Not Start
Section titled “Container Will Not Start”- Confirm device mode:
/system/device-mode/print - Check veth interface exists:
/interface/veth/print - Verify mount source directories exist on storage
- Check for errors:
/log print where topics~"container"
/container/print detailNo Internet Access from Container
Section titled “No Internet Access from Container”- Confirm NAT rule exists:
/ip/firewall/nat/print - Check bridge has IP address:
/ip/address/print - Verify veth is in the bridge:
/interface/bridge/port/print
Container Exits Immediately
Section titled “Container Exits Immediately”- Enable logging and check output:
/container/set myapp logging=yes - Run an interactive shell to diagnose:
/container/shell myapp - Verify image architecture matches your router (arm vs arm64 vs x86)
Memory Issues
Section titled “Memory Issues”Limit container RAM to prevent router instability:
/container/config/set memory-high=256MOr per-container:
/container/set pihole memory-high=128M