quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 8s
quality / changes (push) Successful in 8s
quality / web (push) Skipped
quality / docker-check (push) Skipped
quality / api (push) Successful in 1m20s
CD / quality (push) Successful in 1m31s
CD / publish (push) Successful in 2m4s
Co-authored-by: Cursor <cursoragent@cursor.com>
111 lines
7.1 KiB
Markdown
111 lines
7.1 KiB
Markdown
# Cloudflare Domain Manager
|
||
|
||
Wiki home — synced from repository on `main` when this file changes.
|
||
|
||
## UI
|
||
|
||
Design contract (Frame surface, ReUI kit): [`docs/ui-design-contract.md`](ui-design-contract.md)
|
||
|
||
## Overview
|
||
|
||
Manage Cloudflare zones, DNS records, domain groups, and TLS certificate expiry from a single UI.
|
||
|
||
## Configuration
|
||
|
||
| Variable | Description |
|
||
|----------|-------------|
|
||
| `CLOUDFLARE_API_TOKEN` | API token: Zone.DNS **и** для Worker — Account Workers Scripts Write + Workers KV Storage Write |
|
||
| `DATABASE_URL` | SQLite path (`sqlite:/data/app.db`) |
|
||
| `JWT_SECRET` | JWT signing secret |
|
||
| `ADMIN_USERNAME` | Admin username |
|
||
| `ADMIN_PASSWORD_HASH` | Argon2 hash (empty = dev `admin`/`admin`) |
|
||
| `LOG_LEVEL` | Уровень логов API (`info`, `debug`) |
|
||
| `HEALTH_CHECK_CRON` | Cron для health-check (default `0 */2 * * * *`). Переопределяется в **Настройки → Health-check**. |
|
||
| `HEALTH_DEGRADED_FAILURES` | Ошибок подряд до `degraded` (default `1`). То же в UI. |
|
||
| `HEALTH_DOWN_FAILURES` | Ошибок подряд до `down` (default `2`). То же в UI. |
|
||
| `HEALTH_SUCCESS_RECOVERIES` | Успехов подряд для recovery `CHECKING → HEALTHY` (default `2`). То же в UI. |
|
||
| `HEALTH_LATENCY_WARN_MS` | Латентность-порог для `degraded` (default `1000`). То же в UI. |
|
||
|
||
## Load balancing & health checks
|
||
|
||
Группа сервисов может иметь общий домен (`service_groups.domain`). Балансировка и
|
||
health-check работают на двух уровнях:
|
||
|
||
- **Общий домен группы** — A-записи формируются из IP сервисов группы; режим LB
|
||
и параметры health-check настраиваются в карточке группы.
|
||
- **Несколько FQDN на сервис** — через `service_bindings` один сервис может быть
|
||
привязан к нескольким hostname в разных зонах (уникальность
|
||
`(domain_id, service_id, hostname)`).
|
||
- **Привязка сервиса с multi-A** — режим LB и health-check настраиваются в карточке
|
||
сервиса для каждой привязки с несколькими IP; для IP задаются вес/приоритет.
|
||
- **Ноды** — first-class адреса сервиса (`nodes` + `binding_nodes`); IP-пулы
|
||
`service_ips` / `service_binding_ips` пишутся dual-write.
|
||
- **Change IP** — `POST /api/v1/service-bindings/:id/change-ip` (preview + PATCH DNS).
|
||
- **Change Domain** — перенос привязок между зонами `POST /api/v1/services/:id/change-domain`.
|
||
|
||
Режимы LB: `round_robin`, `failover`, `weighted`. В Cloudflare free `weighted`
|
||
работает как `round_robin` (одна A на IP). В A-пул попадает всё, кроме **Down**
|
||
(`unknown` / checking / Slow возвращаются в DNS на первой успешной пробе).
|
||
Бейдж Healthy — `UNHEALTHY → CHECKING → HEALTHY` после `HEALTH_SUCCESS_RECOVERIES`
|
||
(default 2). Пороги и cron движка задаются в
|
||
**Настройки → Health-check** (env — fallback, пока значения не сохранены в UI).
|
||
|
||
### Источники проб: Local, Cloudflare Worker, Globalping
|
||
|
||
На привязке/группе задаётся **мультивыбор** источников (`health_check_providers` JSON)
|
||
и **правило агрегации** (`health_check_aggregate`: `any` | `all` | `majority`).
|
||
Failover читает одну строку `ip_health_status` (агрегат). Журнал `health_probe_log` —
|
||
строка на каждый источник.
|
||
|
||
| | Local | Cloudflare Worker | Globalping |
|
||
|---|---|---|---|
|
||
| Кто пробирует | процесс API CFDM | Worker на edge (Cron Trigger) | [globalping.io](https://globalping.io) |
|
||
| Планировщик | глобальный cron CFDM | cron Worker + ingest KV | тот же cron CFDM (POST/GET measurements) |
|
||
| Пороги Slow/Down | Настройки → Health-check | те же | те же (по агрегату) |
|
||
| Результат | SQLite `ip_health_status` | та же SQLite + `colo` из KV | та же SQLite, colo = city/country пробы |
|
||
| Fallback | — | нет (не Local) | нет (нет токена / 429 / timeout = fail) |
|
||
|
||
**Агрегация (на сервисе/группе):**
|
||
|
||
- `any` — Down, если хотя бы один выбранный источник Down
|
||
- `all` — Down, только если все выбранные Down
|
||
- `majority` — Down по большинству (2 источника → оба; 3 → ≥2)
|
||
|
||
**Cloudflare в CFDM — это Worker**, не [Health Checks API](https://developers.cloudflare.com/api/resources/healthchecks).
|
||
Продукт Health Checks на Free-плане недоступен и **не используется**.
|
||
|
||
Worker **сам** опрашивает IP/порты/протоколы (TCP/HTTP, паттерн [UptimeFlare](https://github.com/lyc8503/UptimeFlare): `sockets.opened`, p-limit 5).
|
||
CFDM создаёт скрипт через Workers Scripts API, кладёт список целей в KV и читает результаты.
|
||
Публичный URL API не нужен. Если Worker/KV не готовы, cloudflare-цели **не** пробируются как Local.
|
||
|
||
Кнопка **Создать / обновить Worker** — **Настройки → Health-check**. Токен:
|
||
Account `Workers Scripts Write` + `Workers KV Storage Write`. Zone DNS недостаточно.
|
||
|
||
Free: 5 Cron Triggers на аккаунт; KV 1000 writes/сутки (интервал ≥ 2 мин);
|
||
≤ 48 целей за тик. Исходник: [`workers/health-probe/`](../workers/health-probe/).
|
||
|
||
**Globalping:** `POST /v1/measurements` → poll `GET` каждые ≥ 500 мс.
|
||
CFDM TCP → `type: ping` + `protocol: TCP`; HTTP → `type: http`, `target` = IP, `request.host` = hostname.
|
||
Токен: [dash.globalping.io/tokens](https://dash.globalping.io/tokens). Без токена 250 tests/hour, с токеном 500 + [credits](https://globalping.io/credits).
|
||
Локации (magic CSV, default `World`) и `limit` (1–10, default 3) — **Настройки → Health-check**.
|
||
Один measurement на уникальный origin (IP/порт/path) за тик.
|
||
|
||
Reconcile DNS запускается cron-задачей `health-check` после ingest KV и агрегации.
|
||
|
||
## Docker
|
||
|
||
Один alpine-контейнер (API + SPA + SQLite). Образы `cfdm` и `cloudflare-domain-manager` — один манифест.
|
||
|
||
```bash
|
||
docker pull git.shx.one/denozord/cfdm:latest
|
||
# drop-in для прежнего тега:
|
||
docker pull git.shx.one/denozord/cloudflare-domain-manager:latest
|
||
|
||
docker run -d -p 8080:8080 -v cfdm-data:/data \
|
||
-e CLOUDFLARE_API_TOKEN=... \
|
||
-e JWT_SECRET=... \
|
||
git.shx.one/denozord/cfdm:latest
|
||
```
|
||
|
||
Compose: корневой `docker-compose.yml` или `deploy/compose/docker-compose.example.yaml`. Сборка: `deploy/docker` (bake). Релизы: [`docs/releasing.md`](releasing.md).
|