Регистрация mm в каталоге приложений, permissions mm:*, target-app и docs. Co-authored-by: Cursor <cursoragent@cursor.com>
9.2 KiB
Развёртывание 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)
Предпосылки
- Зона домена в Cloudflare (например
shnt.top). - Docker Engine + Compose plugin на VPS.
- Свободные порты 80 и 443 на хосте (этот стек сам поднимает Traefik).
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 port8080. 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:
- В
.envдобавьте origin DNS вRETURN_TO_ALLOWLIST(напримерhttps://dns.shnt.top). curl https://auth.shnt.top/.well-known/openid-configuration— должен отвечать JSON.- Admin → OIDC-клиенты → redirect
https://dns.shnt.top/sso/callback. - В 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.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 |
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 выше.