# JA4proxy — Quick Start # # 3 containers: proxy + Redis + management dashboard. # Designed for emergency deployment, evaluation, and CI smoke testing. # # Usage: # BACKEND_HOST=your-server.com docker compose up -d # # The proxy listens on port 8443 (no root required) and forwards TLS # connections to BACKEND_HOST:443. It starts in monitor mode (dial=0): # scores everything, blocks nothing. # # Dashboard (plain HTTP, loopback only — access via SSH tunnel or locally): # http://127.0.0.1:8090 (admin / changeme — change in production!) # Dashboard (HTTPS, via Caddy sidecar — self-signed cert, click through warning): # https://127.0.0.1:8444 # Health: http://127.0.0.1:8090/api/v1/health (public, no auth required) # # Remote access from home / DMZ: see docs/runbooks/dashboard_access.md # # ── Compose file map ───────────────────────────────────────────────────────── # This file (docker-compose.yml) # Quick start / CI smoke test. Sensible defaults, no required secrets. # # deploy/docker/docker-compose.poc.yml # Full local dev stack: HAProxy + proxy + Redis + backend + analytics + # management + tarpit. Requires .env (run 'make init'). Used by 'make start'. # # deploy/docker/docker-compose.prod.yml # Single-instance production. No test services. Requires real secrets. # # deploy/docker/docker-compose.monitoring.yml # Monitoring overlay: Prometheus + Grafana + Alertmanager + Loki. # Compose alongside poc or prod: docker compose -f poc.yml -f monitoring.yml up # # deploy/docker/docker-compose.scale.yml # Scale overlay: 4× proxy workers behind HAProxy. # # deploy/docker/docker-compose.test.yml # Isolated Go integration/chaos/perf test environment. Used by 'make test'. # # deploy/docker/docker-compose.redis-tls.yml # Redis-TLS overlay for TLS-specific integration tests. # ───────────────────────────────────────────────────────────────────────────── services: redis: image: redis:7-alpine restart: unless-stopped command: > redis-server --requirepass ${REDIS_PASSWORD:-changeme} --maxmemory 128mb --maxmemory-policy allkeys-lru --save "" --appendonly no ports: - "127.0.0.1:6379:6379" healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-changeme}", "ping"] interval: 5s timeout: 3s retries: 10 start_period: 5s security_opt: - no-new-privileges:true read_only: true tmpfs: - /data:size=256M logging: driver: json-file options: max-size: "5m" max-file: "3" management: build: context: . dockerfile: deploy/docker/Dockerfile.management # Pre-built image — 'docker compose pull' fetches this instead of building. # Published to GHCR on every merge to main that touches management/ source. # Make package public: GitHub → Packages → ja4proxy-management → Package settings image: ghcr.io/seanpor/ja4proxy-management:main restart: unless-stopped ports: - "127.0.0.1:${MANAGEMENT_PORT:-8090}:8090" depends_on: redis: condition: service_healthy environment: # JA4PROXY-2026-0096 (phase-522): management.api.main._enforce_strong_secrets() # refuses to boot on the committed MANAGEMENT_JWT_SECRET/MANAGEMENT_ADMIN_PASSWORD # defaults below unless ENVIRONMENT is an explicit dev/test value — this quickstart # keeps working by defaulting to "development" (still overridable for prod-style use # of this file, matching deploy/docker/docker-compose.poc.yml's existing pattern). - ENVIRONMENT=${ENVIRONMENT:-development} - REDIS_URL=redis://:${REDIS_PASSWORD:-changeme}@redis:6379/0 - MANAGEMENT_JWT_SECRET=${MANAGEMENT_JWT_SECRET:-ja4proxy-quickstart-secret-change-me} - MANAGEMENT_ADMIN_USER=${MANAGEMENT_ADMIN_USER:-admin} - MANAGEMENT_ADMIN_PASSWORD=${MANAGEMENT_ADMIN_PASSWORD:-changeme} security_opt: - no-new-privileges:true read_only: true tmpfs: - /tmp:size=10M logging: driver: json-file options: max-size: "5m" max-file: "3" ja4proxy: build: context: . dockerfile: deploy/docker/Dockerfile.go-proxy # Pre-built image — 'docker compose pull' fetches this instead of building. # Published to GHCR on every merge to main that touches proxy source. # Make package public: GitHub → Packages → ja4proxy-go → Package settings image: ghcr.io/seanpor/ja4proxy-go:main restart: unless-stopped ports: - "${PROXY_PORT:-8443}:8443" - "127.0.0.1:9090:9090" depends_on: redis: condition: service_healthy volumes: - ./config:/app/config:ro environment: - CONFIG_PATH=/app/config/proxy.minimal.yml - REDIS_HOST=redis - REDIS_PASSWORD=${REDIS_PASSWORD:-changeme} - BACKEND_HOST=${BACKEND_HOST:-_no_backend_} - BACKEND_PORT=${BACKEND_PORT:-443} security_opt: - no-new-privileges:true read_only: true tmpfs: - /tmp:size=10M logging: driver: json-file options: max-size: "10m" max-file: "3" # phase-511: HTTPS sidecar for the management dashboard. # Terminates TLS on port 8444 (loopback-only) and proxies to management:8090. # Self-signed cert is generated automatically by Caddy — no cert management needed. # Browser will show a certificate warning on first visit; click "Advanced → Proceed". # Access via SSH tunnel: ssh -L 8444:127.0.0.1:8444 user@dmz-host -N # then open: https://127.0.0.1:8444 management-tls: image: caddy:2-alpine restart: unless-stopped ports: - "127.0.0.1:${MGMT_TLS_PORT:-8444}:8444" volumes: - ./deploy/caddy/Caddyfile.management:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config depends_on: - management security_opt: - no-new-privileges:true logging: driver: json-file options: max-size: "5m" max-file: "3" volumes: caddy_data: caddy_config: