🔥 Не хотите сами поднимать и настраивать ноды? Возьмите VPN, где всё уже настроено. Сервис wpn.me работает на vnm: полная поддержка Amnezia 3.1 и 2.0, а также протоколов VLESS, Hysteria2 и TrustTunnel, устойчивых к блокировкам. Работает даже в условиях «белых списков». 👉 Попробовать wpn.me
Базовый слой VPN-ноды: одна программа, которая на уровне ядра решает, куда уходит трафик сервера и кого к нему не пускать, — независимо от того, какие VPN-сервисы на нём крутятся (Xray/Remnawave, AmneziaWG, TrustTunnel и что угодно ещё).
VPN-сервисы на ноде ничего не знают друг о друге, и правила «куда можно ходить» у каждого свои — или их нет вовсе. Типичная дыра: в профиле Xray российские сайты заблокированы, а клиенты AmneziaWG ходят на них напрямую с IP ноды. vnm закрывает это один раз, для всего сервера:
- Политика назначений (egress). Списки адресов и доменов из конфига → действие: отправить через выход (например, Cloudflare WARP), заблокировать или выпустить напрямую. Работает для любого трафика: процессов самой ноды, контейнеров и клиентов туннелей.
- Выход WARP. Своя регистрация Cloudflare WARP на каждой ноде, проверка здоровья, автоматический перевыпуск, если выход умер.
- Fail-closed. Если выход недоступен, трафик по его правилу отклоняется, а не уходит напрямую. Смерть агента ничего не открывает: правила остаются в ядре.
- Guard. Блок входящих соединений от адресов из блок-листов (сканеры, подсети госорганизаций) — до ufw, Docker и всех сервисов.
- Блок торрентов (p2p). Строгие сигнатуры BitTorrent в ядре и вердикты nDPI: загрузка и раздача не идут ни от прокси, ни от клиентов туннелей, рой не достучится до ноды снаружи.
- Свой DNS-резолвер для доменных списков: адреса доменов попадают в наборы ядра в момент ответа, так что правило срабатывает, даже если сайт живёт не на «своих» IP.
- Базовая настройка сервера (по желанию): вход только по ключу, fail2ban, сетевые sysctl, swap.
vnm не знает смысла списков: «ru_ip» или «corp» — это только имена в конфиге. Что куда
отправлять, целиком задаётся в /etc/vnm/config.yaml.
┌──────────────── vnm-agent ─────────────────┐
config.yaml ───▶ │ списки (скачать/проверить) → план → nftables│──▶ ядро: таблица inet vnm,
│ здоровье выходов, перевыпуск, метрики │ ip rule, маршруты выходов
└─────────────────────────────────────────────┘
vnm-dns — резолвер: ответы по доменам списков кладёт в наборы nftables
vnm-boot — при загрузке восстанавливает последнее рабочее состояние с диска, до подъёма сети
vnm (CLI) — установка, переключение режимов, статус, диагностика
- Решение принимается один раз, на первом пакете нового соединения, и запоминается в метке conntrack. Ответы клиентам никогда не перенаправляются.
- Вся политика живёт в одной таблице
inet vnm, которой владеет агент. Чужие таблицы (ufw, Docker, iptables других сервисов) vnm не читает и не трогает. - Агент раз в несколько секунд сверяет ядро с планом и возвращает всё, что изменили руками (это считается дрейфом и видно в статусе и метриках).
| Режим | Что происходит |
|---|---|
observe |
всё классифицируется и считается, трафик не меняется — «что было бы» |
enforce |
рабочий режим |
off |
политика снята |
Выход egress из enforce (в observe или off) выпускает трафик списков с IP ноды, поэтому
требует явного -allow-leak — случайно открыть утечку командой нельзя. Egress и guard
переключаются независимо. Любое переключение можно сделать временным:
-auto-rollback 5m — если за 5 минут его не подтвердить из новой SSH-сессии, vnm сам
вернёт прежний режим. Так же устроена настройка SSH в base: потеряли доступ — через 5 минут
всё откатится.
Хостеры закрывают серверы за раздачу торрентов, а блок bittorrent в Xray ловит только
открытое рукопожатие. vnm режет BitTorrent на уровне сети, для всех сервисов ноды сразу.
Подробно — docs/vpn-node-manager-p2p-tz.md.
Два слоя:
- Сигнатуры в ядре — строгое совпадение полей заголовка, без наивных префиксов (те
ловят TURN/WebRTC):
utp_syn— uTP ST_SYN: заголовок uTP открыт даже при шифровании MSE, и без SYN соединение с пиром не возникает;dht— запросы и ответы DHT (d1:ad2:id20:/d1:rd2:id20:);udp_tracker— connect к UDP-трекеру (magic0x41727101980);bt_handshake— открытое рукопожатие\x13BitTorrent protocolпо TCP.
- nDPId — отдельный демон (
vnm-ndpid) с libnDPI. Пассивно читает копии пакетов на всех интерфейсах (кроме DNS и 80/443/853) и сообщает агенту вердикты по потокам. Ловит то, чего не видно в одном пакете: шифрованный BitTorrent, uTP посреди потока. Агент кладёт пира из вердикта в наборp2p_peersнаpeer_ttl— дальше с ним не говорит никто на ноде. Если клиент туннеля заwindowобращается кthresholdразным пирам, он сам попадает вp2p_banнаttl.
Где проверяется (таблица inet vnm, приоритет −155: после guard, до egress — отрезанный
поток не тратит WARP):
| Цепочка | Хук | Что режет |
|---|---|---|
p2p_local |
output | исходящее процессов ноды (прокси) |
p2p_tunnel → p2p |
prerouting | исходящее клиентов туннелей (AmneziaWG и т.п.) |
p2p_tunnel → p2p_in |
prerouting, с аплинков | входящее от пиров: UDP прокси принимает пакеты от любого адреса, и рой сам стучится в порт, который прокси открыл клиенту |
p2p_banned |
prerouting | всё (или всё, кроме DNS и веба) от забаненного клиента туннеля |
Никогда не трогаются: ответы на соединения, адреса из exempt, DNS и порты 80/443. Наборы
пиров и банов переживают замену таблицы и перезапуск агента. Пользователю прокси бан не
грозит — у ноды нет его адреса: режутся пиры и пакеты торрента, остальной VPN у него работает.
Включение:
# nDPId в комплект не входит (GPL-3.0, отдельный бинарник): nDPId 1.7.0 + libnDPI 6.1,
# собранный статически, кладётся сюда; без него работает только слой сигнатур
scp nDPId root@NODE:/usr/local/lib/vnm/nDPId
# в /etc/vnm/config.yaml (полный пример — configs/vnm.yaml):
# p2p:
# mode: off
# signatures: [utp_syn, dht, udp_tracker, bt_handshake]
# ndpi: {}
ssh root@NODE 'systemctl enable --now vnm-ndpid'
ssh root@NODE 'vnm p2p observe -auto-rollback 5m' # считать, ничего не резать
ssh root@NODE 'vnm p2p confirm'
ssh root@NODE 'vnm status | grep ^p2p' # что было бы отрезано
ssh root@NODE 'vnm p2p enforce -auto-rollback 5m' # проверить сервисы, затем confirmvnm status показывает счётчики сигнатур, работает ли nDPId, сколько найдено потоков,
отвергнуто пиров и забанено клиентов; journalctl -u vnm-agent | grep "p2p peer" — каждый
вердикт с пиром.
| Что | Где на ноде |
|---|---|
Бинарник vnm (статический, CLI + агент + резолвер) |
/usr/local/bin/vnm |
| Конфиг политики | /etc/vnm/config.yaml (при установке кладётся configs/vnm.yaml, если файла нет) |
Юниты vnm-agent, vnm-boot, vnm-dns, vnm-ndpid |
/etc/systemd/system/ (шаблоны в init/) |
| nDPId для p2p (не входит в репозиторий, кладётся отдельно) | /usr/local/lib/vnm/nDPId |
| Выход WARP: аккаунт и конфиг | /etc/vnm/exits/warp/ (права 600) |
wgcf (пин версии и sha256) |
/usr/local/lib/vnm/wgcf |
| Состояние агента, кеши списков, бэкапы миграции | /var/lib/vnm/ |
| Метрики для node_exporter (textfile) | /var/lib/node_exporter/textfile_collector/vnm.prom |
Установщик сам ставит нужные пакеты (nftables, fail2ban для base) и создаёт системного
пользователей vnm-dns для резолвера и vnm-ndpid для nDPId.
- Ubuntu 22.04 / 24.04 / 26.04, Debian 12 / 13 или AlmaLinux 9 / 10, архитектура amd64. На других ОС установщик отказывает, ничего не меняя (Ubuntu 20.04 не поддерживается: старый nftables).
- root, systemd, ядро с WireGuard (для выхода WARP).
- Хотя бы один SSH-ключ в
authorized_keysroot, если ставится base (без ключа base откажет, чтобы не отрезать доступ). - Исходящий доступ к GitHub (списки geo) и к Cloudflare (регистрация WARP).
make build # bin/vnm, статический бинарник, версия = git describe
make check # fmt + vet + тесты — обязательно перед выкаткой на ноду
make test-short # только юнит-тесты, без network namespaceПолный make test включает стенд test/flowstand — настоящие правила в непривилегированных
network namespace (нужны unshare и nft, без них стенд пропускается).
# 1. Бинарник и конфиг
scp bin/vnm root@NODE:/usr/local/bin/vnm
ssh root@NODE 'chmod 755 /usr/local/bin/vnm && mkdir -p /etc/vnm'
scp config.yaml root@NODE:/etc/vnm/config.yaml # или без него — встанет configs/vnm.yaml
# Перед установкой впишите в exempt адреса, которые управляют нодой (панель, мониторинг):
# в configs/vnm.yaml там стоит документационный 203.0.113.10 — он никого не освобождает.
# 2. Установка: base + WARP + юниты. Режим берётся из конфига (начинайте с observe).
ssh root@NODE 'vnm install'
# -skip-base не трогать SSH, fail2ban, sysctl и swap
# -license KEY сразу применить ключ WARP+
# -trust CIDR,… адреса, которые fail2ban никогда не банит
# 3. Подтвердить SSH-настройку base — ИЗ НОВОЙ SSH-сессии, в течение 5 минут
ssh root@NODE 'vnm base confirm'
# 4. Проверить
ssh root@NODE 'vnm status; vnm doctor'
ssh root@NODE 'vnm test ya.ru; vnm test 1.1.1.1' # что нода делает с назначениемssh root@NODE 'vnm egress enforce -auto-rollback 5m'
# проверка: трафик по правилу идёт через выход, остальной — с IP ноды, сервисы живы
ssh root@NODE 'curl -s https://nplus1.ru/cdn-cgi/trace | grep warp' # warp=on
ssh root@NODE 'vnm egress confirm' # из новой сессии
ssh root@NODE 'vnm guard enforce -auto-rollback 5m'
# проверка: SSH, порты сервисов, связь с панелью
ssh root@NODE 'vnm guard confirm' # из новой сессииНе подтвердили — через 5 минут режим вернётся сам. Передумали раньше —
vnm egress rollback / vnm guard rollback.
Установщик находит ручной WARP (wg-quick@warp, свои ip rule на метку 0xca6c, wtm),
сохраняет его в /var/lib/vnm/migration/<дата>/, сносит и регистрирует свой. Правило, которое
он не может однозначно отнести к старому WARP, — остановка с описанием, решение за оператором.
На время замены (1–2 минуты) трафик по правилам выхода отклоняется, остальной не затрагивается.
Разделы /etc/vnm/config.yaml (полный пример с комментариями — configs/vnm.yaml):
| Раздел | Что задаёт |
|---|---|
mode |
режим egress: observe / enforce / off |
geo |
откуда брать geoip.dat / geosite.dat для списков вида geoip:…, geosite:… |
dns |
порт резолвера и вышестоящие DNS |
exits |
выходы: интерфейс, конфиг, запасные endpoints, проверка здоровья, команда перевыпуска |
lists |
списки: ip (geoip, url:, file:), domain, suffix, extra_cidr, границы размера, частота обновления |
policy |
правила по порядку, первое совпадение побеждает: lists → action (exit:<имя>, block, direct) + fallback на случай мёртвого выхода |
guard |
режим и правила блока входящих: lists → drop/reject, log |
p2p |
блок торрентов: режим, сигнатуры, ndpi (вердикты nDPId), ban (бан клиентов туннелей по «рою») |
exempt |
адреса, которые не трогают ни политика, ни guard, ни p2p (панель, управление) |
Пример правила:
policy:
- lists: [ru_ip, ru_domain, ru_suffix]
action: exit:warp
fallback: blockКонфиг читается строго: неизвестное поле — ошибка, и в силе остаётся последний валидный. Поэтому при обновлении сначала выкатывается новый бинарник, потом конфиг с новыми полями.
| Команда | Что делает |
|---|---|
vnm install [-skip-base] [-license KEY] [-trust …] |
полная установка ноды |
vnm base apply / vnm base confirm |
базовая настройка / подтвердить SSH-изменения |
vnm warp install / plus KEY / reissue |
регистрация WARP / ключ WARP+ / новая регистрация |
vnm egress observe|enforce|off [-allow-leak] [-auto-rollback 5m] |
режим политики назначений |
vnm guard observe|enforce|off [-auto-rollback 5m] |
режим guard |
vnm p2p observe|enforce|off [-auto-rollback 5m] |
режим блока торрентов |
vnm egress|guard|p2p confirm|rollback |
оставить или откатить временное переключение |
vnm status |
что агент увидел на последнем проходе: режимы, выходы, списки, счётчики, ошибки |
vnm test IP|DOMAIN |
как нода поступит с этим назначением |
vnm doctor |
сквозная проверка ноды |
vnm lists update |
скачать списки сейчас |
vnm agent / vnm boot / vnm dns serve |
то, что запускают юниты |
vnm version |
версия сборки |
Агент пишет файл в формате Prometheus для textfile-коллектора node_exporter. Главное:
vnm_exit_healthy,vnm_exit_alert— жив ли выход и не мёртв ли он дольше 15 минут;vnm_policy_applied,vnm_drift_total,vnm_apply_errors_total— стоит ли политика в ядре;vnm_connections_total— сколько соединений классифицировано каждым правилом;vnm_guard_refused_total{list}— сколько отбил guard (в observe — «отбил бы»);vnm_list_entries,vnm_list_age_seconds,vnm_list_failed— состояние списков;vnm_resolver_up— работает ли резолвер;vnm_p2p_mode,vnm_p2p_refused_total{signature}— режим и что отрезали сигнатуры;vnm_p2p_ndpi_up,vnm_p2p_detections_total,vnm_p2p_peers_total,vnm_p2p_bans_total— nDPId пишет, сколько найдено потоков, отвергнуто пиров, забанено клиентов.
node_exporter в комплект не входит: чтобы метрики собирались, его нужно поставить на ноду отдельно.
- Монолитное ядро без
modprobe(образы некоторых хостеров): base падает на шаге sysctl — ставить с-skip-base, сетевые sysctl задать вручную. Там же у nft нет именованных счётчиков: политика работает, ноvnm statusне покажет счётчики. - ufw / firewalld: установщик открывает порт резолвера (5353) и кладёт интерфейс выхода
в зону firewalld, если фаервол уже включён. Включили ufw после vnm — откройте 5353 сами
(
vnm doctorэто покажет). - IPv6: выходы только IPv4. Резолвер отдаёт домены списков с выходом без AAAA, а литеральные IPv6-адреса из таких списков блокируются.
docs/vpn-node-manager-tz.md— основное ТЗ: инварианты, политика, выходы, агент, режимы.docs/vpn-node-manager-installer.md— установщик: base и WARP, миграция со старого WARP.docs/vpn-node-manager-dns-tz.md— резолвер доменных списков.docs/vpn-node-manager-guard-tz.md— guard.docs/vpn-node-manager-p2p-tz.md— блок торрентов: сигнатуры, nDPId, бан клиентов.docs/vpn-node-manager-tests.md— приёмочные тесты.docs/vpn-node-manager-logging-tz.md— журнал событий (в разработке).