Remnawave с нуля: панель в Docker за reverse proxy
Установка панели по официальной инструкции: compose, секреты в .env, Caddy или nginx перед ней, первый вход и что бэкапить. Плюс грабли, на которые сообщество уже наступило.
Официальная установка Remnawave занимает три команды и один конфиг прокси. Большая часть проблем в чатах начинается с попытки сэкономить на последнем: открыть порт 3000 наружу «на пять минут» или поставить скрипт, который делает всё сразу и непонятно как.
Заметка
Гайд опирается на Remnawave 3.4.4 (релиз backend и panel от 2026-09-12) и на файлы docker-compose-prod.yml и .env.sample из ветки main репозитория
remnawave/backend на 2026-09-24. Переменные окружения между версиями меняются: при 3.0 сообщество, например, ловило переименование секрета JWT в APP_SECRET (
Env). Перед установкой и каждым обновлением сверяйся с актуальным .env.sample.
Что понадобится
Требования из документации:
| Минимум | Рекомендуется | |
|---|---|---|
| CPU | 2 ядра | 4 ядра |
| RAM | 2 ГБ | 4 ГБ |
| Диск | 20 ГБ | 20 ГБ |
| ОС | Ubuntu или Debian |
Нужен Docker с плагином Compose. Документация ставит его официальным скриптом:
sudo curl -fsSL https://get.docker.com | shИ обязательно свой домен, направленный A/AAAA-записью на сервер. Без домена официально только TryCloudflare, и то для разработки.
Панель не содержит Xray: трафик пользователей обслуживают ноды на отдельных серверах, их подключение описано в гайде Нода Remnawave.
Лайфхак
Опыт сообщества (июль 2026): панель в РФ держать не советуют, а сам сайт docs.rw из РФ без VPN может не открываться ( Ошибки → фиксы, Установка и обновление). Документацию лучше открыть заранее.
- Браузер
- Caddy / nginx
- Панель
remnawave - Нода
remnawave-network, панель опубликована только на loopbackУстановка
Файлы
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Путь /opt/remnawave не обязателен, но на него ссылаются все остальные страницы документации, включая обновление.
Секреты
APP_SECRET, METRICS_PASS и WEBHOOK_SECRET_HEADER в примере заданы значениями по умолчанию (change_me, admin и публичная строка из репозитория). Документация генерирует их так:
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Пароль Postgres по умолчанию postgres, его настоятельно советуют сменить. Команда из доки меняет его сразу в двух местах, POSTGRES_PASSWORD и DATABASE_URL:
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Грабли
Меняй пароль Postgres до первого docker compose up. Образ postgres берёт POSTGRES_PASSWORD только при инициализации пустого тома. Если база уже создана, новая строка в .env не сменит пароль внутри базы, и панель перестанет к ней подключаться.
Домены
В .env правишь вручную:
FRONT_END_DOMAIN=panel.example.com
SUB_PUBLIC_DOMAIN=panel.example.com/api/sub
PANEL_DOMAIN=panel.example.com| Переменная | Обязательна | Зачем |
|---|---|---|
APP_SECRET | да | секрет приложения, дока рекомендует от 64 символов |
FRONT_END_DOMAIN | да | домен панели, из него строятся CORS-заголовки |
SUB_PUBLIC_DOMAIN | да | домен и путь публичной ссылки подписки, без http(s):// и без / в конце |
PANEL_DOMAIN | нет | прямые ссылки на панель, например в Telegram-уведомлениях |
DATABASE_URL | да | строка подключения к Postgres в формате postgresql://user:password@host:port/db |
Пока отдельной страницы подписки нет, SUB_PUBLIC_DOMAIN равен домену панели плюс /api/sub. Остальные переменные (уведомления, вебхуки, метрики) описаны на странице
Environment Variables.
Что внутри compose
Официальный docker-compose.yml поднимает три контейнера в сети remnawave-network:
| Контейнер | Образ | Порт на хосте |
|---|---|---|
remnawave | remnawave/backend:3 | 127.0.0.1:3000 (панель), 127.0.0.1:3001 (метрики) |
remnawave-db | postgres:18.4 | 127.0.0.1:6767 |
remnawave-redis | valkey/valkey:9-alpine | нет, только unix-сокет |
Что из этого следует:
- Все порты уже опубликованы на
127.0.0.1. Не «исправляй» это на3000:3000. - Тег
remnawave/backend:3держит мажорную версию:docker compose pullобновит до последней 3.x, но не перепрыгнет на 4. - Valkey запущен с
--save ""и--appendonly no, то есть ничего не пишет на диск. Всё, что нужно сохранить, лежит в Postgres. - У всех сервисов ограничены логи (
json-file, 100 МБ × 5 файлов).
Запуск
cd /opt/remnawave && docker compose up -d && docker compose logs -f -tВажно
.env читается при создании контейнера. Документация прямо пишет: после правки переменных нужен docker compose down && docker compose up -d, простой restart старое окружение не заменит. В сообществе это одна из самых частых причин «поменял, а не работает» (
Установка и обновление).
Reverse proxy
Документация выделяет это красным: прокси обязателен, наружу сервисы не выставлять, только 127.0.0.1. Дополнительные требования:
- Панель работает только на корне домена или поддомена. Путь вида
example.com/remnawaveне поддерживается. - SSH-проброс порта (
ssh -L 3000:...) тоже не поддерживается.
Причина в коде backend: middleware разрывает соединение, если в запросе нет заголовка X-Forwarded-For или X-Forwarded-Proto не равен https, и пишет в лог Reverse proxy and HTTPS are required. Поэтому curl http://127.0.0.1:3000 получит обрыв соединения вместо ответа, и это нормально.
Caddy (официальный вариант)
Caddy сам получает сертификат и сам проставляет X-Forwarded-For и X-Forwarded-Proto.
https://panel.example.com {
encode
reverse_proxy * http://remnawave:3000
}
:443 {
tls internal
respond 204
}Второй блок ловит всё остальное на 443: запросы с чужим именем или по голому IP получают самоподписанный сертификат и пустой ответ 204, а не панель.
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-datacd /opt/remnawave/caddy && docker compose up -d && docker compose logs -f -tCaddy подключается к внешней сети remnawave-network и ходит к панели по имени контейнера. Поэтому панель сначала, прокси потом: сеть создаёт compose панели.
nginx
Официальный гайд по nginx устроен так же (контейнер remnawave-nginx в сети remnawave-network, proxy_pass http://remnawave:3000), но сертификат выпускается отдельно через acme.sh в режиме TLS-ALPN на порту 8443. Две детали оттуда: порт 8443 должен быть свободен и открыт при каждом продлении, а зоны .ru, .su и .рф этот способ не поддерживает, потому что их не обслуживает ZeroSSL. В конфиге обязательны proxy_set_header X-Forwarded-For и X-Forwarded-Proto $scheme, иначе сработает проверка выше. Про сертификаты подробнее в гайде
TLS-сертификаты.
Панель наружу
ports:
- 3000:3000Порт открыт миру в обход файрвола, а панель всё равно разорвёт соединение без HTTPS-прокси.
ports:
- 127.0.0.1:3000:${APP_PORT:-3000}Как в официальном compose. Снаружи только 443 у Caddy или nginx.
Панель за прокси
Заметка
Документация советует проксировать домен через Cloudflare (оранжевое облако), если Cloudflare нормально работает в твоём регионе. Для аудитории из РФ это «если» важное, разбор в гайдах nginx за Cloudflare и Сайт не открывается из РФ.
Первый вход
Открываешь https://panel.example.com, видишь форму регистрации. Первый зарегистрированный пользователь становится суперадмином. Поэтому регистрируйся сразу, как только прокси заработал, а не оставляй свежую панель висеть в интернете.
Забыл пароль или случайно отключил вход по паролю через OAuth-настройки: поможет Rescue CLI.
docker exec -it remnawave cliВ меню есть сброс суперадмина (после него панель снова предложит создать аккаунт) и включение входа по паролю.
Данные и бэкапы
| Что | Где |
|---|---|
| База панели | docker-том remnawave-db-data |
| Секреты и настройки | /opt/remnawave/.env, /opt/remnawave/docker-compose.yml |
| Прокси | Caddyfile и том caddy-ssl-data (или конфиг nginx и сертификаты) |
В базе, кроме пользователей и настроек, лежит таблица keygen: корневой сертификат, которым панель подписывает ключи нод. Потеряешь базу без дампа, и каждой ноде придётся выдавать новый SECRET_KEY. Восстановишь из дампа, и ноды подключатся со старыми ключами.
Бэкапить логическим дампом pg_dump, а не копией тома. Скрипт, шифрованный репозиторий и проверка восстановления в гайде
Бэкапы: pg_dump, restic и systemd, опыт сообщества в
Бэкапах.
Безопасность
- Проверь, что наружу смотрят только 80/443 прокси:
ss -tlnp. Почемуufwи nftables не видят опубликованные Docker-порты, разобрано в гайде Docker для панелей и ботов. - Файрвол хоста по гайду nftables: минимальный файрвол. Для связи с нодами на панели ничего открывать не нужно: соединение инициирует панель.
- Дополнительная защита страницы входа из официального раздела
Panel Security: Caddy с авторизацией и секретным путём (
remnawave/caddy-with-auth), TinyAuth для nginx, Cloudflare Zero Trust.
Обновление
cd /opt/remnawave && docker compose pull && docker compose down && docker compose up -d && docker compose logs -f
docker image pruneПорядок из документации: сначала панель, потом ноды. Перед обновлением дамп базы и чтение changelog. Подробно в гайде Обновления без поломок.
Типовые ошибки
| Симптом | Причина и что делать |
|---|---|
Соединение рвётся, в логе Reverse proxy and HTTPS are required. | Запрос пришёл мимо прокси или прокси не передал X-Forwarded-For / X-Forwarded-Proto: https. Проверь заголовки в конфиге nginx. |
Поменял .env, ничего не изменилось | Нужен docker compose down && docker compose up -d, не restart. |
| Панель не подключается к базе после смены пароля | Пароль сменили в .env уже после инициализации тома, а образ postgres применяет его только к пустому каталогу данных. Меняй пароль внутри базы или делай это до первого запуска. |
В nginx host not found in upstream | Прокси не в сети remnawave-network. В сообществе классика (
Реверс-прокси). |
| Прокси не стартует, 443 занят | В сообществе фиксировали: nginx и Caddy на одном сервере вместе не живут, оставь один ( Реверс-прокси). |
| После обновления сломались бот или ноды | Сообщество регулярно ловит несовместимость версий: при 3.0 бот Bedolaga падал с KeyError: 'uuid', ноды не стыковались с панелью другой версии (
Ошибки → фиксы,
Релизы). Бот и панель обновляй согласованно, см.
Бот Bedolaga. |
Больше случаев с датами в индексе ошибок.
Источники
- Remnawave: Requirements, Remnawave Panel, Environment Variables, Upgrading
- Remnawave: Reverse Proxies, Caddy, Nginx, Panel Security
- Remnawave: Initial Setup, Rescue CLI, исходники документации в remnawave/panel
- remnawave/backend 3.4.4: docker-compose-prod.yml, .env.sample, proxy-check.middleware.ts, cli.ts, релизы
- Caddy: reverse_proxy, заголовки по умолчанию
- Опыт сообщества: Установка и обновление, Docker-compose, Env, Nginx / Caddy, Ошибки → фиксы, Релизы, Реверс-прокси, Индекс ошибок