VPN Panel

Админ-панель VPN на Go + PostgreSQL 17. Готово к деплою в Dokploy через Docker Compose.

Стек

  • Go 1.23 (веб-админка)
  • PostgreSQL 17
  • Docker Compose
  • Reverse proxy + SSL: Caddy / Nginx / Traefik

Быстрый старт (Dokploy / Docker)

  1. Скопируйте .env.example.env и задайте пароли + DOMAIN.
  2. В Dokploy создайте приложение типа Docker Compose, укажите этот репозиторий.
  3. Deploy — поднимутся сервисы app и postgres.
docker compose up -d --build

Панель: http://localhost:8080

Авторизация админа (из .env)

Переменная Значение по умолчанию
ADMIN_EMAIL admin@panel.local
ADMIN_PASSWORD Admin123!ChangeMe
ADMIN_NAME Administrator

При первом запуске админ создаётся автоматически из этих переменных.


Reverse proxy + SSL (Let's Encrypt)

Примеры лежат в deploy/. Сеть Docker: vpn-panel-net.

Что нужно до выпуска сертификата

  1. DNS: A (и при необходимости AAAA) запись DOMAIN → публичный IP сервера.
  2. Порты: 80 и 443 открыты на firewall / security group (TCP; для Caddy HTTP/3 ещё 443/udp).
  3. Домен в .env:
    DOMAIN=panel.example.com
    ACME_EMAIL=admin@example.com
    
  4. Не светить панель наружу на :8080 — только через proxy:
    docker compose -f docker-compose.yml -f deploy/compose.behind-proxy.yml up -d
    
    Либо в Dokploy / compose закомментируйте ports у app, оставьте доступ по внутренней сети app:8080.
  5. Прокси обязан передавать заголовки Host, X-Forwarded-Proto, X-Forwarded-For (уже есть в примерах).

Let's Encrypt не выпустит сертификат на localhost / приватный IP. Нужен реальный домен с публичным DNS.


Вариант A — Caddy (самый простой, SSL автоматом)

Caddy сам получает и продлевает сертификат.

  1. В deploy/caddy/Caddyfile домен берётся из {$DOMAIN:...} (или задайте в .env).
  2. Запуск вместе с панелью:
# из корня репозитория
docker compose \
  -f docker-compose.yml \
  -f deploy/compose.behind-proxy.yml \
  -f deploy/caddy/docker-compose.caddy.yml \
  up -d --build
  1. Откройте https://panel.example.com.

Файлы: deploy/caddy/Caddyfile, deploy/caddy/docker-compose.caddy.yml.


Вариант B — Nginx + Certbot

  1. Подставьте свой домен в deploy/nginx/nginx.conf (server_name и пути к сертификатам).
  2. Поднимите стек (сначала 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
  1. Выпустите сертификат:
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
  1. В deploy/nginx/nginx.conf:
    • раскомментируйте блок server { listen 443 ... };
    • включите return 301 https://$host$request_uri; в HTTP-сервере;
    • закомментируйте временный location / на порту 80 (оставьте только ACME).
  2. Перезагрузите 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.

  1. В Dokploy укажите домен для сервиса app.
  2. Либо добавьте 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).

  1. Не публикуйте порт 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/protocols — протоколы
  • /health — healthcheck
S
Description
No description provided
Readme
135 KiB
Languages
Go 66.1%
HTML 28.6%
CSS 5.1%
Dockerfile 0.2%