Files
botfights/docker-compose.yml
T
DorianandClaude Fable 5 0511b97cb9
CI / check (push) Has been cancelled
feat(09-01): arena-proxy survives SSE, client-IP forwarding, upstream-down
- Forward client IP via x-forwarded-for/x-real-ip so the canonical arena's
  per-IP rate limiting isn't collapsed to one bucket per node.
- 30s AbortSignal.timeout on non-stream requests; SSE fight streams
  (/api/fights/:id/stream) are exempt (long-lived by design).
- On upstream fetch failure, log and return 502 {error} instead of a
  buffered hang or a 500 stack trace.
- fights.ts: set X-Accel-Buffering: no on the SSE stream response so an
  nginx-fronted arena (nginx-proxy-manager) doesn't buffer live fight events.
- docker-compose.yml: document ARENA_UPSTREAM_URL / TRUSTED_PROXY (commented,
  no active value set here — the canonical arena gets its own compose file
  in a later plan).

TDD: added the SSE/XFF/502 tests, confirmed the 502 test failed against the
prior implementation, then implemented to green (9/9 arena-proxy tests,
17/17 combined with rate-limit.test.ts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 21:32:57 -04:00

54 lines
2.4 KiB
YAML

services:
botfights:
build:
context: .
args:
CACHE_BUST: ${CACHE_BUST:-0}
container_name: botfights
restart: unless-stopped
ports:
- "9100:9100"
volumes:
- botfights-data:/app/server/data
environment:
- NODE_ENV=production
- PORT=9100
# Queue: how long (ms) before falling back to mock bot (default 30s in prod)
# - QUEUE_TIMEOUT_MS=30000
# CORS: set to your domain in prod, or leave for same-origin
# - CORS_ORIGIN=https://botfights.example.com
# Background fights: mock bots fight each other for site activity
- FIGHT_LOOP_ENABLED=true
# - FIGHT_LOOP_INTERVAL_MS=45000
# - FIGHT_LOOP_QUIET_START=2
# - FIGHT_LOOP_QUIET_END=8
# ── Wallet / Payments (required for ranked fights) ──
# Set these in Portainer's stack "Environment Variables" section.
# Generate encryption key with: openssl rand -hex 32
- BOTFIGHTS_WALLET_ENCRYPTION_KEY=${BOTFIGHTS_WALLET_ENCRYPTION_KEY:-}
- BOTFIGHTS_NWC_URL=${BOTFIGHTS_NWC_URL:-}
- BOTFIGHTS_CASHU_MINT_URL=${BOTFIGHTS_CASHU_MINT_URL:-}
- BOTFIGHTS_DEV_PAYOUT_LNADDRESS=${BOTFIGHTS_DEV_PAYOUT_LNADDRESS:-}
# ── Auth ──
# Generate with: openssl rand -hex 32
- JWT_SECRET=${JWT_SECRET}
- BOTFIGHTS_CREATOR_PUBKEYS=${BOTFIGHTS_CREATOR_PUBKEYS:-da5e0c1b646bdb13c2300f805b0ca3e5afe5b052c594ce78bac8978d21c3fa39}
# SQLite database path (defaults to /app/server/data/botfights.db)
# - DB_PATH=/app/server/data/botfights.db
# ── Arena federation (BOT-03) ──
# Set on a NODE instance to make it a thin client of a shared canonical
# arena: every /api/* request is proxied there instead of touching this
# instance's own local SQLite DB. Leave UNSET on the canonical arena
# itself (it stays standalone). Any BotFights instance can be a
# canonical arena for others — this is not hardcoded to one host; the
# Foundation's VPS2 instance is only the well-known default.
# - ARENA_UPSTREAM_URL=http://146.59.87.168:9100
# Set to 1 ONLY on the canonical arena instance when it sits behind a
# reverse proxy (e.g. nginx-proxy-manager) — makes the arena trust
# cf-connecting-ip/x-real-ip/x-forwarded-for from the proxy for
# per-IP rate limiting. Never set on a node's own proxying instance.
# - TRUSTED_PROXY=1
volumes:
botfights-data: