Документация

Выбор того, что идёт через туннель

Необязательные рецепты RouterOS для роутера ForestVPN — отправлять через туннель одну группу приложений, отправлять всё или останавливать утечку трафика, когда туннель недоступен.

Обновлено 8 октября 2026 г.

Всё на этой странице необязательно. Роутер ForestVPN туннелирует собственный трафик сразу после подключения, и для этого ничего из описанного здесь не нужно. Здесь решается другая задача: какой трафик именно вашей локальной сети должен уходить через выходной сервер, и что происходит, когда выходной сервер недоступен.

Разделение обязанностей не меняется никогда. RouterOS решает, что попадает в туннель, контейнер туннелирует всё, что ему передано, а ваш аккаунт решает, где это выходит наружу. Поэтому всё это — обычная настройка RouterOS: метки mangle, таблица маршрутизации, правило файрвола — и ничего из этого не затрагивает сам контейнер.

Прочитайте это в первую очередь

От трёх фактов зависит, заработает ли хоть что-то из этого. Пропустить их — значит потерять вечер, который не вернуть.

Вставляйте эти правила на устройство, которое маршрутизирует вашу локальную сеть. Цепочка prerouting в RouterOS видит только трафик, который маршрутизирует само устройство. На точке доступа, стоящей ниже по цепочке за настоящим шлюзом, все правила ниже бездействуют — это подтверждено на cAP ax, у которого маршрут по умолчанию ведёт на роутер выше по цепочке: контейнер туннелировал безупречно, и трафик клиентов локальной сети до него вообще не доходил. Контейнер может жить на этой точке доступа; правила же должны быть на шлюзе.

Выходной сервер принимает только один исходный адрес на устройство — тот, что он сам выдал как аренду в оверлейной сети. Пакет с любым другим внутренним адресом источника отбрасывается, а не маршрутизируется, какими бы правильными ни были ваши правила. Что-то должно переписывать адреса вашей локальной сети на этот адрес аренды, и что именно — зависит от контейнера:

КонтейнерЧто нужно сделать
suquant/fvpn — приложение, управляемое аккаунтомНичего. Начиная с версии 0.3.9 контейнер маскирует всё, что вы в него перенаправляете, под собственный адрес аренды, и следует за этим адресом, когда он меняется. Команда установки включает это поведение.
suquant/fvpnq — сырой туннель из написанного вами .confДобавьте src-nat на Address в вашем .conf — тот же адрес, что вы указали в AllowedIPs на выходном сервере. Вы выбрали его сами, поэтому он стабилен, и правило может ссылаться на него по имени.

Работает контейнер старше версии 0.3.9? Заново выполните команду установки — иначе правила ниже будут прекрасно маркировать и маршрутизировать трафик, а выходной сервер будет отбрасывать каждый пакет, что выглядит как полная потеря интернета в локальной сети в момент добавления правила маршрутизации.

Fasttrack пропускает mangle. Заводской файрвол MikroTik помещает установленные соединения в fasttrack, и соединение, попавшее в fasttrack, больше никогда не проходит через цепочку mangle — поэтому ваши метки применяются только к первому пакету потока и ни к одному после него. В каждом рецепте ниже есть одно правило, которое не даёт помеченным соединениям попасть в fasttrack, и оно должно находиться выше правила fasttrack-connection.

И часть про IPv6, с которой эти правила вам не помогут

Всё здесь — IPv4. Если на вашем роутере работает IPv6, каждый выбранный ниже адрес назначения также доступен по v6 в обход туннеля, и никто вас об этом не предупредит. Если же вместо этого роутер объявляет себя IPv6-роутером, не имея маршрута по умолчанию для v6, клиенты локальной сети отправляют v6-трафик на него и не получают ничего в ответ — даже ошибки, потому что в RouterOS 7 нет недостижимого маршрута для v6, только тихий blackhole. Устройства без Happy Eyeballs — телевизоры, часы, всё, что делает обычное подключение по записи AAAA, — зависают на полный таймаут подключения на каждом v6-адресе назначения, что выглядит как «интернет иногда ломается» и списывается на Wi-Fi. Эта одна строка показывает, в какой вы ситуации:

