Files
OmniRoute/docker-compose.prod.yml
diegosouzapw b87c92b3d7 fix(docker): bind app/sidecar compose ports to loopback by default (#12568, #12578)
docker-compose.yml and docker-compose.prod.yml defaulted API_HOST/LIVE_WS_HOST/
HOSTNAME to 0.0.0.0 and published the dashboard/API/live-WS ports with bare,
unscoped specs, which Docker expands to every interface. Combined with
REQUIRE_API_KEY=false shipping as the .env.example default, this exposed the
anonymous /v1 LLM proxy to the whole LAN/WAN (#12568). The optional cliproxyapi
sidecar had the same unscoped publish spec plus no forwarded auth env var,
exposing a credential-bearing service the same way (#12578); qdrant and bifrost
had the identical gap.

Applies the existing Redis loopback-bind precedent (tests/unit/compose-redis-
loopback-bind.test.ts) to the app's own ports and to cliproxyapi/qdrant/bifrost:
- New APP_BIND_HOST / CLIPROXY_BIND_HOST / QDRANT_BIND_HOST / BIFROST_BIND_HOST
  opt-in vars, defaulting to 127.0.0.1, documented in .env.example and
  docs/reference/ENVIRONMENT.md.
- API_HOST/LIVE_WS_HOST default to 127.0.0.1 in both compose files; the prod
  file no longer hardcodes HOSTNAME=0.0.0.0.
- cliproxyapi now forwards CLIPROXYAPI_MANAGEMENT_KEY as MANAGEMENT_PASSWORD,
  the one env var the pinned image actually reads for its management API.
- A new boot-time guard (src/lib/startup/nonLoopbackApiKeyGuard.ts) logs a
  warning — never a hard failure — when the API bridge or live-WS server ends
  up bound to a non-loopback host while REQUIRE_API_KEY is disabled.

⚠️ base-red inherited: #12732 — unit #12058, integration codex-cache,
package-artifact, tarball-smoke, agent-skills-sync

Closes #12568
Closes #12578
2026-09-10 13:51:25 -03:00

108 lines
4.4 KiB
YAML

# ──────────────────────────────────────────────────────────────────────
# OmniRoute — Docker Compose (Production Snapshot)
# ──────────────────────────────────────────────────────────────────────
#
# Isolated production instance running on port 20130.
# Keeps the app running while you continue developing locally.
#
# Usage:
# docker compose -f docker-compose.prod.yml up -d --build
# docker compose -f docker-compose.prod.yml down
# docker compose -f docker-compose.prod.yml logs -f
#
# Image flavors (two Dockerfile stages):
# runner-base (default / omniroute:prod)
# Lean image — no Playwright/Chromium. Suitable for all providers
# except web-cookie ones (gemini-web, claude-web, claude-turnstile).
#
# runner-web (omniroute:prod-web) — opt-in, ~300 MB extra
# Includes Playwright + Chromium system libs. Required for web-cookie
# providers. To use this flavor, override the build target:
#
# omniroute-prod:
# build:
# context: .
# target: runner-web
# image: omniroute:prod-web
# ──────────────────────────────────────────────────────────────────────
services:
# ── Redis (Rate Limiter Backend) ──────────────────────────────────
redis:
image: redis:8.6.5-alpine
container_name: omniroute-redis-prod
restart: unless-stopped
volumes:
- redis-prod-data:/data
command: redis-server --save 60 1 --loglevel warning
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
omniroute-prod:
container_name: omniroute-prod
depends_on:
redis:
condition: service_healthy
chatgpt-web-codex-browser:
condition: service_started
build:
context: .
target: runner-cli
args:
OMNIROUTE_BASE_PATH: ${OMNIROUTE_BASE_PATH:-}
image: omniroute:prod
restart: unless-stopped
stop_grace_period: 40s
env_file: .env
environment:
- NODE_ENV=production
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- LIVE_WS_PORT=${LIVE_WS_PORT:-20132}
- LIVE_WS_HOST=${LIVE_WS_HOST:-127.0.0.1}
- LIVE_WS_ALLOWED_ORIGINS=${LIVE_WS_ALLOWED_ORIGINS:-http://localhost:${PROD_DASHBOARD_PORT:-20130},http://127.0.0.1:${PROD_DASHBOARD_PORT:-20130}}
- API_HOST=${API_HOST:-127.0.0.1}
# HOSTNAME intentionally not hardcoded to 0.0.0.0 (#12568) — let the
# app's own loopback-first default apply unless the operator sets it.
- DATA_DIR=/app/data
- OMNIROUTE_BASE_PATH=${OMNIROUTE_BASE_PATH:-}
- CHATGPT_WEB_CODEX_CDP_URL=http://chatgpt-web-codex-browser:9223
ports:
# Loopback-only by default (#12568) — see docker-compose.yml's
# APP_BIND_HOST comment for the rationale. Override for a LAN/WAN prod
# deployment only once REQUIRE_API_KEY=true or a reverse proxy in front
# of this instance is confirmed to enforce its own auth.
- "${APP_BIND_HOST:-127.0.0.1}:${PROD_DASHBOARD_PORT:-20130}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${APP_BIND_HOST:-127.0.0.1}:${PROD_API_PORT:-20131}:${API_PORT:-20129}"
- "${APP_BIND_HOST:-127.0.0.1}:${PROD_LIVE_WS_PORT:-20132}:${LIVE_WS_PORT:-20132}"
volumes:
- omniroute-prod-data:/app/data
healthcheck:
test: ["CMD", "node", "healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
chatgpt-web-codex-browser:
build:
context: .
dockerfile: docker/chatgpt-web-codex-browser/Dockerfile
image: omniroute:chatgpt-web-codex-browser
restart: unless-stopped
shm_size: "2gb"
volumes:
- chatgpt-web-codex-browser-prod-data:/browser-profile
volumes:
chatgpt-web-codex-browser-prod-data:
name: omniroute-chatgpt-web-codex-browser-prod-data
omniroute-prod-data:
name: omniroute-prod-data
redis-prod-data:
name: redis-prod-data