5867afd168
The compose stack hard-coded host ports (postgres 5433, redis 6380,
mailpit 8025, gateway REST 8080, gateway gRPC 9090) — fine for a
clean dev machine, painful when those ports collide with other
services on the same host (e.g. a `crowdsec` sitting on
127.0.0.1:8080 or a Prometheus instance on :9090).
Every host-port mapping is now `${LOCAL_DEV_*_PORT:-<old-default>}`,
so the defaults match prior behaviour for everyone and a per-host
override is a single environment variable away. `.env` carries the
overrides as commented-out lines so the customisation surface is
discoverable without grepping the compose file. README's
"Port 8080 already in use" troubleshooting entry now points at the
new variables and the optional `docker-compose.override.yml`
workflow.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
212 lines
8.0 KiB
YAML
212 lines
8.0 KiB
YAML
# Local development stack for the Galaxy UI.
|
|
#
|
|
# Brings up postgres + redis + mailpit + backend + gateway so the UI
|
|
# Vite dev server (run on the host with `pnpm -C ui/frontend dev`) can
|
|
# talk to a real authenticated stack without any cloud dependency.
|
|
#
|
|
# Browser: http://localhost:8080 (gateway public REST + Connect-Web)
|
|
# Mailpit UI: http://localhost:8025
|
|
# Postgres: localhost:5433 (host-mapped)
|
|
# Redis: localhost:6380 (host-mapped)
|
|
#
|
|
# Bring up: make -C tools/local-dev up
|
|
# Tear down: make -C tools/local-dev down
|
|
# Wipe state: make -C tools/local-dev clean
|
|
#
|
|
# The backend reads `BACKEND_AUTH_DEV_FIXED_CODE=123456` from the
|
|
# `.env` file alongside this compose; ConfirmEmailCode accepts that
|
|
# literal in addition to the real bcrypt-verified code, so a developer
|
|
# can log in without touching Mailpit. Real codes still arrive in
|
|
# Mailpit; both paths coexist.
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
container_name: galaxy-local-dev-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: galaxy
|
|
POSTGRES_PASSWORD: galaxy
|
|
POSTGRES_DB: galaxy_backend
|
|
ports:
|
|
- "${LOCAL_DEV_POSTGRES_PORT:-5433}:5432"
|
|
volumes:
|
|
- postgres-data:/var/lib/postgresql/data
|
|
networks:
|
|
- galaxy-net
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U galaxy -d galaxy_backend"]
|
|
interval: 3s
|
|
timeout: 3s
|
|
retries: 30
|
|
start_period: 5s
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: galaxy-local-dev-redis
|
|
restart: unless-stopped
|
|
command:
|
|
- redis-server
|
|
- --requirepass
|
|
- galaxy-dev
|
|
- --appendonly
|
|
- "no"
|
|
- --save
|
|
- ""
|
|
ports:
|
|
- "${LOCAL_DEV_REDIS_PORT:-6380}:6379"
|
|
networks:
|
|
- galaxy-net
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "-a", "galaxy-dev", "PING"]
|
|
interval: 3s
|
|
timeout: 3s
|
|
retries: 30
|
|
start_period: 3s
|
|
|
|
mailpit:
|
|
image: axllent/mailpit:v1.21
|
|
container_name: galaxy-local-dev-mailpit
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${LOCAL_DEV_MAILPIT_PORT:-8025}:8025"
|
|
networks:
|
|
- galaxy-net
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8025/livez"]
|
|
interval: 3s
|
|
timeout: 3s
|
|
retries: 30
|
|
start_period: 3s
|
|
|
|
backend:
|
|
build:
|
|
context: ../..
|
|
dockerfile: tools/local-dev/backend.Dockerfile
|
|
image: galaxy/backend:local-dev
|
|
container_name: galaxy-local-dev-backend
|
|
restart: unless-stopped
|
|
user: "0:0"
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
mailpit:
|
|
condition: service_healthy
|
|
environment:
|
|
BACKEND_LOGGING_LEVEL: debug
|
|
BACKEND_HTTP_LISTEN_ADDR: ":8080"
|
|
BACKEND_GRPC_PUSH_LISTEN_ADDR: ":8081"
|
|
BACKEND_POSTGRES_DSN: "postgres://galaxy:galaxy@postgres:5432/galaxy_backend?search_path=backend&sslmode=disable"
|
|
BACKEND_SMTP_HOST: mailpit
|
|
BACKEND_SMTP_PORT: "1025"
|
|
BACKEND_SMTP_FROM: "galaxy-backend@galaxy.local"
|
|
BACKEND_SMTP_TLS_MODE: none
|
|
BACKEND_DOCKER_NETWORK: galaxy-local-dev-net
|
|
BACKEND_GAME_STATE_ROOT: /tmp/galaxy-game-state
|
|
BACKEND_GEOIP_DB_PATH: /var/lib/galaxy/geoip.mmdb
|
|
BACKEND_NOTIFICATION_ADMIN_EMAIL: admin@galaxy.local
|
|
BACKEND_AUTH_CHALLENGE_THROTTLE_MAX: "100"
|
|
BACKEND_MAIL_WORKER_INTERVAL: 500ms
|
|
BACKEND_NOTIFICATION_WORKER_INTERVAL: 500ms
|
|
BACKEND_OTEL_TRACES_EXPORTER: none
|
|
BACKEND_OTEL_METRICS_EXPORTER: none
|
|
BACKEND_AUTH_DEV_FIXED_CODE: ${BACKEND_AUTH_DEV_FIXED_CODE:-}
|
|
BACKEND_DEV_SANDBOX_EMAIL: ${BACKEND_DEV_SANDBOX_EMAIL:-}
|
|
BACKEND_DEV_SANDBOX_ENGINE_IMAGE: ${BACKEND_DEV_SANDBOX_ENGINE_IMAGE:-}
|
|
BACKEND_DEV_SANDBOX_ENGINE_VERSION: ${BACKEND_DEV_SANDBOX_ENGINE_VERSION:-}
|
|
BACKEND_DEV_SANDBOX_PLAYER_COUNT: ${BACKEND_DEV_SANDBOX_PLAYER_COUNT:-}
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
# Per-game state directories live under the same absolute path
|
|
# both inside the backend container and on the Docker daemon
|
|
# host (colima VM), so the bind-mount source the backend hands
|
|
# to the daemon resolves correctly when spawning engine
|
|
# containers. See backend/internal/runtime/service.go:454.
|
|
- type: bind
|
|
source: /tmp/galaxy-game-state
|
|
target: /tmp/galaxy-game-state
|
|
bind:
|
|
create_host_path: true
|
|
- ../../pkg/geoip/test-data/test-data/GeoIP2-Country-Test.mmdb:/var/lib/galaxy/geoip.mmdb:ro
|
|
networks:
|
|
- galaxy-net
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8080/healthz"]
|
|
interval: 3s
|
|
timeout: 3s
|
|
retries: 60
|
|
start_period: 10s
|
|
|
|
gateway:
|
|
build:
|
|
context: ../..
|
|
dockerfile: tools/local-dev/gateway.Dockerfile
|
|
image: galaxy/gateway:local-dev
|
|
container_name: galaxy-local-dev-gateway
|
|
restart: unless-stopped
|
|
depends_on:
|
|
backend:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
GATEWAY_LOG_LEVEL: debug
|
|
GATEWAY_PUBLIC_HTTP_ADDR: ":8080"
|
|
GATEWAY_AUTHENTICATED_GRPC_ADDR: ":9090"
|
|
GATEWAY_BACKEND_HTTP_URL: "http://backend:8080"
|
|
GATEWAY_BACKEND_GRPC_PUSH_URL: "backend:8081"
|
|
GATEWAY_BACKEND_GATEWAY_CLIENT_ID: local-dev-gateway-1
|
|
GATEWAY_RESPONSE_SIGNER_PRIVATE_KEY_PEM_PATH: /run/secrets/gateway-response.pem
|
|
GATEWAY_REDIS_MASTER_ADDR: "redis:6379"
|
|
GATEWAY_REDIS_PASSWORD: galaxy-dev
|
|
# Loosen anti-abuse so a developer hammering the form does not
|
|
# rate-limit themselves between cycles.
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_BURST: "1000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_BURST: "1000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_BURST: "1000"
|
|
# public_misc class wraps the authenticated EdgeGateway gRPC
|
|
# endpoints (ExecuteCommand, SubscribeEvents). The gateway's
|
|
# default for this class is 0 bytes, which rejects every
|
|
# non-empty body with HTTP 413; override with a generous limit
|
|
# so browser-side commands carrying signed envelopes go through.
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_MAX_BODY_BYTES: "131072"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_RATE_LIMIT_BURST: "1000"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_BOOTSTRAP_MAX_BODY_BYTES: "65536"
|
|
GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_ASSET_MAX_BODY_BYTES: "65536"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_BURST: "1000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_BURST: "1000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_BURST: "1000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_REQUESTS: "10000"
|
|
GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_BURST: "1000"
|
|
ports:
|
|
- "${LOCAL_DEV_GATEWAY_REST_PORT:-8080}:8080"
|
|
# Authenticated EdgeGateway connect-web/gRPC listener. The
|
|
# browser reaches it via the Vite dev proxy in
|
|
# ui/frontend/vite.config.ts.
|
|
- "${LOCAL_DEV_GATEWAY_GRPC_PORT:-9090}:9090"
|
|
volumes:
|
|
- ./keys/gateway-response.pem:/run/secrets/gateway-response.pem:ro
|
|
networks:
|
|
- galaxy-net
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8080/healthz"]
|
|
interval: 3s
|
|
timeout: 3s
|
|
retries: 30
|
|
start_period: 5s
|
|
|
|
networks:
|
|
galaxy-net:
|
|
name: galaxy-local-dev-net
|
|
|
|
volumes:
|
|
postgres-data:
|
|
name: galaxy-local-dev-postgres-data
|