Хочу поделиться опытом запуска серверов SoftEther VPN и ocserv (OpenConnect/AnyConnect) прямо на MikroTik. В RouterOS из коробки есть WireGuard, OpenVPN, SSTP, L2TP/IPsec и IKEv2, но нет сервера OpenConnect или SoftEther. Иногда нужен именно такой протокол: для клиентов Cisco Secure Client или для каскада с уже работающим сервером SoftEther.

Поднимать отдельную Linux‑машину ради пары VPN‑сервисов не хотелось. Начиная с RouterOS 7 в MikroTik есть поддержка контейнеров, совместимых с образами Docker Hub и Quay. Этим и воспользуемся.

Всё ниже проверено на MikroTik CHR 7.24.5 (x86_64) на KVM, 768 МБ памяти и 7 ГБ диска. На железных маршрутизаторах я не проверял, но, скорее всего, порядок тот же, только нужен образ под их архитектуру (arm/arm64) и внешний накопитель.

Краткое содержание статьи:

  • включение контейнеров и подготовка сети для них;

  • поднятие SoftEther VPN с SecureNAT или каскадом на другой сервер;

  • поднятие ocserv и настройка маршрутов для него;

  • грабли на которые наступил в процессе.

Итак, приступим.

Подготовка RouterOS

Для начала включаем пакет container. В Winbox: System → Packages → container → Enable → Apply Changes. Маршрутизатор уйдёт в перезагрузку.

Пакета мало: запуск контейнеров закрыт device‑mode. Разрешаем их:

/system/device-mode/update container=yes

Изменение нужно подтвердить физически в течение 5 минут. На железе это кнопка reset, на CHR — выключение и включение из панели провайдера: Power off, затем Power on. /system reboot и кнопка Reboot в панели не подойдут.

Проверяем:

/system/device-mode/print

Должно быть container: yes. Если там no и attempt-count: 1, попытка была, но не подтвердилась. Повторяем.

Далее готовим сеть. Каждому контейнеру нужен свой veth‑интерфейс, а все veth мы соберём в один bridge. Адреса берём из свободной подсети, у меня это 10.10.4.0/24:

/interface/bridge add name=br-containers
/ip/address add address=10.10.4.1/24 interface=br-containers
/ip/firewall/nat add chain=srcnat src-address=10.10.4.0/24 action=masquerade

/interface/veth add name=veth-softether address=10.10.4.2/24 gateway=10.10.4.1
/interface/veth add name=veth-ocserv address=10.10.4.3/24 gateway=10.10.4.1
/interface/bridge/port add bridge=br-containers interface=veth-softether
/interface/bridge/port add bridge=br-containers interface=veth-ocserv

RouterOS сам назначит контейнеру адрес и шлюз из настроек veth: внутри он станет eth0. DHCP здесь не участвует.

Внешний трафик попадает в контейнеры только через dst‑nat, а наружу они выходят через masquerade роутера. Осталось указать реестр и папку для распаковки образов:

/container/config set registry-url=https://registry-1.docker.io tmpdir=pull

SoftEther VPN

Используем официальный образ softethervpn/vpnserver. У него есть нюанс: тег stable — это ветка 4.x, и настройки она хранит в /mnt. Ветка 5.x (теги вида 5.2.5188) хранит их в /var/lib/softether. Путь в mount должен соответствовать тегу, иначе пароли и пользователи будут пропадать при пересоздании контейнера. Я брал stable.

Папку для настроек заранее не создаём: если её нет, RouterOS заполнит её содержимым образа. Создаём mount и контейнер:

/container/mounts/add list=SE_DATA src=softether/data dst=/mnt
/container add remote-image=softethervpn/vpnserver:stable interface=veth-softether root-dir=softether/root mountlists=SE_DATA name=softether logging=yes start-on-boot=yes

root-dir — это файловая система самого контейнера, она заменяется при обновлении образа. Настройки живут отдельно, в mount.

Ждём, пока образ скачается (status=stopped в /container print), и запускаем:

/container start softether

В логах должна появиться строка started /usr/local/bin/vpnserver execsvc. Ошибка dmesg: klogctl: Operation not permitted говорит, что сервер пытается прочитать журнал ядра, а контейнеру это запрещено.

После первого запуска пароля администратора нет. Задаём пароль до того, как откроем порт наружу:

/container shell softether
vpncmd localhost /SERVER /CMD ServerPasswordSet
ls -la /mnt
exit

В /mnt должен появиться конфиг файл vpn_server.config. Затем пробрасываем порт. Берём 444 для примера:

