Tiny OpenVPN client container

Hello, I’m impressed and very excited about the container release in RouterOS 7.5. For a long time I dream transfer my openvpn clients to the wifi-router. Enjoy simple guide if you want

On your code is present this, why?

ping -c 10 service. home. internal. net (without spaces on domain)

This call home?

Assuming I’m wrong, never use something that really exists on examples…

Hi service. home. internal. net is just an example of an intranet resource. If it ceases to be available, then the openvpn connection is re-created. When configuring, you must specify your resource

Why it was removed? I’m looking for something similar as Mikrotik OpenVPN as a client still does not support TLS auth

You could have waited a few more months before asking, so one would remember it better,
however it is written, just read.

However I recommend you to use wireguard which is natively supported, in a heartbeat,
instead of wasting your time with openvpn inside a container…

However I recommend you to use wireguard which is natively supported

If the remote server I’m connecting to had used Wireguard, I would surely use it. But it is about MT connecting as a client to a remote OpenVPN server, and I do not have any alternative methods available.

Hey, buddy. Hope you find this useful. This is copy of README from my github

Dockerfile

FROM alpine:3.16

RUN apk update && \
    apk upgrade && \
    apk add --no-cache openvpn iptables && \
    rm -rf /var/cache/apk

COPY ./entry.sh /root/
COPY ./config.ovpn /root/
COPY ./config.pass /root/
RUN chmod +x /root/entry.sh
ENTRYPOINT /root/entry.sh

entry.sh

#!/bin/sh
set -x

/usr/sbin/openvpn --config /root/config.ovpn &
until ip l sh tap0 >/dev/null 2>&1; do sleep 1; done
sysctl -w net.ipv4.ip_forward=1
/sbin/iptables -t nat -A POSTROUTING -o tap0 -j MASQUERADE
/sbin/iptables -A FORWARD -i tap0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
/sbin/iptables -A FORWARD -i eth0 -o tap0 -j ACCEPT

while sleep 50; do
  t=$(ping -c 10 service.home.internal.net | grep -o -E '[0-9]+ packets r' | grep -o -E '[0-9]+')
  if [ "$t" -eq 0 ]; then
    pkill -f openvpn
    /usr/sbin/openvpn --config /root/config.ovpn &
  fi
done

config.ovpn Yout configuration of OpenVPN
config.pass Certificate password

Description

Setup a OpenVPN client for access to your home network
Minimum system requirements

RouterOS 7.5 or newer
arm, arm64 or x86 cpu
10 MB disk space (internal NAND storage)

Usage

Setup container on RouterOS. See details here.

Replace config.ovpn and config.pass with your own files. Or configure client like you want

Replace service. home. internal .net in entry.sh for some host in your home network (for connectivity check). This used for restart connection if it’s down.

Build image:

docker buildx build  --no-cache --platform linux/arm/v7 -t ovpn-container .
docker save ovpn-container > ovpn-container.tar



arch 	router cpu
linux/arm/v7 	ARM
linux/arm64 	ARM64
linux/amd64 	x86

Upload ovpn-container.tar to your router

Setup containers network

/interface/bridge/add name=dockers
/interface/veth/add address=192.168.121.2/24 gateway=192.168.121.1 name=veth1
/interface/bridge/port/add bridge=dockers interface=veth1
/interface/list/member/add interface=dockers list=LAN
/ip/address/add address=192.168.121.1/24 interface=dockers network=192.168.121.0
/ip/firewall/nat/add action=masquerade chain=srcnat src-address-list=192.168.121.0/24

Setup routing

/routing/table/add disabled=no fib name=homeNetwork
/ip/route/add disabled=no distance=1 dst-address=172.16.0.0/12 gateway=192.168.121.2 \
    pref-src=0.0.0.0 routing-table=homeNetwork scope=30 suppress-hw-offload=no \
    target-scope=1
/routing/rule/add action=lookup disabled=no dst-address=172.16.0.0/12 table=homeNetwork

Create container

 /container/add file=ovpn-container.tar interface=veth1 dns=192.168.121.1 logging=yes
 /container/start 0

Done, now you can access all your services in 172.16.0.0/12 network

Hello, my friend. Thank you so much for the tutorial you provided; I really appreciate it. I have a few questions I hope you can help me with. I was able to run the container successfully, but it seems that my service provider does not support TAP mode, so I have to use TUN mode instead. While the connection is established in TUN mode, there is no network connectivity outside the container.

My question is: is it possible to set the dst field to 0.0.0.0/0 in the routing settings you mentioned, so that we can use mangle to specify that all devices should use this gateway?

Hello, if I check the container settings on regular linux (mint 22), everything is fine, the route is created, everything works.
When the same container is sent to microtik, I get an error from iptables

 /sbin/iptables -A FORWARD -i tap0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

. that failed to apply filters module.
I am using hap ac^2, RouterOS version 7.15stable.
Different versions of alpine linux did not help to fix the situation.
P.S. now it is not tap0 but tun0.

Can someone help me with this problem?

hello, can you send your github link,
or someone tell me how can use code, because I’m nob :smiley:, just I want use in my mikrotik router
please help me

I'm not sure if this is still relevant, but for my needs I created a small OpenVPN client container:

Features

  • Multi‑architecture – Supports linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6 – works on MikroTik ARM, ARM64, and x86 devices. Tested on hap be3 media, hap ac2, CHR.
  • Automatic updates – Weekly GitHub Actions workflow checks for new Alpine and OpenVPN releases.
  • Flexible authentication – Use environment variables (OVPN_USER/OVPN_PASS) or an auth.txt file (path configurable via OVPN_AUTH_FILE).
  • DNS control – Set custom DNS servers via OVPN_DNS_SERVERS (space, comma, or semicolon separated). The container overwrites /etc/resolv.conf and DNATs DNS requests to the first DNS server.
  • Healthcheck watchdog – Pings a host through tun0 and reboots the container on consecutive failures.
  • NAT & routing – Applies iptables MASQUERADE, MSS clamping, and forwarding.
  • Custom post‑up script – Execute /vpn/post-up.sh after all routes have been added (using OpenVPN's --route-up hook).
  • Small footprint – Built with OpenVPN's --enable-small and minimal runtime dependencies.
  • Config auto‑detection – Picks the first .ovpn file in /vpn if OVPN_CONFIG_NAME is not set.

Also, there is an instruction on how to run it on RouterOS and forward traffic through it.