Автоматический деплой VPN-ноды на базе Remnawave + Xray-core за одну команду
VLESS · Reality · steal_oneself · транспорт TCP/Vision, XHTTP или оба сразу
Возможности · Быстрый старт · Как это работает · Настройка панели · Обновление · FAQ
routerus — интерактивный bash-скрипт, который на чистой Ubuntu 24.04
разворачивает готовую к работе VPN-ноду для Remnawave Panel:
хардит систему, поднимает Xray-core с
VLESS + Reality, маскирует ноду под легитимный сайт и печатает готовый JSON для
вставки в панель. Одна нода — один домен.
Скрипт идемпотентен: повторный запуск не ломает уже настроенную ноду, а на
живой ноде пропускает apt upgrade, чтобы не оборвать трафик.
- VLESS + Reality — TLS-маскировка без собственного сертификата; DPI и пробберы видят легитимный TLS-хендшейк.
- Три режима транспорта — выбор цифрой
1/2/3при запуске (Enter =1):1tcp(по умолчанию) — RAW +xtls-rprx-vision, полная совместимость с любым клиентом, включая podkop/Nikki на mihomo;2xhttp—mode=packet-up: дробит upload под API-запросы, устойчив к поведенческому DPI на мобильных сетях РФ;3both— оба inbound на одной ноде (tcp:443+xhttp:<port>) с общимprivateKey; подписка отдаёт обе ссылки, podkop берёт tcp.
- steal_oneself — Reality
destуказывает на собственный nginx на том же сервере: SNI резолвится на наш IP → настоящий сайт → всё легитимно. - Фейковый сайт — генератор бизнес-лендинга, детерминированный от хэша домена (на ре-запуске не меняется — фингерпринт стабилен).
- Хардинг из коробки — SSH key-only на нестандартном порту с замаскированным
ssh.socket, fail2ban, sysctl (BBR, TCP-буферы, SYN-flood protection), UFW, автообновления безопасности. - Docker из подписанного репозитория — установка через официальный apt-репо
с GPG-проверкой пакетов, а не
curl … | sh; заодно гарантируетdocker composev2. - Безопасность секретов — приватный ключ Reality не попадает в лог (Config
Profile пишется в
config-profile.json600и на терминал); лог,.envиkeys.txtс правами600, фейк-сайт644(иначе nginx отдал бы 403). - Zero-downtime SSL — выпуск и продление через webroot, nginx не гасится; renewal-hook пересоздаёт контейнер ноды, чтобы Xray подхватил новый сертификат.
- Эксплуатация — watchdog контейнера, автообновление geo-списков с валидацией целостности, ротация docker-логов, опциональный агент Beszel.
| Компонент | Версия / условие |
|---|---|
| ОС | чистая Ubuntu 24.04+ с выделенным IPv4 |
| Порт 443 | свободен до установки (Xray слушает напрямую) |
| Домен | A-запись указывает на IP сервера |
| Remnawave | Panel 2.8.0+ |
| Node / Xray | Node 2.8.0+ (Xray-core 26.6.27 в образе) |
| Права | root на время установки |
Купи домен (.ru от 129 ₽/год) и настрой DNS A-запись на IP сервера.
ssh root@IP_СЕРВЕРА
bash <(wget -qO- https://raw.githubusercontent.com/anfixit/routerus/main/deploy-remnanode.sh)Скрипт спросит: домен, публичный SSH-ключ, имя ноды, транспорт.
Для ключа он печатает команды получения .pub под macOS/Linux
(cat ~/.ssh/id_ed25519.pub) и Windows
(Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub в PowerShell,
type %USERPROFILE%\.ssh\id_ed25519.pub в cmd). Транспорт выбирается цифрой
1/2/3 (Enter = 1/tcp); для both дополнительно спрашивается порт xhttp.
Опциональные переменные окружения:
# пин образа ноды (по умолчанию remnawave/node:latest)
REMNANODE_IMAGE=remnawave/node:2.8.0 bash deploy.sh
# пин образа для генерации ключей (по умолчанию :latest)
XRAY_KEYGEN_IMAGE=ghcr.io/xtls/xray-core:26.6.27 bash deploy.sh
# email для Let's Encrypt (по умолчанию регистрация без email)
CERTBOT_EMAIL=you@example.com bash deploy.shСкрипт печатает готовый JSON и пошаговый чек-лист (см.
ниже). После ввода SECRET_KEY из панели
контейнер поднимается автоматически.
ssh -p 2810 admin@IP_СЕРВЕРА # из НОВОГО терминала — доступ жив?
# нода в панели зелёная? клиент → обнови подписку → пинг есть?Клиент (Happ / v2rayNG / podkop-Nikki на mihomo)
│
▼
Xray :443 (VLESS + Reality + TCP/Vision | XHTTP) [+ xhttp:<port> в режиме both]
│
├── Reality-клиент ──────────► VPN-туннель ──► интернет
│
└── Не-Reality (DPI / проббер)
│
▼
nginx :8443 (настоящий сайт с SSL) ← steal_oneself
Reality проверяет клиента по x25519-ключу и shortId. Легитимный трафик уходит в туннель; всё остальное (DPI-зонды, случайные боты) Reality прозрачно проксирует на локальный nginx с настоящим сайтом — сервер выглядит как обычный веб-хостинг.
Скрипт выполняет 18 фаз (0–17): проверки окружения (включая свободный :443) →
ввод параметров → зависимости и Docker (подписанный apt-репо) → хардинг SSH →
fail2ban → sysctl → nginx :80 + SSL
(webroot) → nginx-fallback :8443 → фейковый сайт → генерация ключей и JSON →
пауза на настройку панели → geo-файлы → запуск remnawave-node →
автообслуживание → watchdog → UFW → Beszel → итоговая сводка.
| Порт | Назначение |
|---|---|
| 2810 | SSH (key-only) |
| 443 | Xray Reality (VLESS tcp/xhttp) |
<port> |
Xray Reality XHTTP (только режим both) |
| 80 | HTTP-редирект + ACME challenge |
| 2222 | Remnawave node API |
| 45876 | Beszel agent (опционально) |
nginx-fallback слушает
127.0.0.1:8443(только loopback — через него ходит Reality), наружу не публикуется.
Актуально для Panel 2.8.0. Учти изменения хостов в этой версии: единый
tagзаменён на массивtags[];allowInsecureубран; фиксированные значенияfingerprintбольше не enum — это свободная строка (chromeпо-прежнему валиден); ALPN поддерживаетh2,h3и комбинации.
- Config Profiles → Create — вставить JSON из вывода скрипта.
- Nodes → Create — Address = IP сервера, Port
2222, привязать профиль, включить все inbound, скопироватьSECRET_KEYобратно в скрипт. - Hosts → Create — Address и SNI = домен, Fingerprint
chrome:- Flow задавать не нужно — для VLESS + Reality + TCP панель добавляет
xtls-rprx-visionавтоматически; tcp-хост: Port443, ALPN не задавать;xhttp-хост: Port443(или<port>в режимеboth), ALPNh2;- в режиме
bothсоздать два хоста — по одному на каждый inbound.
- Flow задавать не нужно — для VLESS + Reality + TCP панель добавляет
- Internal Squads → Default-Squad — добавить все inbound ноды (без этого нода не попадёт в подписку).
Проверь готовую ссылку подписки: для tcp-инбаунда в ней должно быть
&flow=xtls-rprx-vision. Если flow не появился — в Config Profile поменяй"network": "tcp"на"network": "raw"(в Xray 26.x это одно и то же).
TCP + Vision выбран по умолчанию ради маршрутизации на роутере: ядро mihomo
(podkop / Nikki) парсит ссылку подписки Remnawave с flow=xtls-rprx-vision
без доработок.
Начиная с Panel/Node 2.8.0 Remnawave умеет генерировать XHTTP- и Hysteria2-подписки и для клиентов на ядре Mihomo (полный набор xmux, download-settings и padding). Если твоя сборка podkop собрана со свежим mihomo — XHTTP на роутере становится реально применим; проверяй на своей прошивке перед раскаткой на флот.
В режиме both подписка содержит и tcp-, и xhttp-ссылку — приложения (Happ)
видят обе, а роутер берёт tcp. Раскатка подписки на роутер и авто-выбор
быстрейшего сервера живут в отдельных инструментах (podkop-sub, fleet_deploy)
и в этот репозиторий не входят.
Ядро Xray живёт внутри docker-образа remnawave/node, а Reality-конфиг
хранится в панели, не на ноде. Поэтому при выходе новой версии ядра
(например, Node 2.8.0 → Xray-core 26.6.27) полная пересборка не нужна —
достаточно подтянуть свежий образ. Хардинг, geo, nginx и SSH не затрагиваются.
Достаточно подтянуть свежий образ. На ноде:
cd /opt/remnanode && docker compose pull && docker compose up -dХардинг, geo, nginx, SSH и ключи не затрагиваются. Чтобы зафиксировать
конкретную версию, поправь строку image: в /opt/remnanode/docker-compose.yml
перед pull (по умолчанию remnawave/node:latest; тег задаётся и при первом
деплое через REMNANODE_IMAGE).
Панель мониторит только API-порт
2222— нода может показываться «зелёной» при мёртвом VPN-инбаунде. После обновления проверь реальный inbound:ss -tlnp | grep -E ':(443|8444)'на ноде.
| Задача | Где |
|---|---|
| Ключи Reality | /opt/remnanode/keys.txt (chmod 600) |
| Лог установки | /var/log/deploy-remnanode.log (chmod 600) |
| Обновление geo | cron 0 3 * * * → update-geo.sh (с валидацией) |
| Перезапуск при падении | cron */5 → watchdog.sh |
| Обновление образа ноды | docker compose pull && up -d в /opt/remnanode |
| Логи ноды | docker logs remnawave-node |
- Приватный ключ Reality печатается только на терминал; Config Profile с ключом
сохраняется в
/opt/remnanode/config-profile.json(600) и не пишется в лог. - Лог установки,
.envиkeys.txtсоздаются с правами600; фейк-сайт —644(иначе nginx-воркер отдаёт 403 и ломает маскировку). - SSH: только по ключу, root запрещён, нестандартный порт,
ssh.socketзамаскирован,sshd -tперед рестартом (защита от локаута), fail2ban. - SSL выпускается и продлевается через webroot без остановки nginx; продление пересоздаёт контейнер ноды (renewal-hook), чтобы Xray подхватил новый cert.
- Docker ставится из официального apt-репозитория с GPG-проверкой пакетов
(не
curl … | sh); проверяется наличиеdocker composev2. - Существующие
daemon.json/cli.ini/sshd_configрезервируются перед перезаписью.
Нашёл проблему безопасности? Не открывай публичный issue — см. SECURITY.md.
Почему TCP по умолчанию, а не XHTTP?
TCP + Vision совместим со всеми клиентами и стабилен. XHTTP (packet-up)
устойчивее к поведенческому DPI на мобильных сетях, но с частью клиентов на
mihomo исторически менее надёжен — хотя в Panel 2.8.0 поддержка Mihomo+XHTTP
уже появилась. Выбор остаётся за тобой при запуске.
Зачем режим both?
Одна нода отдаёт и tcp (для podkop/флота), и xhttp (для клиентов за жёстким
DPI) одновременно, с общим ключом.
Не нашёл поле Flow в панели.
Его там и нет. Remnawave добавляет flow: xtls-rprx-vision автоматически для
VLESS + Reality + TCP. Проверить можно в готовой ссылке подписки.
Обновилось ядро — надо пересобирать ноды?
Нет. Ядро внутри docker-образа. На ноде: cd /opt/remnanode && docker compose pull && docker compose up -d. Reality-конфиг, ключи и хардинг не тронутся.
Можно ли запускать deploy повторно?
Да, скрипт идемпотентен: пользователь, ключи, конфиги переиспользуются, apt upgrade на живой ноде пропускается, geo и контейнер обновляются.
Нода не появилась в клиенте. Проверь шаг 4 в панели — inbound должен быть добавлен в Internal Squad, иначе он не попадёт в подписку.
| Версия | Изменения |
|---|---|
| v3.9 | UX + аудит: выбор транспорта цифрой 1/2/3, SSH-примеры для Windows/Linux/macOS, Docker из подписанного apt-репо (+ гарантия compose v2), проверка свободного :443, head -1 в парсинге ключа, устойчивая fallback-цепочка keygen, check_internet без ICMP-маскировки, поллинг старта контейнеров вместо sleep, 45876 в списке занятых портов |
| v3.8 | Аудит: privateKey убран из лога (JSON → config-profile.json 600), SSH-хардинг в 00-hardening.conf (пароли реально off), nginx-fallback только loopback + порт убран из UFW, фикс зависания phase2 (needrestart/lock), renewal пересоздаёт ноду, обязательный geoip.dat, bittorrent → BLOCK, пин образа REMNANODE_IMAGE |
| v3.7 | Аудит: chmod фейк-сайта (фикс 403), mask ssh.socket (фикс падений SSH), zero-downtime SSL (webroot), валидация geo перед подменой, санитизация имени/портов, apt upgrade только при первичной установке, парсинг ключей под Xray 26.x, XHTTP packet-up |
| v3.6 | Режим транспорта both (tcp+xhttp на одной ноде), авто-открытие xhttp-порта в UFW |
| v3.5 | Аудит безопасности: лог 600, ключи не в лог, hub-IP убран, getent, backend=systemd, бэкапы конфигов |
| v3.4 | Выбор транспорта tcp/xhttp; tcp использует flow Vision |
| v3.1 | NODE_PORT в .env, geo до docker up, все read из /dev/tty |
| v3.0 | XHTTP + steal_oneself, один домен, Xray на 443 |
| v2.0 | Полный хардинг, admin-user, fail2ban, sysctl |
| v1.0 | Первая версия |
PR и issue приветствуются. Перед отправкой:
- прогони ShellCheck:
shellcheck deploy-remnanode.sh— должно быть без замечаний; - проверь синтаксис:
bash -n deploy-remnanode.sh; - сохраняй идемпотентность и не пиши секреты в лог;
- держи стиль: фазовые функции, хелперы
ok/info/warn/die,set -euo pipefail.
MIT © anfixit
- Remnawave — панель управления
- XTLS/Xray-core — ядро
- chika0801/Xray-examples — референсные конфиги
- runetfreedom/russia-v2ray-rules-dat — geo-файлы
- henrygd/beszel — мониторинг