# Does this router tell LAN clients it is their IPv6 router?
/ipv6/nd/print where ra-lifetime!=none
 
# Does it have somewhere to send their v6 traffic?
/ipv6/route/print where dst-address="::/0" and routing-table="main"

Если есть ответ на первый вопрос и нет на второй — это второй случай. Дайте IPv6 настоящий маршрут по умолчанию либо прекратите объявлять себя IPv6-роутером командой /ipv6/nd/set [find] ra-lifetime=none.

Шаг 1 — базовая настройка

Одинаково для всех трёх рецептов. Замените адрес контейнера 172.31.254.2 (это значение по умолчанию из установки; его показывает /interface/veth/print) на свой, а также замените префикс локальной сети 192.168.88.0/24 на свой.

Сначала проверьте /container/print detail. Значение remote-image должно быть 0.3.9 или новее, а cmd должно содержать --nat-lan. Оба параметра берутся из актуальной команды установки; в контейнере, установленном раньше, их нет, и симптом — полная потеря интернета в локальной сети в момент добавления правила маршрутизации на шаге 2.

# A routing table of its own, so nothing here can disturb your normal
# default route.
/routing/table add name=via-fvpn fib
 
# Where marked traffic goes: the container, on the address RouterOS itself
# gave it.
/ip/route add dst-address=0.0.0.0/0 gateway=172.31.254.2 \
    routing-table=via-fvpn comment="fvpn: traffic leaves via the container"
 
# Collapse the LAN to one source address on the way IN to the container. The
# exit never sees this one either -- the container masquerades again onto its
# own lease -- so this is about keeping your LAN's layout out of the
# container's connection table, not about being admitted.
/ip/firewall/nat add chain=srcnat out-interface=veth-fvpn action=masquerade \
    comment="fvpn: hide LAN addressing from the container"
 
# The tunnel costs 80 bytes of MTU. Without this, large TCP flows stall
# rather than fail, which presents as "the internet is broken on Tuesdays".
/ip/firewall/mangle add chain=forward action=change-mss new-mss=clamp-to-pmtu \
    protocol=tcp tcp-flags=syn connection-mark=via-fvpn \
    comment="fvpn: clamp MSS on tunnelled TCP"
 
# Fasttrack bypasses mangle, so marked connections have to be accepted
# before they reach it. This rule is inert if it ends up below the fasttrack
# rule -- check with /ip/firewall/filter/print that it did not.
/ip/firewall/filter add chain=forward action=accept connection-mark=via-fvpn \
    place-before=[find action=fasttrack-connection] \
    comment="fvpn: marked flows skip fasttrack"

Затем выберите один из следующих двух вариантов. Оба создают одну и ту же метку соединения via-fvpn, поэтому если вставить оба, они будут конфликтовать за один и тот же трафик.

Шаг 2a — по желанию: только звонки и мессенджеры

Настройка, которая месяцами работает на нашем собственном RB3011. Она делит задачу так же, как делится сам трафик: сигнализация — это несколько имён хостов вендоров, медиа — это диапазон портов на релеях, которые никто не публикует.

# Signalling, by hostname. A hostname in a RouterOS address list is not a
# static entry -- the router resolves it and keeps the answers fresh, which
# is the only form that survives a CDN moving under you.
/ip/firewall/address-list
add list=fvpn-via address=g.whatsapp.net      comment="fvpn: signalling"
add list=fvpn-via address=media.whatsapp.net  comment="fvpn: signalling"
add list=fvpn-via address=mmg.whatsapp.net    comment="fvpn: signalling"
add list=fvpn-via address=static.whatsapp.net comment="fvpn: signalling"
add list=fvpn-via address=web.whatsapp.com    comment="fvpn: signalling"
add list=fvpn-via address=api.telegram.org    comment="fvpn: signalling"
add list=fvpn-via address=core.telegram.org   comment="fvpn: signalling"
add list=fvpn-via address=web.telegram.org    comment="fvpn: signalling"
add list=fvpn-via address=chat.signal.org     comment="fvpn: signalling"
add list=fvpn-via address=storage.signal.org  comment="fvpn: signalling"
 
