Files
auth-portal/docs/deploy-traefik.md
T
DenozordecandCursor fd7d9fd13c
quality / commitlint (push) Skipped
quality / changes (push) Successful in 7s
quality / docker-check (push) Skipped
quality / web (push) Successful in 40s
quality / api (push) Successful in 36s
CD / quality (push) Successful in 1m37s
CD / publish (push) Successful in 1m40s
feat(apps): добавить MikrotikManager app id mm
Регистрация mm в каталоге приложений, permissions mm:*, target-app и docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 20:38:27 +07:00

9.2 KiB
Raw Blame History

Развёртывание 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, docs/releasing.md.
Публичный URL: https://auth.shnt.top
Compose: deploy/docker-compose.traefik.yml
Env-шаблон: deploy/env.traefik.example

Документация Traefik: Expose Docker, ACME DNS challenge.

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 — шаблон 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 (серое облако)
dig +short auth.shnt.top A

Traefik для сертификата создаёт TXT _acme-challenge.auth… через Cloudflare API (HTTP-01 на :80 не обязателен).


2. Файлы на сервере

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 после старта

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.


3. Запуск (один compose)

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 с.

Проверка

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'

Обновление / остановка

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.


Связка с приложениями

JWT apps (CFDM / VPS / BGP / FW)

AUTH_REQUIRED=true
AUTH_JWT_SECRET=<тот же JWT_SECRET>
AUTH_ISSUER=https://auth.shnt.top
AUTH_PORTAL_URL=https://auth.shnt.top

UI:

VITE_AUTH_ENABLED=true
VITE_AUTH_PORTAL_URL=https://auth.shnt.top

См. integrate-vps-tracker.md, integrate-cfdm.md, integrate-evobgp.md, integrate-evofirewall.md, integrate-cdnmanager.md, integrate-mikrotikmanager.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.


Бэкап

# 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.Zdocker 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
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 выше.