/ip/firewall/nat add chain=dstnat in-interface-list=WAN protocol=tcp dst-port=444 action=dst-nat to-addresses=10.10.4.2 to-ports=443

Дальше удобнее работать через SoftEther VPN Server Manager: подключаемся к IP:444 с паролем администратора и создаём пользователей в хабе (Manage Users → New). Как клиенты получат IP‑адреса и выход в интернет, зависит от режима.

Режим SecureNAT

SecureNAT — встроенный в хаб DHCP и NAT, который работает полностью в userspace. TUN, iptables и дополнительные права ему не нужны, поэтому в контейнере RouterOS он работает сразу. Включаем в Manage Virtual Hub → Virtual NAT and Virtual DHCP Server (SecureNAT) → Enable SecureNAT. Клиенты получат адреса из 192.168.30.0/24, а DNS будет пересылаться в DNS маршрутизатора.

Каскад на другой сервер SoftEther

У меня уже был сервер SoftEther на Linux с Local Bridge на TAP‑интерфейс и dnsmasq в роли DHCP. Cascade Connection соединяет хабы SoftEther на уровне L2 в одну логическую сеть.

Порядок действий:

  1. На удалённом сервере SoftEther создаём отдельного пользователя для каскада.

  2. На SoftEther в MikroTik выключаем SecureNAT в хабе. Иначе его DHCP через каскад начнёт раздавать адреса устройствам удалённой сети.

  3. Manage Cascade Connections → New: адрес и порт удалённого сервера, имя его хаба, пользователь из первого шага.

  4. Нажимаем Online. Статус должен смениться на Online (Established).

Важно: каскад настраиваем только в одну сторону, иначе каскад с обеих сторон даст петлю.

ocserv

С ocserv сложнее: ему нужны TUN, ip_forward и iptables. В Docker их даёт cap_add: NET_ADMIN, а в RouterOS такого параметра нет. На практике контейнер RouterOS спокойно создаёт TUN и меняет сетевые настройки внутри своего сетевого пространства. Режим privileged=yes мне не понадобился.

Берём образ aminvakil/ocserv. Актуальные версии лежат на Quay: на Docker Hub есть образ с таким же именем, но он не обновлялся с 2 020 года.

Запуск

Сеть для VPN‑клиентов задаём переменными окружения. У меня это 10.10.5.0/24. Всю папку /etc/ocserv монтируем наружу: там конфиг, сертификаты и пользователи.

/container/envs/add list=OC_ENV key=OC_IPV4_NETWORK value=10.10.5.0
/container/envs/add list=OC_ENV key=OC_IPV4_NETMASK value=255.255.255.0
/container/mounts/add list=OC_DATA src=ocserv/conf dst=/etc/ocserv

Реестр в RouterOS задаётся одной общей настройкой на все контейнеры. Временно переключаем его на Quay и создаём контейнер:

/container/config set registry-url=https://quay.io
/container add remote-image=aminvakil/ocserv:latest interface=veth-ocserv root-dir=ocserv/root envlist=OC_ENV mountlists=OC_DATA name=ocserv logging=yes start-on-boot=yes

Когда образ скачался, возвращаем Docker Hub, иначе SoftEther потом не обновится. Запускаем:

/container/config set registry-url=https://registry-1.docker.io
/container start ocserv

При первом запуске образ сам создаёт самоподписанный сертификат и тестового пользователя test с паролем test. Создаём своего пользователя и не забываем удалить тестового:

/container shell ocserv
ocpasswd -c /etc/ocserv/ocpasswd user1
ocpasswd -c /etc/ocserv/ocpasswd -d test
exit

Пробрасываем порт. ocserv работает по TCP и по UDP (DTLS), поэтому нужны оба протокола:

/ip/firewall/nat add chain=dstnat in-interface-list=WAN protocol=tcp dst-port=8443 action=dst-nat to-addresses=10.10.4.3 to-ports=443
/ip/firewall/nat add chain=dstnat in-interface-list=WAN protocol=udp dst-port=8443 action=dst-nat to-addresses=10.10.4.3 to-ports=443

Маршрутизация и NAT

RouterOS должен знать, что сеть клиентов ocserv находится за контейнером. Добавляем маршрут и masquerade:

/ip/route add dst-address=10.10.5.0/24 gateway=10.10.4.3
/ip/firewall/nat add chain=srcnat src-address=10.10.5.0/24 out-interface-list=WAN action=masquerade

