Files
EvoBGP/docs/remote-speakers.md
T
DenozordecandCursor 3723ba7ed1
quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / openapi (push) Failing after 21s
quality / web (push) Successful in 55s
quality / go (push) Successful in 1m2s
quality / bird2 (push) Successful in 16s
CD / quality (push) Failing after 2m49s
CD / publish (push) Skipped
feat(httpapi): return replica docker install commands on speaker create
После создания реплики 201 отдаёт agent_secret, node_token и install.docker_commands (bird2 + agent + Traefik DNS-01). UI показывает шаг установки вместо закрытия диалога, чтобы секрет больше не терялся.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-21 13:51:06 +07:00

8.5 KiB
Raw Blame History

Удалённые BGP-спикеры (Remnawave-style)

Runbook для реплик bird2 + evobgp-agent на отдельных VPS. Control plane (evobgp-all) инициирует доставку после module_refreshdeploy_apply; реплика не собирает префиксы сама.

Модель

Remnawave EvoBGP
Panel → Node:PORT CP POST https://AGENT_DOMAIN/v1/agent/sync
SECRET_KEY agent_secret (Bearer)
Copy compose Web UI → после создания реплики: docker-команды (bird2 + agent + Traefik)
Push Xray JSON Wake-up → pull signed bundle → verify Ed25519 → apply

Подробнее: architecture.md.

Быстрый старт

  1. CP (microvps-full): зафиксируйте EVOBGP_BUNDLE_SEED_HEX (32 байта hex) — стабильный ключ подписи бандлов. EVOBGP_NODE_DISPATCH_ENABLED=1.
  2. Cloudflare: A/AAAA AGENT_DOMAIN → публичный IP VPS реплики, режим DNS only (серый облачко), как Web UI в quickstart.md.
  3. Web UI → Сеть → Спикеры: создайте спикер role=replica. Укажите домен агента, IP ноды, BGP source (по умолчанию = IP ноды), email Let's Encrypt, Cloudflare DNS API token (Zone:DNS:Edit), IP панели (CIDR whitelist).
  4. В диалоге «Установка на ноду» скопируйте docker-команды (секреты agent_secret и node_token показываются один раз). Репозиторий EvoBGP на ноде не нужен: команда пишет /opt/evobgp-speaker/docker-compose.yaml (bird2 + agent + Traefik DNS-01) и делает docker compose up -d.
  5. Если образы из приватного реестра — на VPS заранее docker login git.shx.one.
  6. Не делайте docker compose down -v на реплике без бэкапа тома evobgp_speaker_traefik_letsencrypt (acme.json).

Эталонный compose в репозитории (lab / ручной запуск): docker-compose.remote-speaker.yaml. Prod-установка с панели — paste из UI.

HTTPS на ноде (DNS-01)

Сертификат не выписывает Control Plane и не Cloudflare Origin CA. Его выпускает Traefik на самой реплике (evobgp-edge), resolver letsencrypt, ACME DNS-01 через Cloudflare.

Кто Что делает
Оператор DNS only: AGENT_DOMAIN → IP VPS
Traefik на ноде dnschallenge=true, provider=cloudflare
CF_DNS_API_TOKEN В env реплики (вшит в команду из UI). Traefik создаёт TXT _acme-challenge.<AGENT_DOMAIN>
Let's Encrypt Проверяет TXT, отдаёт сертификат
Том evobgp_speaker_traefik_letsencrypt/letsencrypt/acme.json
CP → нода https://AGENT_DOMAIN/v1/agent/* + Authorization: Bearer <agent_secret> + Traefik ipallowlist (PANEL_IP_WHITELIST)

Порты:

Порт Кто Зачем
443 IP CP (PANEL_IP_WHITELIST) HTTPS dispatch, health, GET /v1/agent/bird/protocols
179 BGP peers Data plane
80 любой редирект HTTP → HTTPS (не HTTP-01 ACME)

DNS-01 ходит исходящим к Cloudflare API и Let's Encrypt; inbound 80 для выпуска сертификата не нужен. Agent слушает :8443 только во внутренней docker-сети; снаружи — Traefik 443.

Токен Cloudflare для панели (evobgp-edge на CP) в процесс API не проброшен — для реплики его задают в форме создания.

