1a26403afb
Telegram Login Widget в браузере требует именно порт 443 — его CSP frame-ancestors от oauth.telegram.org не учитывает порт домена и всегда подразумевает дефолтный порт схемы, поэтому на 8443 виджет рендерился, но iframe блокировался как cross-origin. VPN-нода, ранее занимавшая 443 на dev VPS, перенесена на другой порт, так что конфликта больше нет. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
107 lines
6.8 KiB
Markdown
107 lines
6.8 KiB
Markdown
# Netrunner Control Plane — разработка и деплой
|
||
|
||
## Локальная разработка (fully-dockerized, hot-reload)
|
||
|
||
Весь стек поднимается одной командой — Postgres, Redis и приложение с
|
||
автоперекомпиляцией (`cargo-watch`). Локальный хостовый Rust не нужен.
|
||
|
||
```bash
|
||
make dev # db + redis + app (http://localhost:8080)
|
||
make dev-logs # логи приложения
|
||
make dev-down # остановить (тома/кеши сохраняются)
|
||
make clean # снести стек вместе с БД и кешем компиляции
|
||
```
|
||
|
||
- Конфиг — `.env.dev` (бот выключен: `BOT_ENABLED=false`, реальный токен Telegram не нужен).
|
||
- Миграции накатываются автоматически при старте `app` (`cargo run -- --migrate`).
|
||
- Healthcheck: `GET /health` (liveness), `GET /health/ready` (readiness, пингует БД).
|
||
- Первый запуск компилирует всё (несколько минут); дальше — инкрементально через тома `target_cache` / `cargo_registry`.
|
||
|
||
Качество кода (то же, что гоняет CI):
|
||
|
||
```bash
|
||
make fmt # форматирование
|
||
make lint # clippy -D warnings
|
||
make test # тесты (нужен Postgres + DATABASE_URL)
|
||
```
|
||
|
||
## Пайплайн (CI/CD)
|
||
|
||
Три воркфлоу в `.github/workflows/`:
|
||
|
||
| Workflow | Триггер | Что делает |
|
||
|----------|---------|------------|
|
||
| `ci.yml` | PR, push в `main` | `fmt --check`, `clippy -D warnings`, тесты на эфемерном Postgres |
|
||
| `build.yml` | push в `main`, тег `v*`, вручную | Собирает Docker-образ (cargo-chef + GHA-кеш слоёв) и пушит в GHCR |
|
||
| `deploy.yml` → `deploy-dev` | **авто**, сразу после успешного `build.yml` на `main` | SSH на dev VPS: pull образа `latest` → миграции → перезапуск (`docker-compose.dev-remote.yml`) |
|
||
| `deploy.yml` → `deploy-prod` | **только вручную** (Actions → Run workflow) | SSH на прод VPS: pull образа → миграции → перезапуск (`docker-compose.prod.yml`) |
|
||
|
||
Компиляция Rust происходит **в GitHub Actions**, а не на машине разработчика и
|
||
не на VPS. Сервер только тянет готовый образ — деплой занимает секунды.
|
||
Сборка не требует доступа к БД (sqlx работает в offline-режиме).
|
||
|
||
### Ручной деплой (прод)
|
||
|
||
GitHub → **Actions** → **Deploy** → **Run workflow**
|
||
(можно указать тег образа, по умолчанию `latest`).
|
||
|
||
Dev-окружение отдельного ручного шага не требует — обновляется само после каждого
|
||
успешного билда `main`.
|
||
|
||
### Секреты GitHub (Settings → Secrets → Actions)
|
||
|
||
- `VPS_IP` / `SSH_PRIVATE_KEY` — прод-сервер
|
||
- `DEV_VPS_IP` / `DEV_SSH_PRIVATE_KEY` — dev-сервер (`45.76.161.137`, DNS
|
||
`dev.netrunner-vpn.com`; на нём же по аналогии деплоится dev-версия
|
||
`netrunner-landing`, см. её `DEPLOYMENT`/README). Домен, а не голый IP,
|
||
используется во всех browser-facing URL (`WEB_APP_BASE_URL`,
|
||
`CORS_ALLOWED_ORIGINS` и т.п.) — Telegram Login Widget не работает на IP
|
||
(`/setdomain` в BotFather принимает только доменное имя).
|
||
- `GHCR_TOKEN` — токен GHCR с правом `read:packages` (для pull на VPS, обоих)
|
||
|
||
`GITHUB_TOKEN` для push в GHCR выдаётся автоматически.
|
||
|
||
Отдельно на самом dev VPS (не GitHub-секрет, а переменная в `.env` рядом с
|
||
`docker-compose.dev-remote.yml`) — `CF_API_TOKEN`: Cloudflare-токен для Caddy
|
||
(DNS-01 challenge, см. ниже), шаблон "Edit zone DNS", ограниченный зоной
|
||
`netrunner-vpn.com`. Не Global API Key.
|
||
|
||
### Что должно лежать на VPS (`/root/netrunner-core`)
|
||
|
||
- `docker-compose.prod.yml`
|
||
- `.env` (прод-секреты; `APP_ENV=production`, `BOT_ENABLED=true`, реальные токены)
|
||
- `keys/netrunner_master_ed25519[.pub]` — мастер-ключ для провижининга нод
|
||
- конфиги мониторинга: `prometheus.yml`, `loki-config.yml`, `promtail-config.yml`, `grafana-datasources.yml`
|
||
|
||
Прод-стек (`docker-compose.prod.yml`) поднимает: `migrate` (one-shot миграции) →
|
||
`app` (с healthcheck) + `db` + `redis` + Prometheus/Loki/Promtail/Grafana.
|
||
|
||
### Что должно лежать на dev VPS (`/root/netrunner-core`)
|
||
|
||
- `docker-compose.dev-remote.yml`, `Dockerfile.caddy`, `Caddyfile.dev` (все три
|
||
синкает CI при каждом `deploy-dev`, руками копировать не нужно)
|
||
- `.env` (см. [`.env.dev-remote.example`](.env.dev-remote.example) — свои
|
||
`JWT_SECRET`/`ARGON_SALT`/`DB_PASSWORD`, `CF_API_TOKEN`,
|
||
`CORS_ALLOWED_ORIGINS`/`CSRF_ALLOWED_ORIGINS` включают origin dev-лендинга и
|
||
Caddy-порта на этом же хосте)
|
||
- `keys/netrunner_master_ed25519[.pub]` — свой мастер-ключ, отдельный от прода
|
||
|
||
Dev-стек: `migrate` → `app` (порт `8080`, обычный HTTP, без TLS) + `db` + `redis`
|
||
+ `caddy` (порт `443`, реальный TLS через DNS-01/Cloudflare — см.
|
||
[`Caddyfile.dev`](Caddyfile.dev)). Caddy здесь нужен по двум причинам: Telegram
|
||
Web Apps (кнопки бота "Личный Кабинет"/"Тарифы"/"Синдикат") требуют `https://`
|
||
URL, а Telegram Login Widget в обычном браузере требует именно порт 443 (его
|
||
CSP `frame-ancestors` не учитывает порт и всегда подразумевает дефолтный порт
|
||
схемы). Порт 80 на этом VPS закрыт — обычный HTTP-01 challenge не проходит,
|
||
поэтому DNS-01. Все браузерные auth-флоу (бот, лендинг) должны идти через
|
||
Caddy на 443, не напрямую в `:8080` — `COOKIE_SECURE=true` (как в проде), и
|
||
Secure-cookie по голому HTTP на `:8080` браузер по-прежнему отбросит.
|
||
|
||
### Локальная сборка образа (фолбэк, обычно не нужно)
|
||
|
||
```bash
|
||
make build-image # docker build -t $IMAGE .
|
||
make push-image # docker push $IMAGE
|
||
# или ./deploy.sh — собрать и запушить разом
|
||
```
|