/ip/firewall/mangle
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    dst-address-list=fvpn-via \
    comment="fvpn: signalling by resolved vendor hostname"
 
# Media, by port -- the half an address list can never cover, because a call
# lands on whichever TURN relay the vendor picked that minute.
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    protocol=udp dst-port=3478-3481 \
    comment="fvpn: STUN/TURN media - calls in every major app"
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    protocol=tcp dst-port=3478-3481,5349,5350 \
    comment="fvpn: STUN/TURN over TCP and TLS"
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    protocol=udp dst-port=5060,5061 comment="fvpn: SIP"
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    protocol=tcp dst-port=5060,5061 comment="fvpn: SIP over TCP/TLS"
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    protocol=tcp dst-port=5222,5223 comment="fvpn: XMPP signalling"
 
# One routing decision for the whole connection. Marking the connection
# first and the route second -- rather than marking the route directly -- is
# what keeps a call that started on the tunnel on the tunnel.
add chain=prerouting action=mark-routing new-routing-mark=via-fvpn \
    passthrough=no src-address=192.168.88.0/24 connection-mark=via-fvpn \
    comment="fvpn: route marked connections via the exit"

Список хостов — это отправная точка, а не эталон. Вендоры добавляют и убирают их, никого не предупреждая. Проверьте /ip/firewall/mangle/print stats на предмет счётчиков, которые остаются на нуле, — это правило, которое ничего не совпадает, а не правило, тихо выполняющее свою работу.

Шаг 2b — по желанию: всё

/ip/firewall/mangle
# The container's own packets must never be marked, or its tunnel gets
# routed into itself. The install puts the container's interface in the LAN
# list, so the rule below WOULD match it. Substitute the container's
# address.
add chain=prerouting action=accept src-address=172.31.254.2 \
    comment="fvpn: never mark the container's own traffic"
 
# Everything from the LAN that is not addressed to this router.
# `dst-address-type=!local` is what keeps DNS, WebFig and the status page
# off the tunnel; `in-interface-list=LAN` rather than a source prefix keeps
# the rule correct when the LAN is renumbered.
add chain=prerouting action=mark-connection new-connection-mark=via-fvpn \
    in-interface-list=LAN dst-address-type=!local \
    comment="fvpn: everything from the LAN"
# `dst-address-type=!local` on this rule too, and it is not decoration. The
# install puts the container's veth in the LAN list, so replies coming back
# OUT of the container also match `in-interface-list=LAN`, and they still
# carry the connection mark. Mangle prerouting runs before dstnat, so at
# this moment their destination is still the router's own srcnat address --
# local. Without the test they would take the routing mark and be sent back
# into the container instead of on to the client that asked.
add chain=prerouting action=mark-routing new-routing-mark=via-fvpn \
    passthrough=no in-interface-list=LAN dst-address-type=!local \
    connection-mark=via-fvpn \
    comment="fvpn: route marked connections via the exit"

Прежде чем тестировать, посчитайте, что вы вставили. /ip/firewall/mangle/print должен показать все три этих правила. Если при вставке в терминал теряется продолжение одной из строк, у вас останутся правила маркировки, но не будет правила маршрутизации, а это выглядит в точности как «туннель игнорируется» — соединения несут connection-mark=via-fvpn, но таблицу никто не смотрит, и каждый пакет уходит через обычное соединение.

Отправляя всё, вы отправляете и DNS — в этом и смысл, но это значит, что резолвер выходного сервера отвечает вашей локальной сети. Прежде чем решить, что этот режим вам подходит, проверьте, что всё зависящее от локальных имён (принтер, NAS, router.lan) по-прежнему разрешается.

Шаг 3 — по желанию: блокировка трафика без VPN

У выборочной маршрутизации есть один режим отказа, который стоит закрыть: когда туннель останавливается, помеченный трафик может незаметно вернуться к отправке через обычное соединение. Эти три правила вместо этого его останавливают. Добавьте их после того рецепта, который вы выбрали.