Profile plain в файле репозитория — только lab без Traefik.

Compose-профили (файл в репозитории)

Profile Состав
production bird2 (host) + agent + Traefik LE
plain bird2 + agent на хосте без Traefik (только lab)
fallback + sync-bundle polling (scripts/sync-bundle.sh)

Команда из UI — самодостаточный yaml без profiles (эквивалент production).

Подготовка VPS

bird2network_mode: host. Docker не может задать net.ipv4.ip_forward в таком контейнере. Команда из UI включает sysctl; для постоянства:

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
echo 'net.ipv4.ip_forward=1' | tee /etc/sysctl.d/99-evobgp-bird.conf
echo 'net.ipv6.conf.all.forwarding=1' >> /etc/sysctl.d/99-evobgp-bird.conf
sysctl --system

Безопасность (три участка)

  1. CP → реплика: HTTPS (LE) + Traefik ipallowlist + agent_secret.
  2. Реплика → CP: HTTPS + роль node (только bundle/latest/enroll). Ключ создаётся вместе со спикером.
  3. Конфиг: Ed25519 bundle.sig, SHA-256 manifest, bird -p, LKG на ноде.

Prod checklist:

  • EVOBGP_CONTROL_PLANE_URL=https://... (в команде из UI)
  • EVOBGP_NODE_DISPATCH_ENABLED=1 на CP
  • EVOBGP_BUNDLE_SEED_HEX на CP (не менять после выдачи pubkey репликам)
  • Уникальные agent_secret и node token на спикер
  • Не использовать profile plain в prod
  • Не отключать verify-bundle в agent
  • Не docker compose down -v без бэкапа acme.json

Per-speaker BGP source

В UI: IP ноды (meta_json.node_ipv4) и BGP source IPv4 (bird_bgp_source_ipv4, default = IP ноды). Pipeline накладывает overlay при GET .../bundle/{revision_id} — меняются router id и peer local.

Tenant /v1/settings (bird_bgp_source_ipv4) — fallback для master / если у спикера не задано.

Drift и dispatch

  • published_revision_id vs last_applied_revision_id — в UI и evobgp-deploy.
  • Job deploy_apply meta: node_dispatch.results[] — статус wake-up per speaker.
  • Canary: POST /v1/speakers/{id}/apply с revision_id.

Troubleshooting

Симптом Проверка
sysctl net.ipv4.ip_forward not allowed in host network Уберите sysctls из compose (уже так в main); включите ip_forward на VPS (см. выше)
CHANGE_ME_* в yaml В форме не заполнены email LE / CF token / IP панели / домен
Traefik отдаёт дефолтный сертификат DNS only; token Zone:DNS:Edit; логи evobgp-edge; том acme.json
Offline в UI GET https://AGENT_DOMAIN/v1/agent/health с CP; LE cert; whitelist
dispatch error CP logs job meta; firewall 443; agent_secret
verify-bundle fail pubkey совпадает с CP seed; пересоберите pubkey после смены seed
BGP не поднимается bird2 network_mode: host; peers; MD5 BGP отдельно от HTTP sync

Ограничения (scale-review)

  • Peers не фильтруются по speaker_id — один tenant-wide peers fragment на все реплики.
  • Разные peer-наборы per site — отдельная итерация pipeline.
  • Если Panel не достучится до agent — включите profile fallback (polling) в файле репозитория.

Связанные env

Переменная Где
EVOBGP_NODE_DISPATCH_ENABLED=1 CP
EVOBGP_AGENT_SECRET реплика (из UI, один раз)
EVOBGP_NODE_TOKEN реплика (API-ключ role=node, из UI)
EVOBGP_FIREWALL_FAILOVER_ENABLED=1 реплика (опционально: отдавать /v1/firewall/blocklist при недоступности CP)
EVOBGP_FIREWALL_STATE_FILE реплика (default /var/lib/evobgp-agent/firewall-state.json)
EVOBGP_BUNDLE_PUBKEY_BASE64 реплика (в команде из UI)
PANEL_IP_WHITELIST Traefik на реплике
CF_DNS_API_TOKEN Traefik на реплике
LETSENCRYPT_EMAIL Traefik на реплике