Полностью автоматизированное развертывание Remnawave Panel, Remnawave Nodes, Subscription Page
и полная миграция данных Marzban → Remnawave (inbounds, hosts, users).
- Автодеплой панели Remnawave
- Автодеплой нод + автоматическая регистрация в панели
- Автодеплой страницы подписки (bundled / separate)
- Subscription Page v7 (blue-green):
- параллельный next-контур на отдельном порту;
- декларативная конфигурация через Remnawave API;
- безопасный cutover/rollback production upstream;
- TLS и health checks
- Управление сертификатами (HTTP‑01 / DNS‑01)
- Интеграция с HAProxy (TLS passthrough, SNI‑routing)
- Полная миграция данных Marzban → Remnawave
- inbound VLESS Reality
- hosts (node-host configs)
- users (включая uuid, трафик, статус, срок действия)
- Legacy Router: поддержка старых ссылок формата
https://<domain>/sub/<marzban_token> - Smoke‑тесты панели, нод и страницы подписки
- Полный decommission нод
make panelПосле успешного развёртывания панели:
-
Зайдите в веб-интерфейс панели под
admin. -
Перейдите в Settings → API Tokens → Create Token.
-
Скопируйте значение токена (
ey...) и сохраните в:inventory/group_vars/panel/vault.yml
пример:
vault_remnawave_panel_api_token: "eyJhbGciO..."
Этот токен используется для API-вызовов и автоматического добавления inbound’ов.
make dns LIMIT=panel TAGS=cf_dnsПосле того как панель развернута и токен добавлен в vault, можно автоматически добавить Reality-inbound в профиль панели:
make inboundsПримеры:
# ограничить по хосту
make inbounds LIMIT=panel
# явно указать UUID профиля
make inbounds EXTRA='-e remnawave_profile_uuid=7988e3a1-5a32-461a-9136-c9475e92f19a'Inbound будет создан или обновлён идемпотентно (по tag), а затем автоматически зарегистрирован во внутреннем скваде Default-Squad.
Подробности см. в docs/remnawave_inbounds.md
Разворачивает production-контейнер Remnawave Subscription Page (legacy, порт 3010) и Nginx-vhost.
make sub LIMIT=subscriptionПримеры:
# bundled: страница подписки на том же хосте, что и панель
make sub LIMIT=panel
# separate: отдельный subscription-хост
make sub LIMIT=subscriptionSubscription Page v7 — next-контур, API-конфигурация, бренды и cutover:
make sub-next-check LIMIT=subscription
make sub-next-full LIMIT=subscription
make sub-next-config-check
make sub-next-config-plan LIMIT=subscription
make sub-next-config-apply LIMIT=subscription
# multi-brand Subpage Configs + External Squads
make subscription-branding-check LIMIT=subscription
# make subscription-branding LIMIT=subscription # apply только после явного подтверждения
make sub-cutover-check LIMIT=subscription
make sub-cutover LIMIT=subscription
make sub-rollback-check LIMIT=subscription
make sub-rollback LIMIT=subscription
make sub-portalbase-check LIMIT=subscription
make sub-portalbase LIMIT=subscriptionПодробности v7: docs/remnawave_subscription_page_next.md Multi-brand / External Squads: docs/remnawave_subscription_branding.md Legacy deploy: docs/remnawave_subscription_deploy.md
Declarative JSON v7:
roles/remnawave_subscription_page_config/files/base.json+files/brands/*.patch.json
Для новой ноды per-node vault.yml с remnawave_secret_key больше не
обязателен. make nodes LIMIT=<new-node> сам получает ключ через
GET /api/keygen и сохраняет его в /opt/remnanode/.env. Повторный запуск
читает .env, не генерирует новый ключ и не перезаписывает файл.
Существующие Vault-секреты поддерживаются и имеют приоритет над .env и API.
Старые ноды не перегенерируются.
API token панели должен иметь scope keygen:get.
После этого можно запускать ноду:
make nodes LIMIT=de-fra-1 TAGS=nodemake nodes LIMIT=node-name TAGS=register_nodemake nodes LIMIT=node-name TAGS=register_hostRead-only аудит Host в панели и dry-run register_host:
make hosts-audit LIMIT=panel
make hosts-plan LIMIT=de-fra-1remark — отображаемое имя Host; брендовая подпись задаётся через External Squad
serverDescription. Безопасное переименование Host: match mode endpoint_inbound +
явный rw_host_set_remark_if_exists=true (по умолчанию выключено). Подробности:
docs/remnawave_add_host.md.
make nodes LIMIT=node-name TAGS=smoke_nodeКогда ноду нужно корректно вывести из работы (например, при обновлении или замене), процесс выполняется в три шага:
-
Отключить ноду и её хосты
make disable-node EXTRA='-e remnawave_node_name=de-fra-1 -e remnawave_enable_state=false -e remnawave_disable_hosts_of_node=true' -
Дождаться завершения активных сессий
- Убедитесь через панель или Grafana, что активных соединений нет.
- При необходимости можно запустить smoke-тесты:
make nodes LIMIT=de-fra-1 TAGS=smoke_node
-
Удалить ноду (и связанные хосты)
make delete-node EXTRA='-e remnawave_node_name=de-fra-1 -e remnawave_delete_hosts=true'
🔒 Обе операции безопасны и идемпотентны — повторный запуск не приведёт к ошибкам.
В репозитории присутствуют три специализированные роли, позволяющие полностью перенести конфигурацию из существующего Marzban-кластера в Remnawave:
-
Inbound VLESS TCP Reality
roles/remnawave_migrate_inbound -
Hosts (пулы адресов / Domain Bindings)
roles/remnawave_migrate_hosts -
Users (статусы, лимиты, UUID, squads, expireAt)
roles/remnawave_migrate_users
Все роли поддерживают DRY-RUN, работают идемпотентно и допускают повторный запуск без побочных эффектов.
Переносит профиль Reality из Marzban в Remnawave, маппируя:
- публичный ключ сервера,
- shortId,
- serverName,
- поток реальности,
- параметры VLESS,
- теги,
- слушающие адреса.
make migrate-inboundПримеры:
# Только посмотреть, что будет создано/обновлено
make migrate-inbound EXTRA='-e remnawave_migrate_inbound_dry_run=true'Подробности:
👉 docs/remnawave_migrate_inbound.md
Переносит host-binding’и (доменные имена, режимы, привязку к inbound'ам).
make migrate-hostsПримеры:
# DRY-RUN без внесения изменений
make migrate-hosts EXTRA='-e remnawave_migrate_hosts_dry_run=true'Документация:
👉 docs/remnawave_migrate_hosts.md
Самая сложная часть миграции — перенести всех пользователей Marzban:
- username / note
- статус (active / disabled / limited / expired)
- trafficLimit + стратегия
- expireAt → перевод unix-timestamp → ISO8601
- VLESS UUID — перенос 1:1
- squads (опционально)
- описание
- фильтрация по
usernames=[...]
Команда:
make migrate-users LIMIT=panelПримеры:
# Полный DRY-RUN всех пользователей
make migrate-users LIMIT=panel EXTRA='-e remnawave_migrate_users_dry_run=true'
# DRY-RUN только одного пользователя
make migrate-users LIMIT=panel EXTRA='-e remnawave_migrate_users_dry_run=true -e remnawave_migrate_users_usernames=["us_67"]'
# Применить реальные изменения для конкретного пользователя
make migrate-users LIMIT=panel EXTRA='-e remnawave_migrate_users_dry_run=false -e remnawave_migrate_users_usernames=["us_67"]'Роль гарантирует:
- идемпотентность: существующий пользователь → PATCH, нового → POST
- никакого «добавления _ в конце» (строгая нормализация)
- уведомления в выходном логе о
createилиupdate
Документация:
👉 docs/remnawave_migrate_users.md
| Раздел | Файл | Описание |
|---|---|---|
| Панель | docs/remnawave_panel.md | Установка панели и сервисов |
| Обновление (Upgrade) | docs/remnawave_upgrade.md | Безопасное обновление панели и нод (upgrade flow) |
| Inbounds | docs/remnawave_inbounds.md | Добавление и регистрация inbound’ов |
| AntiBlock CDN | docs/antiblock_cdn.md | xHTTP packet-up inbound, per-node Yandex CDN, wildcard cert |
| HAProxy | docs/haproxy_tls_sni.md | Совместная работа панели и Xray |
| Ноды | docs/remnawave_node.md | Запуск контейнера с SECRET_KEY |
| Регистрация ноды | docs/remnawave_register_node.md | API-регистрация ноды |
| Регистрация Host | docs/remnawave_add_host.md | Host reconcile, audit, безопасный rename remark |
| Subscription Deploy | docs/remnawave_subscription_deploy.md | Развёртывание страницы подписки |
| Subscription Page | docs/remnawave_subscription_page.md | Конфигурация Nginx и Docker контейнера |
| Subscription Page v7 | docs/remnawave_subscription_page_next.md | Blue-green deploy, API-конфигурация, cutover и rollback |
| Проверки | docs/smoke_tests.md | Smoke-тесты панели и нод |
| Отключение ноды | docs/remnawave_disable_node.md | Временное отключение ноды и хостов |
| Удаление ноды | docs/remnawave_delete_node.md | Полное удаление ноды и связанных хостов |
| Миграция Inbound | docs/remnawave_migrate_inbound.md | Перенос Reality-inbound |
| Миграция Hosts | docs/remnawave_migrate_hosts.md | Перенос Host-binding’ов |
| Миграция Users | docs/remnawave_migrate_users.md | Полная миграция пользователей |
flowchart TB
User[Пользователь] -->|запрос к remna.vpn-for-friends.com или sub.vpn-for-friends.com| CloudflareDNS[Cloudflare DNS]
CloudflareDNS --> PublicIP_One[Публичный IP Host1]
PublicIP_One --> HAProxy443
subgraph Host1 [Host1: panel + subpage + node]
HAProxy443[HAProxy 443 TCP SNI]
Nginx4443[Nginx 4443 loopback]
Xray8444[Xray 8444 loopback]
Panel3000[Panel app port 3000]
Sub3010[Subscription page port 3010 docker]
Certbot[Certbot ACME]
HAProxy443 -->|SNI remna.* , sub.*| Nginx4443
HAProxy443 -->|non-TLS/иное SNI| Xray8444
Sub3010 -->|HTTP /api| Nginx4443
Nginx4443 -->|proxy /api| Panel3000
Nginx4443 -->|proxy| Panel3000
Nginx4443 -->|proxy| Sub3010
Nginx4443 -. validation .-> Certbot
end
Certbot -. DNS-01 или HTTP-01 .-> CloudflareDNS
flowchart TB
User[Пользователь] -->|remna-domain| CloudflareDNS[Cloudflare DNS]
User -->|sub-domain| CloudflareDNS
CloudflareDNS -->|A remna-domain| PublicIP_Panel[Публичный IP Host1]
CloudflareDNS -->|A sub-domain| PublicIP_Sub[Публичный IP Host2]
PublicIP_Panel --> HAProxy1
subgraph Host1 [Host1: panel + node]
HAProxy1[HAProxy 443 TCP SNI]
Nginx1[Nginx 4443 loopback]
Xray1[Xray 8444 loopback]
Panel3000[Panel app port 3000]
Certbot1[Certbot ACME]
HAProxy1 -->|SNI remna-domain| Nginx1
HAProxy1 -->|non-TLS/иное SNI| Xray1
Nginx1 -->|proxy /api| Panel3000
Nginx1 -. validation .-> Certbot1
end
PublicIP_Sub --> Nginx2
subgraph Host2 [Host2: subscription]
Nginx2[Nginx 443 upstream legacy/next]
Sub3010[Legacy Subscription Page :3010]
Sub3011[Subscription Page v7 :3011]
Certbot2[Certbot ACME]
Nginx2 -->|production upstream| Sub3010
Nginx2 -->|production upstream| Sub3011
end
Sub3010 -->|HTTPS remna-domain /api| PublicIP_Panel
Sub3011 -->|HTTPS remna-domain /api| PublicIP_Panel
Certbot1 -. DNS-01 или HTTP-01 .-> CloudflareDNS
Certbot2 -. DNS-01 или HTTP-01 .-> CloudflareDNS
inventory/group_vars/all/vault.yml
inventory/group_vars/panel/vault.yml
inventory/host_vars/<node>/vault.yml
Не коммитим содержимое Vault в git.
Используйтеansible-vault editдля безопасного редактирования файлов.
curl -vk https://panel.example.com/health
docker logs remnanode --tail=50
echo | openssl s_client -connect IP:443 -servername panel.example.com
echo | openssl s_client -connect IP:443 -servername www.cloudflare.comPR приветствуются: дополнения к ролям, новые дашборды и правила, улучшения документации. Старайтесь сопровождать изменения коротким описанием и примерами проверки.