Каждая команда в этом разделе была выполнена на RouterOS 7.24.1, прежде чем оказаться здесь записанной. Синтаксис отличается от RouterOS 6 в одном месте, отмеченном ниже.

# 1. The route to the container counts only while the container answers.
/ip/route/set [find routing-table=via-fvpn dst-address=0.0.0.0/0] \
    check-gateway=ping
 
# 2. When it stops counting, drop rather than fall back. The higher distance
#    keeps this route inactive for as long as the real one is up. `blackhole`
#    is a bare flag here, not `type=blackhole` -- RouterOS 7 has no `type`
#    property on a route at all, and rejects it with "bad parameter type".
/ip/route/add dst-address=0.0.0.0/0 blackhole distance=10 \
    routing-table=via-fvpn comment="fvpn: kill switch - no exit, no traffic"
 
# 3. The leak the first two cannot see: a container that is alive and
#    answering ping while its own tunnel is down forwards to its default
#    gateway, which is you. Traffic wearing the address the srcnat above gave
#    it must never reach the internet directly. Substitute your router's own
#    address on the container's /30 if you changed it.
/ip/firewall/filter/add chain=forward action=drop src-address=172.31.254.1 \
    out-interface-list=WAN \
    place-before=[find comment="fvpn: marked flows skip fasttrack"] \
    comment="fvpn: kill switch - overlay source must not leave over WAN"

Правило 3 должно находиться выше правила исключения из fasttrack из шага 1, иначе это правило пропустит трафик первым и до сброса дело не дойдёт. Здесь это делает place-before; проверьте с помощью /ip/firewall/filter/print.

Более строгий вариант: устройства, которым разрешено выходить в сеть только через туннель

Если на самом деле вы хотите сказать «у этого ноутбука нет интернета, если он не идёт через туннель», скажите это напрямую, а не выводите из состояния маршрутизации:

/ip/firewall/address-list/add list=fvpn-only address=192.168.88.50 \
    comment="fvpn: the work laptop"
/ip/firewall/filter/add chain=forward action=drop src-address-list=fvpn-only \
    out-interface-list=WAN \
    place-before=[find comment="fvpn: marked flows skip fasttrack"] \
    comment="fvpn: kill switch - these devices are tunnel-only"

Теперь это устройство выходит в интернет только через контейнер — или не выходит вовсе, что бы ни говорили таблицы маршрутизации в то или иное утро.

Проверка, что всё сработало

# A rule sitting at zero packets is a rule matching nothing.
/ip/firewall/mangle/print stats
/ip/route/print where routing-table=via-fvpn
# The fasttrack-exemption rule has to be above the fasttrack rule.
/ip/firewall/filter/print

С устройства в локальной сети откройте любую страницу «какой у меня IP». Она должна показывать страну выходного сервера для выбранного вами трафика и вашу собственную — для всего остального. Если она показывает вашу собственную страну для всего, обычная причина — первый факт на этой странице: правила стоят на устройстве, которое не маршрутизирует локальную сеть.

Отмена настроек

Каждая строка выше несёт комментарий, начинающийся с fvpn:, поэтому их удаление точное — и не затронет собственные объекты контейнера, которые установщик помечает комментарием forestvpn.

/ip/firewall/mangle/remove [find comment~"^fvpn:"]
/ip/firewall/filter/remove [find comment~"^fvpn:"]
/ip/firewall/nat/remove [find comment~"^fvpn:"]
/ip/firewall/address-list/remove [find comment~"^fvpn:"]
/ip/route/remove [find comment~"^fvpn:"]
/ip/address/remove [find comment~"^fvpn:"]
/routing/table/remove [find name="via-fvpn"]

Контейнер продолжает работать, сохраняет привязку к аккаунту и возвращается к туннелированию только собственного трафика. Если что-то ещё не так, см. устранение неполадок.

Назад к разделу «Помощь»

Русский
Спросите нас о чём угодно