Files
auth-portal/docs/deploy-traefik.md
T
DenozordecandCursor 0f1f89776b
quality / commitlint (push) Skipped
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
quality / web (push) Successful in 57s
quality / api (push) Failing after 30s
CD / quality (push) Failing after 1m36s
CD / publish (push) Skipped
feat(cdn): integrate CDN Manager into the application
- Updated environment configurations to include CDN Manager in the RETURN_TO_ALLOWLIST.
- Enhanced target app resolution to recognize CDN-related hosts.
- Added CDN Manager to the application switcher and updated relevant documentation.
- Included tests to verify the correct mapping of CDN hosts.

Co-authored-by: Cursor <[email protected]>
2026-09-04 14:11:34 +07:00

238 lines
9.1 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.
# Развёртывание Auth Portal + Traefik (один Docker Compose)
Один стек: **Traefik** (HTTPS, Let's Encrypt DNS-01 через Cloudflare) + **auth-portal** (API + SPA, SQLite).
Образ приложения: `git.shx.one/denozord/auth-portal` (тот же манифест публикуется как `authportal`)
Runtime: `node:22-alpine`, API + SPA + SQLite в одном процессе.
Пайплайн: [`.gitea/README.md`](../.gitea/README.md), [`docs/releasing.md`](releasing.md).
Публичный URL: `https://auth.shnt.top`
Compose: [`deploy/docker-compose.traefik.yml`](../deploy/docker-compose.traefik.yml)
Env-шаблон: [`deploy/env.traefik.example`](../deploy/env.traefik.example)
Документация Traefik: [Expose Docker](https://doc.traefik.io/traefik/expose/docker/basic/), [ACME DNS challenge](https://doc.traefik.io/traefik/https/acme/).
```
Internet → :80/:443 (Traefik) → auth-portal:8080
Cloudflare DNS TXT (ACME)
```
## Предпосылки
1. Зона домена в Cloudflare (например `shnt.top`).
2. Docker Engine + Compose plugin на VPS.
3. Свободные порты **80** и **443** на хосте (этот стек сам поднимает Traefik).
4. `docker login git.shx.one`.
> Если на сервере уже крутится другой Traefik на 80/443 — либо остановите его, либо смените `TRAEFIK_HTTP_PORT` / `TRAEFIK_HTTPS_PORT` (и проброс снаружи). Два Traefik на одних портах не запустятся.
---
## 1. Cloudflare: токен и DNS
### API-токен
[API Tokens → Create Token](https://dash.cloudflare.com/profile/api-tokens) — шаблон **Edit zone DNS** или Custom:
| Permission | Access |
|------------|--------|
| Zone → DNS | Edit |
| Zone → Zone | Read (желательно) |
**Zone Resources:** Include → Specific zone → ваша зона.
Токен → `CF_DNS_API_TOKEN` в `.env` стека. Не Global API Key, не в Git.
### DNS-запись
| Type | Name | Content | Proxy |
|------|------|---------|-------|
| `A` / `AAAA` | `auth` | IP VPS | **DNS only** (серое облако) |
```bash
dig +short auth.shnt.top A
```
Traefik для сертификата создаёт TXT `_acme-challenge.auth…` через Cloudflare API (HTTP-01 на :80 не обязателен).
---
## 2. Файлы на сервере
```bash
mkdir -p /opt/auth-portal/data
cd /opt/auth-portal
# из репозитория или curl:
# deploy/docker-compose.traefik.yml → docker-compose.yml
# deploy/env.traefik.example → .env
curl -fsSL -o docker-compose.yml \
https://git.shx.one/denozord/auth-portal/raw/branch/main/deploy/docker-compose.traefik.yml
curl -fsSL -o .env \
https://git.shx.one/denozord/auth-portal/raw/branch/main/deploy/env.traefik.example
nano .env # заполнить секреты
```
### Обязательные переменные в `.env`
| Переменная | Назначение |
|------------|------------|
| `CF_DNS_API_TOKEN` | Cloudflare token для ACME DNS-01 (env контейнера **Traefik**) |
| `LETSENCRYPT_EMAIL` | Email для Let's Encrypt |
| `JWT_SECRET` | HS256; тот же секрет в VPS Tracker / CFDM (`AUTH_JWT_SECRET`) |
| `ADMIN_PASSWORD` | Пароль bootstrap-админа (только при пустой БД) |
| `AUTH_DOMAIN` | Хост в Traefik rule, по умолчанию `auth.shnt.top` |
| `ISSUER` | `https://auth.shnt.top` — совпадает с `AUTH_ISSUER` приложений **и** OIDC issuer |
| `RETURN_TO_ALLOWLIST` | Origins SSO / App Switcher (`.shnt.top`, `https://dns.shnt.top`, …) |
| `OIDC_ISSUER` | Опционально; если пусто — берётся `ISSUER`. Публичный URL IdP для Technitium |
| `OIDC_RSA_PRIVATE_KEY` | Опционально PKCS8 PEM; иначе RSA-ключ в SQLite (`./data`) |
Опционально: `AUTH_IMAGE_TAG`, `TRAEFIK_IMAGE_TAG`, `TRAEFIK_HTTP_PORT`, `TRAEFIK_HTTPS_PORT`.
В production cookie refresh с флагом `Secure` — нужен HTTPS.
### Проверка OIDC после старта
```bash
curl -fsS https://auth.shnt.top/.well-known/openid-configuration | head
curl -fsS https://auth.shnt.top/.well-known/jwks.json | head
```
Админка: `https://auth.shnt.top/admin/oidc` — создать client для Technitium.
Полная инструкция SSO: [integrate-technitium.md](integrate-technitium.md).
---
## 3. Запуск (один compose)
```bash
cd /opt/auth-portal
docker login git.shx.one
docker compose pull
docker compose up -d
docker compose ps
docker compose logs -f --tail=100
```
Сервисы:
| Service | Контейнер | Роль |
|---------|-----------|------|
| `traefik` | `auth-portal-traefik` | :80 → HTTPS, ACME, роутинг |
| `app` | `auth-portal` | приложение на внутренней сети `auth-portal`, порт 8080 |
Первая выдача сертификата обычно 30–90 с.
### Проверка
```bash
curl -fsS https://auth.shnt.top/health
echo | openssl s_client -connect auth.shnt.top:443 -servername auth.shnt.top 2>/dev/null \
| openssl x509 -noout -issuer -dates -subject
docker compose logs traefik 2>&1 | grep -iE 'acme|certificate|cloudflare|error'
```
### Обновление / остановка
```bash
cd /opt/auth-portal
docker compose pull
docker compose up -d
# остановка (тома и ./data сохраняются)
docker compose down
# НЕ делайте down -v без бэкапа — сотрёт ACME (auth_portal_traefik_letsencrypt)
```
---
## Что внутри compose
- Сеть Docker **`auth-portal`** (внутренняя, создаётся стеком).
- Том **`auth_portal_traefik_letsencrypt`** → `/letsencrypt/acme.json`.
- Том хоста **`./data`** → SQLite портала.
- Labels на `app`: `Host(AUTH_DOMAIN)`, `entrypoints=websecure`, `certresolver=letsencrypt`, backend port `8080`.
- `CF_DNS_API_TOKEN` только у сервиса `traefik`.
Полный файл: [`deploy/docker-compose.traefik.yml`](../deploy/docker-compose.traefik.yml).
---
## Связка с приложениями
### JWT apps (CFDM / VPS / BGP / FW)
```env
AUTH_REQUIRED=true
AUTH_JWT_SECRET=<тот же JWT_SECRET>
AUTH_ISSUER=https://auth.shnt.top
AUTH_PORTAL_URL=https://auth.shnt.top
```
UI:
```env
VITE_AUTH_ENABLED=true
VITE_AUTH_PORTAL_URL=https://auth.shnt.top
```
См. [integrate-vps-tracker.md](integrate-vps-tracker.md), [integrate-cfdm.md](integrate-cfdm.md), [integrate-evobgp.md](integrate-evobgp.md), [integrate-evofirewall.md](integrate-evofirewall.md), [integrate-cdnmanager.md](integrate-cdnmanager.md).
Logout SSO: `https://auth.shnt.top/logout`.
### Technitium DNS (OIDC)
Portal — IdP; Technitium — RP. После `docker compose up`:
1. В `.env` добавьте origin DNS в `RETURN_TO_ALLOWLIST` (например `https://dns.shnt.top`).
2. `curl https://auth.shnt.top/.well-known/openid-configuration` — должен отвечать JSON.
3. Admin → OIDC-клиенты → redirect `https://dns.shnt.top/sso/callback`.
4. В Technitium SSO: Metadata = `https://auth.shnt.top/.well-known/openid-configuration`.
Важно: Technitium резолвит IdP **своим** DNS — A/AAAA для `auth.shnt.top` должна быть видна с DNS-сервера.
Детали: [integrate-technitium.md](integrate-technitium.md).
---
## Бэкап
```bash
# SQLite
cp /opt/auth-portal/data/app.db /opt/auth-portal/data/app.db.bak-$(date +%F)
# ACME
docker run --rm -v auth_portal_traefik_letsencrypt:/data -v "$PWD:/backup" alpine \
tar czf /backup/traefik-acme-$(date +%F).tgz -C /data .
```
Откат образа: в `.env` `AUTH_IMAGE_TAG=vX.Y.Z``docker compose pull && docker compose up -d`.
---
## Troubleshooting
| Симптом | Что проверить |
|---------|----------------|
| `Bind for 0.0.0.0:80/443 failed` | Другой Traefik/nginx занимает порты |
| ACME / нет HTTPS | `CF_DNS_API_TOKEN`, права Zone:DNS:Edit, логи `docker compose logs traefik` |
| `invalid credentials` | Не Global Key; зона в scope токена; пробелы в `.env` |
| Gateway Timeout / 404 | `docker compose ps`; labels; сеть `auth-portal` |
| Login OK, SSO в app падает | `JWT_SECRET` / `ISSUER` |
| `return_to` rejected | `RETURN_TO_ALLOWLIST` |
| Cookie не держится | HTTPS; `NODE_ENV=production` |
| Technitium «Failed to reach SSO provider» | A/AAAA `auth.*` в самом Technitium; `curl` с хоста DNS к discovery URL |
| OIDC discovery 404 | образ без OIDC; `ISSUER`/`OIDC_ISSUER` = публичный HTTPS URL; Traefik Host |
```bash
docker compose logs traefik 2>&1 | grep -iE 'acme|certificate|cloudflare|error'
docker compose logs app --tail=50
```
---
## Альтернатива: Docker CLI (без compose)
Если нужен ручной запуск — создайте сеть и два контейнера с теми же env/labels, что в compose. Предпочтительный путь — **один `docker compose up -d`** выше.