---
title: Install TVPN on MikroTik (Docker)
description: Run the Somewear TVPN agent as a container on a MikroTik RouterOS router.
url: "https://docs.somewear.app/networking/install/mikrotik/"
updated: "2026-10-08"
requires:
  features: []
  organizationRole:
    - Admin
  workspaceRole: []
facets:
  hardware: []
  client:
    - tvpn:
        since: baseline
  satcom: []
---

This page covers the TVPN-specific parts of running TVPN as a container on a MikroTik router — [MikroTik’s own container docs](https://help.mikrotik.com/docs/spaces/ROS/pages/84901929/Container) cover the router-side setup (bridges, internet access) this page doesn’t. Tested on a MikroTik RB5009 running RouterOS 7.

## Set up the mount and config

Configure a mount inside the MikroTik console:

```bash
/container/mounts add name=tvpn-data src=disk1/tvpn dst=/var/lib/somewear/tvpn
```

Create a `config.toml` with at least:

```toml
[api]
key = "<the-api-key>"

# Log to stdout so mikrotik captures the output
[log]
stdout = true

# This is needed since RouterOS emits some rtnetlink messages
# which are non-standard and break parsing in the default mode
[interfaces]
lookup-strategy = "poll"
```

For `<the-api-key>`, [generate an API key](https://docs.somewear.app/developer/getting-started/authentication/#generate-an-api-key) from your Organization’s admin dashboard and [activate it for the Workspace](https://docs.somewear.app/developer/getting-started/authentication/#activate-the-key-for-a-workspace) this router should join.

Copy the config file to the router:

```bash
scp config.toml admin@<ip>:disk1/tvpn/config.toml
```

## Create the interface

```bash
/interface/veth/add name=veth-tvpn address=172.17.0.2/16 gateway=172.17.0.1
```

## Set up the container

TVPN runs as an arm64 Docker container: `us-docker.pkg.dev/somewear-souvla/tvpn/somewear-tvpn`.

1. Point the container environment at Somewear’s registry:

```bash
/container/config/set registry-url=https://us-docker.pkg.dev
```

2. Create the container. If you hit an error, see Troubleshooting below:

```bash
/container/add \
    name=somewear-tvpn \
    remote-image=somewear-souvla/tvpn/somewear-tvpn \
    interface=veth-tvpn \
    mounts=tvpn-data \
    start-on-boot=yes
```

3. Wait for the image to download (a couple of minutes). Run this until you see `import done`:

```bash
/container/log/print
```

4. Start the container:

```bash
/container/start somewear-tvpn
```

## Troubleshooting

**`failure: not allowed by device-mode`** — containers are disabled on this router. Enable them:

```bash
/system/device-mode/update container=yes
```

Reset the router, then re-run the container add command.

## Configuration

TVPN’s configuration file is at `disk1/tvpn/config.toml` on the router, mounted into the container at `/var/lib/somewear/tvpn/config.toml`. Edit it and restart TVPN (`/container/stop somewear-tvpn`, then `/container/start somewear-tvpn`) to apply changes. Run `tvpn -h` for the full list of settings.

Here’s an example:

```toml
[api]
key = "wk_1a2b3c4d5e6f:sk_9f8e7d6c5b4a3210"
# The API hostname. You only need to change this if you're using Somewear Self-Hosted
host = "api.somewear.co"

[log]
# The log level: trace, debug, info, warn, error, or off.
level = "info"
# The log style: compact or logfmt.
style = "logfmt"
# Whether to write to stdout.
stdout = true

[log.filesystem]
# The maximum size in MB to use for log files.
max-size-mb = 50
# The maximum number of log files to use.
max-files = 5

[tls]
# TLS cryptographic profile: PQ_HYBRID (default), CNSA_2_0, or CNSA_1_0.
profile = "PQ_HYBRID"
# TLS session rekey interval in seconds; sessions older than this trigger re-handshake.
# Defaults to 86400 (24 hours).
rekey-interval = 86400
# When true, allow loading TLS certificates from filesystem as a fallback
# when IPC cert bundles are unavailable. Defaults to false.
cert-files = false

[endpoint-id.rotation]
# Endpoint ID rotation interval in seconds.
interval = 86400

[traffic-policy]
# Traffic policy toggle, default is false. When true, the daemon attempts to load traffic-policy.toml.
enabled = false
# Path to traffic-policy.toml. Defaults to traffic-policy.toml in the same directory as config.toml.
# config-path = "/path/to/traffic-policy.toml"

[tun]
# The MTU to use on the TUN device. Defaults to 1320.
mtu = 1320

[interfaces]
# The list of interfaces which should not be used to route traffic through or receive traffic from.
disabled = ["eth1", "wlan2"]
# The list of interfaces that would be disabled by tvpn based on their name but
# we want to allow them to be used. Interfaces in here are still bound to the
# usual rules, like whether it's up, operational, etc.
allowed = ["br-lan"]
# Whether to allow virtual interfaces.
allow-virtual = false
# The interface lookup strategy to use: default or poll.
lookup-strategy = "default"

[gateway-routes]
# Whether to enable the use of literal routes. This is needed on every endpoint if you're using literal routes
allow-literal = true
# The list of literal gateway routes.
literal = ["192.168.10.0/24"]

# The list of virtual routes; each maps a physical range to a virtual range.
[[gateway-routes.virtual]]
physical = "192.168.1.0/24"
virtual = "100.127.0.0/24"

[[gateway-routes.virtual]]
physical = "10.0.2.0/24"
virtual = "100.127.1.0/24"

[relays]
# The list of relay servers to use.
servers = ["uswest1-0.relay.somewear.app", "uscentral1-0.relay.somewear.app", "useast4-0.relay.somewear.app"]
```

## Related

- [Configuring Gateway Routes](https://docs.somewear.app/networking/gateway-routes/) — expose devices behind a TVPN node to the rest of your Workspace
- [Quality of Service](https://docs.somewear.app/networking/qos/) — prioritize traffic across multiple network links
