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>
6.8 KiB
Netrunner Control Plane — разработка и деплой
Локальная разработка (fully-dockerized, hot-reload)
Весь стек поднимается одной командой — Postgres, Redis и приложение с
автоперекомпиляцией (cargo-watch). Локальный хостовый Rust не нужен.
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):
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, DNSdev.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— свои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). Caddy здесь нужен по двум причинам: Telegram Web Apps (кнопки бота "Личный Кабинет"/"Тарифы"/"Синдикат") требуютhttps://URL, а Telegram Login Widget в обычном браузере требует именно порт 443 (его CSPframe-ancestorsне учитывает порт и всегда подразумевает дефолтный порт схемы). Порт 80 на этом VPS закрыт — обычный HTTP-01 challenge не проходит, поэтому DNS-01. Все браузерные auth-флоу (бот, лендинг) должны идти через Caddy на 443, не напрямую в:8080—COOKIE_SECURE=true(как в проде), и Secure-cookie по голому HTTP на:8080браузер по-прежнему отбросит.
Локальная сборка образа (фолбэк, обычно не нужно)
make build-image # docker build -t $IMAGE .
make push-image # docker push $IMAGE
# или ./deploy.sh — собрать и запушить разом