Add reverse proxy SSL guides for Caddy, Nginx, and Traefik.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,12 @@ APP_PORT=8080
|
|||||||
APP_SECRET=change-me-to-a-long-random-secret-key
|
APP_SECRET=change-me-to-a-long-random-secret-key
|
||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
|
|
||||||
|
# Public domain (reverse proxy / SSL)
|
||||||
|
DOMAIN=panel.example.com
|
||||||
|
ACME_EMAIL=admin@example.com
|
||||||
|
# Dokploy Traefik cert resolver name (часто letsencrypt)
|
||||||
|
TRAEFIK_CERT_RESOLVER=letsencrypt
|
||||||
|
|
||||||
# Admin authorization
|
# Admin authorization
|
||||||
ADMIN_EMAIL=admin@panel.local
|
ADMIN_EMAIL=admin@panel.local
|
||||||
ADMIN_PASSWORD=Admin123!ChangeMe
|
ADMIN_PASSWORD=Admin123!ChangeMe
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
- Go 1.23 (веб-админка)
|
- Go 1.23 (веб-админка)
|
||||||
- PostgreSQL 17
|
- PostgreSQL 17
|
||||||
- Docker Compose
|
- Docker Compose
|
||||||
|
- Reverse proxy + SSL: **Caddy** / **Nginx** / **Traefik**
|
||||||
|
|
||||||
## Быстрый старт (Dokploy / Docker)
|
## Быстрый старт (Dokploy / Docker)
|
||||||
|
|
||||||
1. Скопируйте `.env.example` → `.env` и задайте пароли.
|
1. Скопируйте `.env.example` → `.env` и задайте пароли + `DOMAIN`.
|
||||||
2. В Dokploy создайте приложение типа **Docker Compose**, укажите этот репозиторий.
|
2. В Dokploy создайте приложение типа **Docker Compose**, укажите этот репозиторий.
|
||||||
3. Deploy — поднимутся сервисы `app` и `postgres`.
|
3. Deploy — поднимутся сервисы `app` и `postgres`.
|
||||||
|
|
||||||
@@ -30,6 +31,151 @@ docker compose up -d --build
|
|||||||
|
|
||||||
При первом запуске админ создаётся автоматически из этих переменных.
|
При первом запуске админ создаётся автоматически из этих переменных.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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)
|
## Протоколы (seed)
|
||||||
|
|
||||||
WireGuard, OpenVPN, VLESS, VMess, Trojan, Shadowsocks, Hysteria2 — можно включать/выключать в админке.
|
WireGuard, OpenVPN, VLESS, VMess, Trojan, Shadowsocks, Hysteria2 — можно включать/выключать в админке.
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{$DOMAIN:panel.example.com} {
|
||||||
|
encode gzip zstd
|
||||||
|
|
||||||
|
# Healthcheck без редиректов наружу
|
||||||
|
handle /health {
|
||||||
|
reverse_proxy app:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy app:8080 {
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
header_up X-Forwarded-For {remote_host}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
header_up Host {host}
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-Content-Type-Options nosniff
|
||||||
|
X-Frame-Options DENY
|
||||||
|
Referrer-Policy strict-origin-when-cross-origin
|
||||||
|
-Server
|
||||||
|
}
|
||||||
|
|
||||||
|
log {
|
||||||
|
output stdout
|
||||||
|
format console
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Пример: Caddy как reverse proxy с авто-SSL (Let's Encrypt)
|
||||||
|
#
|
||||||
|
# Запуск вместе с панелью:
|
||||||
|
# docker compose -f docker-compose.yml -f deploy/caddy/docker-compose.caddy.yml up -d --build
|
||||||
|
#
|
||||||
|
# Перед стартом:
|
||||||
|
# 1. DNS A/AAAA домена → IP сервера
|
||||||
|
# 2. Открыты порты 80 и 443
|
||||||
|
# 3. В .env задайте DOMAIN=panel.example.com
|
||||||
|
# 4. В docker-compose панели лучше НЕ публиковать 8080 наружу (или оставить только localhost)
|
||||||
|
|
||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
image: caddy:2-alpine
|
||||||
|
container_name: vpn-panel-caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp"
|
||||||
|
environment:
|
||||||
|
DOMAIN: ${DOMAIN:-panel.example.com}
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
networks:
|
||||||
|
- vpn-net
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
vpn-net:
|
||||||
|
name: vpn-panel-net
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Override: не публиковать :8080 наружу (только через reverse proxy).
|
||||||
|
# Нужен Docker Compose v2.24+ (поддержка !override).
|
||||||
|
#
|
||||||
|
# docker compose -f docker-compose.yml -f deploy/compose.behind-proxy.yml up -d
|
||||||
|
#
|
||||||
|
# Если !override не поддерживается — в docker-compose.yml закомментируйте
|
||||||
|
# блок ports у сервиса app и оставьте только expose: ["8080"].
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
ports: !override []
|
||||||
|
expose:
|
||||||
|
- "8080"
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Пример: Nginx + Certbot (Let's Encrypt)
|
||||||
|
#
|
||||||
|
# Запуск:
|
||||||
|
# docker compose -f docker-compose.yml -f deploy/nginx/docker-compose.nginx.yml up -d --build
|
||||||
|
#
|
||||||
|
# Первый выпуск сертификата (после того как DNS уже указывает на сервер):
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# Затем раскомментируйте HTTPS-server в nginx.conf и:
|
||||||
|
# docker compose -f docker-compose.yml -f deploy/nginx/docker-compose.nginx.yml up -d
|
||||||
|
#
|
||||||
|
# Обновление сертификатов (cron / systemd timer на хосте):
|
||||||
|
# docker compose -f deploy/nginx/docker-compose.nginx.yml run --rm certbot renew
|
||||||
|
# docker compose -f deploy/nginx/docker-compose.nginx.yml exec nginx nginx -s reload
|
||||||
|
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.27-alpine
|
||||||
|
container_name: vpn-panel-nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
- ./snippets:/etc/nginx/snippets:ro
|
||||||
|
- certbot_www:/var/www/certbot:ro
|
||||||
|
- certbot_certs:/etc/letsencrypt:ro
|
||||||
|
networks:
|
||||||
|
- vpn-net
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
certbot:
|
||||||
|
image: certbot/certbot:latest
|
||||||
|
container_name: vpn-panel-certbot
|
||||||
|
volumes:
|
||||||
|
- certbot_www:/var/www/certbot
|
||||||
|
- certbot_certs:/etc/letsencrypt
|
||||||
|
entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot --quiet; sleep 12h & wait $${!}; done"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
certbot_www:
|
||||||
|
certbot_certs:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
vpn-net:
|
||||||
|
name: vpn-panel-net
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Замените panel.example.com на свой DOMAIN.
|
||||||
|
# После выпуска сертификата Certbot раскомментируйте блок HTTPS ниже.
|
||||||
|
|
||||||
|
upstream vpn_panel {
|
||||||
|
server app:8080;
|
||||||
|
keepalive 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name panel.example.com;
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Пока сертификата нет — проксируем HTTP.
|
||||||
|
# После выпуска SSL лучше редиректить на HTTPS (раскомментируйте return и закомментируйте location /).
|
||||||
|
# return 301 https://$host$request_uri;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://vpn_panel;
|
||||||
|
include /etc/nginx/snippets/proxy_params.conf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- HTTPS (раскомментировать после certbot certonly) ---
|
||||||
|
# server {
|
||||||
|
# listen 443 ssl http2;
|
||||||
|
# listen [::]:443 ssl http2;
|
||||||
|
# server_name panel.example.com;
|
||||||
|
#
|
||||||
|
# ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
|
||||||
|
# ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;
|
||||||
|
# include /etc/nginx/snippets/ssl_params.conf;
|
||||||
|
#
|
||||||
|
# location / {
|
||||||
|
# proxy_pass http://vpn_panel;
|
||||||
|
# include /etc/nginx/snippets/proxy_params.conf;
|
||||||
|
# }
|
||||||
|
# }
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header Connection "";
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_buffering on;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
# Modern Mozilla intermediate
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||||
|
add_header X-Content-Type-Options nosniff always;
|
||||||
|
add_header X-Frame-Options DENY always;
|
||||||
|
add_header Referrer-Policy strict-origin-when-cross-origin always;
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Пример: Traefik v3 + Let's Encrypt (HTTP challenge)
|
||||||
|
#
|
||||||
|
# Запуск:
|
||||||
|
# docker compose -f docker-compose.yml -f deploy/traefik/docker-compose.traefik.yml up -d --build
|
||||||
|
#
|
||||||
|
# В .env обязательны:
|
||||||
|
# DOMAIN=panel.example.com
|
||||||
|
# ACME_EMAIL=admin@example.com
|
||||||
|
#
|
||||||
|
# Если используете Dokploy — у него уже есть Traefik.
|
||||||
|
# Тогда НЕ поднимайте этот compose, а только повесьте labels на сервис app
|
||||||
|
# (см. labels.example.yml / README).
|
||||||
|
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: traefik:v3.3
|
||||||
|
container_name: vpn-panel-traefik
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- --providers.docker=true
|
||||||
|
- --providers.docker.exposedbydefault=false
|
||||||
|
- --providers.docker.network=vpn-panel-net
|
||||||
|
- --entrypoints.web.address=:80
|
||||||
|
- --entrypoints.websecure.address=:443
|
||||||
|
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||||
|
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||||
|
- --certificatesresolvers.le.acme.httpchallenge=true
|
||||||
|
- --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
|
||||||
|
- --certificatesresolvers.le.acme.email=${ACME_EMAIL:-admin@example.com}
|
||||||
|
- --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
|
||||||
|
- --api.dashboard=false
|
||||||
|
- --log.level=INFO
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- traefik_letsencrypt:/letsencrypt
|
||||||
|
networks:
|
||||||
|
- vpn-net
|
||||||
|
|
||||||
|
app:
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=vpn-panel-net
|
||||||
|
- traefik.http.routers.vpn-panel.rule=Host(`${DOMAIN:-panel.example.com}`)
|
||||||
|
- traefik.http.routers.vpn-panel.entrypoints=websecure
|
||||||
|
- traefik.http.routers.vpn-panel.tls=true
|
||||||
|
- traefik.http.routers.vpn-panel.tls.certresolver=le
|
||||||
|
- traefik.http.services.vpn-panel.loadbalancer.server.port=8080
|
||||||
|
- traefik.http.middlewares.vpn-panel-headers.headers.stsSeconds=31536000
|
||||||
|
- traefik.http.middlewares.vpn-panel-headers.headers.stsIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.vpn-panel-headers.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.vpn-panel-headers.headers.frameDeny=true
|
||||||
|
- traefik.http.routers.vpn-panel.middlewares=vpn-panel-headers
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
traefik_letsencrypt:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
vpn-net:
|
||||||
|
name: vpn-panel-net
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Labels для сервиса app, если Traefik уже запущен (Dokploy / общий Traefik).
|
||||||
|
# Скопируйте в docker-compose.yml под services.app:
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.vpn-panel.rule=Host(`${DOMAIN:-panel.example.com}`)
|
||||||
|
- traefik.http.routers.vpn-panel.entrypoints=websecure
|
||||||
|
- traefik.http.routers.vpn-panel.tls=true
|
||||||
|
- traefik.http.routers.vpn-panel.tls.certresolver=${TRAEFIK_CERT_RESOLVER:-letsencrypt}
|
||||||
|
- traefik.http.services.vpn-panel.loadbalancer.server.port=8080
|
||||||
@@ -41,4 +41,5 @@ volumes:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
vpn-net:
|
vpn-net:
|
||||||
|
name: vpn-panel-net
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
Reference in New Issue
Block a user