Files
CDNManager/docs/deploy-traefik.md
T
Denozordec dd3c378b5f
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
quality / web (push) Successful in 56s
quality / api (push) Successful in 41s
CD / quality (push) Successful in 1m47s
CD / publish (push) Successful in 33s
Update CDN Manager: Add integration for new settings route, enhance permissions for nodes and aliases, and improve Docker configuration documentation. Update UI components for better navigation and user experience.
2026-09-04 13:11:33 +07:00

163 lines
5.9 KiB
Markdown

# Развёртывание CDN Manager + Traefik (один Docker Compose)
Один стек: **Traefik** (HTTPS, Let's Encrypt DNS-01 через Cloudflare) + **cdnmanager** (API + SPA, SQLite).
| | |
|---|---|
| Образ | `git.shx.one/denozord/cdnmanager` (алиас `cdn-manager`) |
| Runtime | `node:22-alpine`, API + SPA + SQLite |
| Публичный URL | `https://cdn.shnt.top` |
| Compose | [`deploy/docker-compose.traefik.yml`](../deploy/docker-compose.traefik.yml) |
| Env-шаблон | [`deploy/env.traefik.example`](../deploy/env.traefik.example) |
| SSO | [`integrate-auth-portal.md`](./integrate-auth-portal.md) |
| Релизы | [`releasing.md`](./releasing.md) |
Документация 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) → cdnmanager: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`.
5. Для SSO — работающий auth-portal с тем же `JWT_SECRET` / `AUTH_ISSUER`.
> Если на сервере уже крутится другой Traefik на 80/443 — либо остановите его, либо смените `TRAEFIK_HTTP_PORT` / `TRAEFIK_HTTPS_PORT`. Два Traefik на одних портах не запустятся.
---
## 1. Cloudflare: токены и DNS
### Два разных токена
| Переменная | Куда | Назначение |
|------------|------|------------|
| `CF_DNS_API_TOKEN` | контейнер **Traefik** | ACME DNS-01 (TXT `_acme-challenge`) |
| `CLOUDFLARE_API_TOKEN` | контейнер **app** | Zone DNS Edit + Zone Read для sync флота |
Можно один токен с нужными правами продублировать в обе переменные, либо разделить (рекомендуется least privilege).
[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 → ваша зона. Не Global API Key, не в Git.
### DNS-запись
| Type | Name | Content | Proxy |
|------|------|---------|-------|
| `A` / `AAAA` | `cdn` | IP VPS | **DNS only** (серое облако) |
```bash
dig +short cdn.shnt.top A
```
Traefik для сертификата создаёт TXT `_acme-challenge.cdn…` через Cloudflare API.
---
## 2. Файлы на сервере
```bash
mkdir -p /opt/cdnmanager/data
cd /opt/cdnmanager
# из репозитория:
# cp deploy/docker-compose.traefik.yml docker-compose.yml
# cp deploy/env.traefik.example .env
curl -fsSL -o docker-compose.yml \
https://git.shx.one/denozord/CDNManager/raw/branch/main/deploy/docker-compose.traefik.yml
curl -fsSL -o .env \
https://git.shx.one/denozord/CDNManager/raw/branch/main/deploy/env.traefik.example
nano .env # заполнить секреты
```
### Обязательные переменные в `.env`
| Переменная | Назначение |
|------------|------------|
| `CF_DNS_API_TOKEN` | Cloudflare token для ACME DNS-01 (Traefik) |
| `LETSENCRYPT_EMAIL` | Email для Let's Encrypt |
| `CDN_DOMAIN` | Хост в Traefik rule, по умолчанию `cdn.shnt.top` |
| `CLOUDFLARE_API_TOKEN` | Token приложения для DNS sync |
| `AUTH_JWT_SECRET` / `JWT_SECRET` | = `JWT_SECRET` auth-portal (HS256) |
| `AUTH_ISSUER` | `https://auth.shnt.top` |
| `AUTH_PORTAL_URL` | URL UI портала |
Опционально: `CDN_IMAGE_TAG`, `TRAEFIK_IMAGE_TAG`, `TRAEFIK_HTTP_PORT`, `TRAEFIK_HTTPS_PORT`, `AUTH_AUDIT_INGEST_SECRET`, `AUTH_REQUIRED` (default `true`).
На стороне портала добавьте origin в `RETURN_TO_ALLOWLIST` (`https://cdn.shnt.top`) и выдайте app **`cdn`** + права `cdn:*`. App Switcher URL: тот же origin.
---
## 3. Запуск
```bash
cd /opt/cdnmanager
docker login git.shx.one
docker compose pull
docker compose up -d
docker compose ps
docker compose logs -f --tail=100
```
Проверка:
```bash
curl -fsS https://cdn.shnt.top/health
# {"status":"ok",…}
```
Откройте `https://cdn.shnt.top` → редирект на auth-portal → handoff на `/auth/callback`.
---
## 4. Обновление
```bash
cd /opt/cdnmanager
docker compose pull
docker compose up -d
```
Миграции SQLite применяются при старте API. Volume `./data` сохраняется.
---
## 5. Остановка
```bash
docker compose down
# с удалением ACME volume (сертификаты перевыпустятся):
# docker compose down -v
```
Данные SQLite в `./data` на хосте остаются, пока не удалите каталог.
---
## Troubleshooting
| Симптом | Причина |
|---------|---------|
| Порт 80/443 занят | другой Traefik/nginx; смените порты или хост |
| ACME timeout | `CF_DNS_API_TOKEN` без DNS Edit; Cloudflare Proxy на A-записи (нужен DNS only) |
| SSO loop / 401 | разный `AUTH_JWT_SECRET` / `AUTH_ISSUER` vs portal |
| 403 «Нет доступа» | у пользователя нет app `cdn` |
| return_to rejected | `https://cdn.shnt.top` не в `RETURN_TO_ALLOWLIST` портала |
| Sync CF падает | пустой/`CLOUDFLARE_API_TOKEN` без Zone DNS Edit |
Без Traefik (plain `docker run` / простой Compose): [`deploy-docker.md`](./deploy-docker.md).