Files
panel-vpn/README.md
T

240 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. В Dokploy создайте **Docker Compose** приложение из этого репозитория.
2. Задайте Environment Variables (`.env` в git не лежит):
```env
APP_SECRET=long-random-secret
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=strong-password
POSTGRES_PASSWORD=strong-db-password
```
3. Deploy. Домен в Dokploy → сервис **`app`**, порт **`8080`** (не postgres).
4. Если **Bad Gateway**: смотрите логи `app` — чаще всего падение из‑за БД или домен смотрит не на тот порт.
```bash
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](https://docs.rw/install/remnawave-node)).
### Чем удобнее
| Remnawave Node | VPN Panel |
|---|---|
| Docker вручную + вставить compose | **Авто по SSH**: host/user/пароль (или ключ) → панель ставит Docker + агент |
| Или вручную | **Ручной режим** — тот же compose, если SSH недоступен |
### Как добавить ноду
1. Админка → **Ноды****Добавить ноду**
2. Укажите имя, IP/хост, SSH (`root` + пароль или ключ), порт API ноды (по умолчанию `2222`)
3. Режим:
- **Авто по SSH** — мастер подключается, ставит Docker (если нет), заливает бинарник `vpn-node`, поднимает `docker compose`
- **Вручную** — скопируйте `docker-compose.yml` и бинарник `/app/bin/vpn-node` на сервер
4. На firewall ноды откройте `NODE_PORT` **только** для IP панели
5. Нажмите **Проверить 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`.
### Что нужно до выпуска сертификата
1. **DNS**: A (и при необходимости AAAA) запись `DOMAIN` → публичный IP сервера.
2. **Порты**: `80` и `443` открыты на firewall / security group (TCP; для Caddy HTTP/3 ещё `443/udp`).
3. **Домен в `.env`**:
```env
DOMAIN=panel.example.com
ACME_EMAIL=admin@example.com
```
4. **Не светить панель наружу на `:8080`** — только через proxy:
```bash
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. Запуск вместе с панелью:
```bash
# из корня репозитория
docker compose \
-f docker-compose.yml \
-f deploy/compose.behind-proxy.yml \
-f deploy/caddy/docker-compose.caddy.yml \
up -d --build
```
3. Откройте `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):
```bash
docker compose \
-f docker-compose.yml \
-f deploy/compose.behind-proxy.yml \
-f deploy/nginx/docker-compose.nginx.yml \
up -d --build
```
3. Выпустите сертификат:
```bash
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
```
4. В `deploy/nginx/nginx.conf`:
- раскомментируйте блок `server { listen 443 ... }`;
- включите `return 301 https://$host$request_uri;` в HTTP-сервере;
- закомментируйте временный `location /` на порту 80 (оставьте только ACME).
5. Перезагрузите nginx:
```bash
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 из репозитория
```bash
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`):
```yaml
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`).
3. Не публикуйте порт `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
```bash
# нужен локальный Postgres 17 и .env с POSTGRES_HOST=localhost
go mod tidy
go run ./cmd/server
```
## Эндпоинты
- `/` — главная
- `/login` — вход
- `/admin` — дашборд
- `/admin/nodes` — ноды
- `/admin/protocols` — протоколы
- `/health` — healthcheck