9.0 KiB
VPN Panel
Админ-панель VPN на Go + PostgreSQL 17. Готово к деплою в Dokploy через Docker Compose.
Стек
- Go 1.23 (веб-админка)
- PostgreSQL 17
- Docker Compose
- Reverse proxy + SSL: Caddy / Nginx / Traefik
Быстрый старт (Dokploy / Docker)
- В Dokploy создайте Docker Compose приложение из этого репозитория.
- Задайте Environment Variables (
.envв git не лежит):
APP_SECRET=long-random-secret
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=strong-password
POSTGRES_PASSWORD=strong-db-password
- Deploy. Домен в Dokploy → сервис
app, порт8080(не postgres). - Если Bad Gateway: смотрите логи
app— чаще всего падение из‑за БД или домен смотрит не на тот порт.
docker compose up -d --build
docker compose logs -f app
Панель: http://localhost:8080 · health: /health
Авторизация админа (из .env)
| Переменная | Значение по умолчанию |
|---|---|
ADMIN_EMAIL |
admin@panel.local |
ADMIN_PASSWORD |
Admin123!ChangeMe |
ADMIN_NAME |
Administrator |
При первом запуске админ создаётся автоматически из этих переменных.
Режим ноды (как Remnawave, но проще)
Панель не гоняет Xray сама — VPN поднимается на отдельных серверах-нодах (как Remnawave Node).
Чем удобнее
| Remnawave Node | VPN Panel |
|---|---|
| Docker вручную + вставить compose | Авто по SSH: host/user/пароль (или ключ) → панель ставит Docker + агент |
| Или вручную | Ручной режим — тот же compose, если SSH недоступен |
Как добавить ноду
- Админка → Ноды → Добавить ноду
- Укажите имя, IP/хост, SSH (
root+ пароль или ключ), порт API ноды (по умолчанию2222) - Режим:
- Авто по SSH — мастер подключается, ставит Docker (если нет), заливает бинарник
vpn-node, поднимаетdocker compose - Вручную — скопируйте
docker-compose.ymlи бинарник/app/bin/vpn-nodeна сервер
- Авто по SSH — мастер подключается, ставит Docker (если нет), заливает бинарник
- На firewall ноды откройте
NODE_PORTтолько для IP панели - Нажмите Проверить online
Агент слушает NODE_PORT, авторизация: Authorization: Bearer <SECRET_KEY>.
Эндпоинты агента: GET /health, GET|POST /api/v1/config, GET /api/v1/status.
SSH-секреты в БД шифруются AES-GCM ключом от APP_SECRET.
Панель в Docker должна иметь сетевой доступ до SSH (22) и NODE_PORT ноды. На VPS/Dokploy это обычно ок.
Reverse proxy + SSL (Let's Encrypt)
Примеры лежат в deploy/. Сеть Docker: vpn-panel-net.
Что нужно до выпуска сертификата
- DNS: A (и при необходимости AAAA) запись
DOMAIN→ публичный IP сервера. - Порты:
80и443открыты на firewall / security group (TCP; для Caddy HTTP/3 ещё443/udp). - Домен в
.env:DOMAIN=panel.example.com ACME_EMAIL=admin@example.com - Не светить панель наружу на
:8080— только через proxy:Либо в Dokploy / compose закомментируйтеdocker compose -f docker-compose.yml -f deploy/compose.behind-proxy.yml up -dportsуapp, оставьте доступ по внутренней сетиapp:8080. - Прокси обязан передавать заголовки
Host,X-Forwarded-Proto,X-Forwarded-For(уже есть в примерах).
Let's Encrypt не выпустит сертификат на
localhost/ приватный IP. Нужен реальный домен с публичным DNS.
Вариант A — Caddy (самый простой, SSL автоматом)
Caddy сам получает и продлевает сертификат.
- В
deploy/caddy/Caddyfileдомен берётся из{$DOMAIN:...}(или задайте в.env). - Запуск вместе с панелью:
# из корня репозитория
docker compose \
-f docker-compose.yml \
-f deploy/compose.behind-proxy.yml \
-f deploy/caddy/docker-compose.caddy.yml \
up -d --build
- Откройте
https://panel.example.com.
Файлы: deploy/caddy/Caddyfile, deploy/caddy/docker-compose.caddy.yml.
Вариант B — Nginx + Certbot
- Подставьте свой домен в
deploy/nginx/nginx.conf(server_nameи пути к сертификатам). - Поднимите стек (сначала HTTP + ACME webroot):
docker compose \
-f docker-compose.yml \
-f deploy/compose.behind-proxy.yml \
-f deploy/nginx/docker-compose.nginx.yml \
up -d --build
- Выпустите сертификат:
docker compose -f deploy/nginx/docker-compose.nginx.yml run --rm certbot certonly \
--webroot -w /var/www/certbot \
-d panel.example.com \
--email admin@example.com \
--agree-tos --no-eff-email
- В
deploy/nginx/nginx.conf:- раскомментируйте блок
server { listen 443 ... }; - включите
return 301 https://$host$request_uri;в HTTP-сервере; - закомментируйте временный
location /на порту 80 (оставьте только ACME).
- раскомментируйте блок
- Перезагрузите nginx:
docker compose -f docker-compose.yml -f deploy/nginx/docker-compose.nginx.yml exec nginx nginx -s reload
Продление: контейнер certbot крутит renew раз в 12 часов; после renew — nginx -s reload.
Файлы: deploy/nginx/.
Вариант C — Traefik (свой или Dokploy)
C1. Свой Traefik из репозитория
docker compose \
-f docker-compose.yml \
-f deploy/compose.behind-proxy.yml \
-f deploy/traefik/docker-compose.traefik.yml \
up -d --build
В .env: DOMAIN, ACME_EMAIL. Сертификат выпускается HTTP-challenge на entrypoint web.
C2. Dokploy (встроенный Traefik)
Dokploy уже поднимает Traefik — не добавляйте deploy/traefik/docker-compose.traefik.yml.
- В Dokploy укажите домен для сервиса
app. - Либо добавьте labels к
app(см.deploy/traefik/labels.example.yml):
labels:
- traefik.enable=true
- traefik.http.routers.vpn-panel.rule=Host(`panel.example.com`)
- traefik.http.routers.vpn-panel.entrypoints=websecure
- traefik.http.routers.vpn-panel.tls=true
- traefik.http.routers.vpn-panel.tls.certresolver=letsencrypt
- traefik.http.services.vpn-panel.loadbalancer.server.port=8080
Имя certresolver в Dokploy часто letsencrypt — проверьте в настройках (или TRAEFIK_CERT_RESOLVER в .env).
- Не публикуйте порт
8080наружу в UI Dokploy, если трафик идёт только через Traefik.
Чеклист после включения HTTPS
| Проверка | Ожидание |
|---|---|
https://DOMAIN/ |
Главная панель |
https://DOMAIN/health |
ok |
| HTTP → HTTPS | Редирект 301 (Caddy/Traefik по умолчанию; Nginx — после шага 4) |
| Сертификат | Валидный LE, не self-signed |
Порт 8080 снаружи |
Закрыт |
Типичные ошибки
| Симптом | Причина |
|---|---|
| ACME timeout / pending | DNS ещё не указывает на сервер, или закрыт порт 80 |
| 502 Bad Gateway | Proxy не в сети vpn-panel-net / сервис app не запущен |
| Редирект-петля | За приложением HTTPS, а X-Forwarded-Proto не передаётся |
| Certbot: no such file | Домен в путях nginx.conf не совпадает с -d |
Протоколы (seed)
WireGuard, OpenVPN, VLESS, VMess, Trojan, Shadowsocks, Hysteria2 — можно включать/выключать в админке.
Локальная разработка без Docker
# нужен локальный Postgres 17 и .env с POSTGRES_HOST=localhost
go mod tidy
go run ./cmd/server
Эндпоинты
/— главная/login— вход/admin— дашборд/admin/nodes— ноды/admin/protocols— протоколы/health— healthcheck