Remnawave: панель, нода и VLESS Reality на двух VPS
Полная установка Remnawave в Docker: панель с Caddy и HTTPS, отдельная нода, профиль VLESS Reality, хост, пользователь и подписка. Плюс брандмауэр, обновление и бэкап. Ubuntu и Debian.

Remnawave — панель для управления VPN-серверами на ядре Xray, рассчитанная на несколько нод и сотни пользователей. Пользователи, подписки, лимиты, сквады — всё в одном месте, а серверы с Xray подключаются к панели как ноды. Проект открытый, с подробной официальной документацией.
Под эту инструкцию подойдёт любой VPS на tanaka.host: серверы в Германии, IPv4 и IPv6 в комплекте, оплата по дням.
Ниже — установка целиком: панель, HTTPS через Caddy, нода, профиль VLESS Reality, хост и первый пользователь. Команды из официальной документации, проверено на Remnawave 3.4.x. Если переезжаете с Marzban — есть отдельная статья.
Из чего состоит
- Панель — веб-интерфейс и API, PostgreSQL и кеш Valkey. Трафик пользователей через неё не идёт.
- Нода — лёгкий контейнер с Xray. К нодам и подключаются пользователи.
- Страница подписки — необязательный компонент, скрывает адрес панели и показывает инструкцию.
Пока нет ни одной ноды, подключиться никто не сможет, поэтому порядок строгий: панель → прокси → нода → профиль → хост → пользователи.
Что нужно
Два сервера. Разработчики не советуют ставить панель и ноду вместе: они будут спорить за порт 443, а при блокировке IP ноды вы потеряете и панель.
| Роль | Требования |
|---|---|
| Панель | от 2 ядер и 2 ГБ, лучше 4 и 4, диск 20 ГБ |
| Нода | от 1 ядра и 1 ГБ |
На оба — Ubuntu 24.04 или Debian 12.
Две A-записи: panel.ваш-домен.com → IP панели, cdn.ваш-домен.com → IP ноды. Отдельное имя для ноды позволяет потом сменить сервер, не трогая подписки.
Нейтральные имена. Никаких vpn, proxy, xray, vless, reality, node в домене — SNI передаётся открыто и легко ловится по списку. Лучше
cdn.example.comилиphotos.example.com. Проксирование Cloudflare для домена ноды должно быть выключено всегда, для панели — тоже лучше выключить (серое облако).
1. Подготовьте оба сервера
На каждом:
apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
docker --version && docker compose version
Подробнее про Docker — в отдельной статье.
2. Установите панель
На сервере панели:
mkdir /opt/remnawave && cd /opt/remnawave
curl -o docker-compose.yml https://raw.githubusercontent.com/remnawave/backend/refs/heads/main/docker-compose-prod.yml
curl -o .env https://raw.githubusercontent.com/remnawave/backend/refs/heads/main/.env.sample
Сгенерируйте секреты:
sed -i "s/^APP_SECRET=.*/APP_SECRET=$(openssl rand -hex 64)/" .env && sed -i "s/^METRICS_PASS=.*/METRICS_PASS=$(openssl rand -hex 64)/" .env && sed -i "s/^WEBHOOK_SECRET_HEADER=.*/WEBHOOK_SECRET_HEADER=$(openssl rand -hex 64)/" .env
Смените пароль базы:
pw=$(openssl rand -hex 24) && sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$pw/" .env && sed -i "s|^\(DATABASE_URL=\"postgresql://postgres:\)[^\@]*\(@.*\)|\1$pw\2|" .env
В nano .env укажите домен в трёх строках (без https:// и без слеша в конце):
FRONT_END_DOMAIN=panel.ваш-домен.com
PANEL_DOMAIN=panel.ваш-домен.com
SUB_PUBLIC_DOMAIN=panel.ваш-домен.com/api/sub
Запустите и посмотрите журнал:
docker compose up -d && docker compose logs -f -t
Когда появится заставка с версией — панель поднялась, выходите из журнала через Ctrl+C.
Не открывайте сервисы наружу. Всё слушает только
127.0.0.1, и так должно остаться. Доступ — только через прокси из следующего шага. После любых правок.envконтейнеры пересоздают:docker compose down && docker compose up -d.
3. Caddy и HTTPS
Caddy сам получает и продлевает сертификат Let’s Encrypt.
mkdir -p /opt/remnawave/caddy && cd /opt/remnawave/caddy && nano Caddyfile
https://panel.ваш-домен.com {
encode
reverse_proxy * http://remnawave:3000
}
:443 {
tls internal
respond 204
}
Второй блок отвечает пустотой на обращения по IP, не по вашему домену. Рядом nano docker-compose.yml:
services:
caddy:
image: caddy:2.9
container_name: 'caddy'
hostname: caddy
restart: always
ports:
- '0.0.0.0:443:443'
- '0.0.0.0:80:80'
networks:
- remnawave-network
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-ssl-data:/data
networks:
remnawave-network:
name: remnawave-network
driver: bridge
external: true
volumes:
caddy-ssl-data:
driver: local
external: false
name: caddy-ssl-data
docker compose up -d && docker compose logs -f -t
Через минуту https://panel.ваш-домен.com покажет страницу регистрации.
4. Зарегистрируйте администратора
Первый зарегистрированный становится супер-админом, поэтому сделайте это сразу. Придумайте юзернейм, нажмите Сгенерировать и скопировать для пароля, сохраните его и нажмите Зарегистрироваться. Потеряли доступ — docker exec -it remnawave cli на сервере панели.
5. Подключите ноду
На сервере ноды:
mkdir /opt/remnanode && cd /opt/remnanode
В панели Ноды → +: внутреннее название (например DE-1), страна, Домен или IP = cdn.ваш-домен.com, Node Port = 2222. Нажмите Скопировать docker-compose.yml — получите примерно такое:
services:
remnanode:
container_name: remnanode
hostname: remnanode
image: remnawave/node:latest
network_mode: host
restart: always
cap_add:
- NET_ADMIN
ulimits:
nofile:
soft: 1048576
hard: 1048576
environment:
- NODE_PORT=2222
- SECRET_KEY="ключ из панели"
Вставьте в nano docker-compose.yml на ноде и запустите:
docker compose up -d && docker compose logs -f -t
В журнале появится таблица с версией Xray — нода ждёт панель. Вернитесь в панель, Далее, в Конфигурация ядра пока выберите Default-Profile, Создать ноду. Через несколько секунд — «Подключение установлено. Xray Core запущен и работает!».
6. Профиль VLESS Reality
Профили → + → имя VLESS-Reality → Создать. В редакторе: меню рядом с Форматировать → Загрузить с GitHub → Example VLESS-TCP-REALITY config → Загрузить шаблон. Панель сразу подсветит please fill in a valid value for "target" — это нормально. Ключи генерируйте на ноде:
docker exec remnanode xray x25519
openssl rand -hex 8
В realitySettings заполните privateKey (строка PrivateKey), shortIds (вывод openssl в кавычках внутри скобок), target и serverNames (сайт для маскировки). Когда внизу появится Xray config is valid — Сохранить.
Не маскируйтесь под google.com, microsoft.com, apple.com — это главный признак, по которому сейчас блокируют. Надёжнее self-steal: nginx с вашим сайтом на ноде,
target=127.0.0.1:8443,serverNames= ваш домен,xver: 0. Пошагово — в статье про self-steal.
Включите профиль: Ноды → ваша нода → Конфигурация ядра → отметьте VLESS-Reality → сохранить. Затем Пользователи → Внутренние сквады → Default-Squad → галочка на VLESS-Reality → сохранить. Без этого пользователи подключение не получат.
7. Хост
Подписка → Хосты → +. Включите Видимость хоста (по умолчанию выключена!), Примечание — «Германия», Инбаунд — VLESS_TCP_REALITY, Адрес — cdn.ваш-домен.com. В Опции → Добавить → Отпечаток → firefox. Сохранить.
Почему firefox: пара «отпечаток Chrome + IP дата-центра» стала для фильтров признаком прокси. edge с Xray 26.9.8 не подключится вовсе — сервер требует ML-KEM, а профиль edge его не умеет. random/randomized тоже не ставьте.
8. Пользователь и подписка
Пользователи → +: юзернейм без пробелов (менять потом нельзя), лимит трафика (0 — без ограничений), дата окончания (по умолчанию сутки — поправьте), в Внутренние сквады отметьте Default-Squad. Создать. В карточке пользователя — Ссылка на подписку вида https://panel.ваш-домен.com/api/sub/идентификатор. Её отправляйте человеку, он импортирует в любой клиент на Xray-core (Incy, Happ, v2rayN, v2rayNG).
Брандмауэр
Панель:
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Нода (порт 2222 — только с IP панели):
ufw allow 22/tcp
ufw allow 443/tcp
ufw allow from IP_ПАНЕЛИ to any port 2222 proto tcp
ufw enable
Если SSH на другом порту — подставьте его вместо 22.
Страница подписки (необязательно)
Добавьте A-запись sub.ваш-домен.com, впишите её в SUB_PUBLIC_DOMAIN в /opt/remnawave/.env и пересоздайте панель: cd /opt/remnawave && docker compose down remnawave && docker compose up -d. В панели Настройки → Токены API создайте токен. Затем /opt/remnawave/subscription/.env:
APP_PORT=3010
REMNAWAVE_PANEL_URL=http://remnawave:3000
REMNAWAVE_API_TOKEN=токен_из_панели
Там же docker-compose.yml:
services:
remnawave-subscription-page:
image: remnawave/subscription-page:latest
container_name: remnawave-subscription-page
hostname: remnawave-subscription-page
restart: always
env_file:
- .env
ports:
- '127.0.0.1:3010:3010'
networks:
- remnawave-network
networks:
remnawave-network:
driver: bridge
external: true
docker compose up -d, затем новый блок в /opt/remnawave/caddy/Caddyfile:
https://sub.ваш-домен.com {
encode
reverse_proxy * http://remnawave-subscription-page:3010
}
И перезапуск Caddy: cd /opt/remnawave/caddy && docker compose down && docker compose up -d.
Обновление и бэкап
Сначала панель, потом ноды:
cd /opt/remnawave && docker compose pull && docker compose down && docker compose up -d
docker image prune
cd /opt/remnanode && docker compose pull && docker compose down && docker compose up -d
Бэкап — база и конфиги, Valkey ничего важного не хранит:
cd /opt/remnawave
docker exec remnawave-db pg_dump -U postgres postgres > backup-$(date +%F).sql
tar czf remnawave-config-$(date +%F).tar.gz .env docker-compose.yml caddy/Caddyfile
Копии уносите с сервера — например по статье про restic и S3.
Частые ошибки
- Панель не открывается. A-запись на IP панели;
docker compose logsв/opt/remnawaveи/opt/remnawave/caddy— если Caddy не получил сертификат, причина там. - Нода не подключается. Порт 2222 открыт для IP панели,
SECRET_KEYскопирован целиком. Журнал —docker compose logsв/opt/remnanode. - Ошибка про target. Не заполнены
target,serverNames,privateKey,shortIdsвrealitySettings. - SPAWN_ERROR: xray. Xray на ноде не стартовал — ошибка в профиле или занят порт.
docker exec remnanode xlogs. - Пользователь не видит сервер. Профиль в
Default-Squad, пользователь в скваде, у хоста включена видимость. - Подключение есть, сайты не открываются.
serverNames, ключи иshortIdsсовпадают с тем, что получает клиент; IP ноды не заблокирован у провайдера.