# Удалённый BGP-спикер (Remnawave-style): bird2 + evobgp-agent + Traefik (LE). # См. docs/remote-speakers.md # # cp .env.remote-speaker.example .env.remote-speaker # cp .env.remote-speaker-tls.example .env.remote-speaker-tls # docker compose -f docker-compose.remote-speaker.yaml \ # --env-file .env.remote-speaker --env-file .env.remote-speaker-tls up -d # # Profiles: # production (default) — bird2 host + agent + evobgp-edge # plain — bird2 + agent без Traefik (lab) # fallback — + sync-bundle polling name: evobgp-remote-speaker x-logging: &default-logging driver: json-file options: max-size: "10m" max-file: "3" services: bird2: profiles: ["production", "plain", "fallback"] image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-bird2:${EVOBGP_IMAGE_TAG:-latest} restart: unless-stopped network_mode: host cap_add: - NET_ADMIN # sysctls нельзя с network_mode: host — включите ip_forward на VPS (см. docs/remote-speakers.md) volumes: - bird_etc:/etc/bird - bird_run:/run/bird logging: *default-logging evobgp-agent: profiles: ["production"] image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-agent:${EVOBGP_IMAGE_TAG:-latest} restart: unless-stopped depends_on: - bird2 cap_add: - NET_ADMIN environment: EVOBGP_AGENT_LISTEN: ":8443" EVOBGP_AGENT_SECRET: ${EVOBGP_AGENT_SECRET:?set EVOBGP_AGENT_SECRET} EVOBGP_CONTROL_PLANE_URL: ${EVOBGP_CONTROL_PLANE_URL:?set EVOBGP_CONTROL_PLANE_URL} EVOBGP_NODE_TOKEN: ${EVOBGP_NODE_TOKEN:?set EVOBGP_NODE_TOKEN} EVOBGP_SPEAKER_ID: ${EVOBGP_SPEAKER_ID:?set EVOBGP_SPEAKER_ID} EVOBGP_BUNDLE_PUBKEY_BASE64: ${EVOBGP_BUNDLE_PUBKEY_BASE64:?set EVOBGP_BUNDLE_PUBKEY_BASE64} EVOBGP_BIRD_EXTRACT_DIR: /etc/bird EVOBGP_BIRDC_SOCKET: /run/bird/bird.ctl volumes: - bird_etc:/etc/bird - bird_run:/run/bird entrypoint: ["/usr/local/bin/evobgp-agent"] command: ["serve", "-socket=/run/bird/bird.ctl"] networks: - speaker-net labels: - traefik.enable=true - traefik.http.routers.evobgp-agent.rule=Host(`${AGENT_DOMAIN}`) - traefik.http.routers.evobgp-agent.entrypoints=websecure - traefik.http.routers.evobgp-agent.tls=true - traefik.http.routers.evobgp-agent.tls.certresolver=letsencrypt - traefik.http.routers.evobgp-agent.middlewares=panel-ipwhitelist@docker - traefik.http.middlewares.panel-ipwhitelist.ipallowlist.sourcerange=${PANEL_IP_WHITELIST} - traefik.http.services.evobgp-agent.loadbalancer.server.port=8443 logging: *default-logging evobgp-agent-plain: profiles: ["plain", "fallback"] image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-agent:${EVOBGP_IMAGE_TAG:-latest} restart: unless-stopped network_mode: host depends_on: - bird2 cap_add: - NET_ADMIN environment: EVOBGP_AGENT_LISTEN: "${EVOBGP_AGENT_PORT:-8443}" EVOBGP_AGENT_SECRET: ${EVOBGP_AGENT_SECRET:?set EVOBGP_AGENT_SECRET} EVOBGP_CONTROL_PLANE_URL: ${EVOBGP_CONTROL_PLANE_URL:?set EVOBGP_CONTROL_PLANE_URL} EVOBGP_NODE_TOKEN: ${EVOBGP_NODE_TOKEN:?set EVOBGP_NODE_TOKEN} EVOBGP_SPEAKER_ID: ${EVOBGP_SPEAKER_ID:?set EVOBGP_SPEAKER_ID} EVOBGP_BUNDLE_PUBKEY_BASE64: ${EVOBGP_BUNDLE_PUBKEY_BASE64:?set EVOBGP_BUNDLE_PUBKEY_BASE64} EVOBGP_BIRD_EXTRACT_DIR: /etc/bird EVOBGP_BIRDC_SOCKET: /run/bird/bird.ctl volumes: - bird_etc:/etc/bird - bird_run:/run/bird entrypoint: ["/usr/local/bin/evobgp-agent"] command: ["serve", "-listen=:${EVOBGP_AGENT_PORT:-8443}", "-socket=/run/bird/bird.ctl"] logging: *default-logging evobgp-edge: profiles: ["production"] image: traefik:latest restart: unless-stopped depends_on: - evobgp-agent ports: - "80:80" - "443:443" environment: DOCKER_API_VERSION: "1.44" CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN:?set CF_DNS_API_TOKEN} command: - --api.dashboard=false - --providers.docker=true - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL:?set LETSENCRYPT_EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json - --certificatesresolvers.letsencrypt.acme.dnschallenge=true - --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare - --certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=15 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - traefik_letsencrypt:/letsencrypt networks: - speaker-net logging: *default-logging sync-bundle: profiles: ["fallback"] image: ${EVOBGP_REGISTRY:-git.shts.su/denozord}/evobgp-node:${EVOBGP_IMAGE_TAG:-latest} restart: unless-stopped depends_on: - bird2 environment: EVOBGP_CONTROL_PLANE_URL: ${EVOBGP_CONTROL_PLANE_URL:?set EVOBGP_CONTROL_PLANE_URL} EVOBGP_NODE_TOKEN: ${EVOBGP_NODE_TOKEN:?set EVOBGP_NODE_TOKEN} EVOBGP_SPEAKER_ID: ${EVOBGP_SPEAKER_ID:?set EVOBGP_SPEAKER_ID} EVOBGP_BUNDLE_PUBKEY_BASE64: ${EVOBGP_BUNDLE_PUBKEY_BASE64:?set EVOBGP_BUNDLE_PUBKEY_BASE64} EVOBGP_SYNC_INTERVAL_SEC: ${EVOBGP_SYNC_INTERVAL_SEC:-300} volumes: - bird_etc:/etc/bird - bird_run:/run/bird - ../../scripts/sync-bundle.sh:/usr/local/bin/sync-bundle.sh:ro entrypoint: ["/bin/sh", "/usr/local/bin/sync-bundle.sh"] network_mode: host logging: *default-logging networks: speaker-net: volumes: bird_etc: bird_run: traefik_letsencrypt: name: evobgp_speaker_traefik_letsencrypt