Files
EvoBGP/docs/remote-speakers.md
Denozordec 927e27640a
quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 26s
quality / web (push) Successful in 1m27s
quality / go (push) Successful in 1m18s
quality / bird2 (push) Successful in 16s
CD / quality (push) Successful in 3m43s
CD / publish (push) Successful in 3m11s
feat(docs): update speaker installation instructions and logging details
- Enhanced the speaker installation documentation to clarify the use of TCP port 179 and the logging commands for monitoring BIRD and evobgp-agent.
- Updated the speaker form dialog to include additional information about MikroTik connections and logging commands.
- Modified the BIRD configuration to include logging to stderr for better visibility during operations.
- Adjusted the Docker Compose configuration to ensure proper network settings and sysctl configurations for BGP functionality.
2026-08-21 16:11:28 +07:00

148 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Удалённые BGP-спикеры (Remnawave-style)
Runbook для реплик **bird2 + evobgp-agent** на отдельных VPS. Control plane (`evobgp-all`) инициирует доставку после `module_refresh``deploy_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](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](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](../deploy/compose/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 — Docker `ports: 179:179/tcp`, как на панели |
| **80** | любой | редирект HTTP → HTTPS (не HTTP-01 ACME) |
В панели хостера / security group откройте **TCP 179** (скрипт compose это не делает). Overlay (`bird_bgp_source_ipv4` / `node_ipv4`) задаёт `router id`; host-сеть bird2 не используется.
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 (`speaker-net`, `179:179`) + agent + Traefik LE |
| `plain` | bird2 + agent без Traefik (lab; agent на хосте) |
| `fallback` | + `sync-bundle` polling (`scripts/sync-bundle.sh`) |
Команда из UI — самодостаточный yaml **без profiles** (эквивалент production).
## Подготовка VPS
`bird2` в docker-сети с `ports: 179:179/tcp` и `sysctls` ip_forward (как панель). Команда из UI дополнительно включает sysctl на хосте:
```bash
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
```
## Логи на реплике
BIRD пишет в stderr (`log stderr all`), agent — в stdout. На VPS:
```bash
cd /opt/evobgp-speaker
docker compose logs -f bird2
docker compose logs -f evobgp-agent
```
До первого apply бандла с `protocol bgp` порт 179 может быть CLOSED (нет listener). После sync в логах agent: `sync start` / `sync ok` / `sync failed`.
## Безопасность (три участка)
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
| Симптом | Проверка |
|---------|----------|
| `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 не поднимается / сканер CLOSED | `179:179` в compose; SG хостера; `docker compose logs bird2`; пир MikroTik на IP ноды; бандл применён (`sync ok`) |
## Ограничения (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 на реплике |