Есть тонкий момент. Скрипт образа при каждом старте добавляет свой MASQUERADE для сети клиентов. Тогда RouterOS видит трафик с адреса контейнера 10.10.4.3, а не с адресов клиентов. Для интернета это не важно, но правила firewall и маршрутизации по адресам клиентов срабатывать не будут.

Правило строится по переменной OC_IPV4_NETWORK, а сам ocserv берёт сеть из уже созданного ocserv.conf. Поэтому после первого запуска перенаправляем правило на документационную сеть TEST‑NET-1, пакетов из которой не бывает:

/container/envs/set [find list=OC_ENV key=OC_IPV4_NETWORK] value=192.0.2.0
/container stop ocserv
/container start ocserv

Если когда‑нибудь удалите ocserv.conf, сначала верните переменную на 10.10.5.0. Иначе клиенты начнут получать адреса 192.0.2.x.

Доступ к внутренним сетям

Следующая проблема: с клиента не открывалась внутренняя сеть 172.31.0.0/16, хотя маршрутизация на RouterOS была в порядке. Образ добавляет в конфиг исключения для всех частных сетей, чтобы у клиентов не пропадал доступ к домашним сетям:

route = default
no-route = 192.168.0.0/255.255.0.0
no-route = 10.0.0.0/255.0.0.0
no-route = 172.16.0.0/255.240.0.0
no-route = 127.0.0.0/255.0.0.0

no-route говорит клиенту не отправлять этот трафик в VPN. Убираем нужное исключение и добавляем явный маршрут:

/container shell ocserv
sed -i '/^no-route = 172.16.0.0\/255.240.0.0/d' /etc/ocserv/ocserv.conf
echo "route = 172.31.0.0/255.255.0.0" >> /etc/ocserv/ocserv.conf
exit
/container stop ocserv
/container start ocserv

Маршруты передаются клиенту только при подключении, поэтому переподключаемся и проверяем.

Грабли

Собрал в одном месте всё, что отняло время.

Симптом

Причина

Решение

device-mode остаётся container: no

мягкая перезагрузка не считается подтверждением

Power off и Power on из панели VPS в течение 5 минут

Winbox не сохраняет контейнер: Error in Shm Size

Winbox не читает своё же значение по умолчанию 64.0 MiB

стереть поле или создавать контейнер из терминала

Образ не скачивается

по умолчанию реестр — lscr.io

задать registry-url в /container/config

После ocserv не обновляется SoftEther

registry-url один на все контейнеры и остался quay.io

вернуть Docker Hub после скачивания

Настройки SoftEther сбрасываются

mount не совпадает с веткой образа

stable → /mnt, 5.x → /var/lib/softether

Ошибки iptables про nf_tables в логе ocserv

ядро RouterOS может не поддерживать nft‑вариант iptables

NAT делает RouterOS, самому ocserv iptables не нужен

Правила по адресам клиентов ocserv не срабатывают

MASQUERADE внутри контейнера подменяет адрес клиента

OC_IPV4_NETWORK=192.0.2.0 после первого запуска

С клиента не видно внутреннюю сеть

no-route для частных сетей в ocserv.conf

удалить исключение и добавить route

Режим privileged=yes в RouterOS 7.24 есть, но включать его ради VPN не стоит. Privileged‑контейнер может менять firewall и форматировать диски маршрутизатора, а в том, что описано выше, он не нужен.

Итоги

Оба VPN‑сервера работают на MikroTik без privileged и без отдельной Linux‑машины. SoftEther заводится проще, ocserv требует больше внимания к маршрутизации.

SoftEther VPN

ocserv

Образ

softethervpn/vpnserver:stable (Docker Hub)

aminvakil/ocserv:latest (Quay)

Настройки

/mnt

/etc/ocserv

Клиенты

SoftEther Client, OpenVPN, SSTP, L2TP/IPsec

Cisco Secure Client, OpenConnect

Адреса клиентам

SecureNAT или DHCP удалённой стороны через каскад

пул из ocserv.conf, маршрут на RouterOS

Управление

Server Manager (GUI) и vpncmd

ocpasswd и правка ocserv.conf

Порты у меня

444/tcp

8443/tcp и 8443/udp

Если нужен просто надёжный VPN, сначала стоит посмотреть на встроенные в RouterOS WireGuard или OpenVPN. Контейнеры имеют смысл, когда нужен конкретный протокол или совместимость с уже работающей инфраструктурой.

Источники:

Комментарии (1)


  1. MoscowStyle
    20.10.2026 19:30

    Amnezia отлично крутится с лета на микроте