# OpenCodeHub — self-hosted quickstart stack (production-safe) # ============================================================ # 1. cp .env.example .env # 2. Fill in ALL required secrets in .env # 3. docker compose up -d # # REQUIRED .env values (compose refuses to start without them): # JWT_SECRET SESSION_SECRET INTERNAL_HOOK_SECRET CRON_SECRET # RUNNER_SECRET AI_CONFIG_ENCRYPTION_KEY WORKFLOW_SECRET_ENCRYPTION_KEY # POSTGRES_PASSWORD REDIS_PASSWORD # → generate each with: openssl rand -hex 32 # # Storage — two backends only: # - local (default): filesystem; point STORAGE_PATH/GIT_REPOS_PATH at a # dedicated disk or NAS mount for best performance # - s3: any S3-compatible store (AWS S3, MinIO, R2, Garage, ...) via # STORAGE_ENDPOINT/STORAGE_BUCKET/STORAGE_ACCESS_KEY_ID/STORAGE_SECRET_ACCESS_KEY # # Optional profiles: # docker compose --profile with-runner up -d # CI/CD runner (needs Docker-in-Docker) # docker compose --profile with-minio up -d # local S3-compatible storage # ============================================================ services: # ── Main OpenCodeHub application (web + API + Git HTTP) ──── app: build: context: . dockerfile: Dockerfile container_name: opencodehub-app restart: unless-stopped env_file: .env environment: NODE_ENV: production PORT: 4321 PROCESS_TYPE: app DATABASE_DRIVER: postgres DATABASE_URL: postgresql://${POSTGRES_USER:-opencodehub}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@postgres:5432/${POSTGRES_DB:-opencodehub} REDIS_URL: redis://:${REDIS_PASSWORD:?Set REDIS_PASSWORD in .env}@redis:6379 JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET in .env} SESSION_SECRET: ${SESSION_SECRET:?Set SESSION_SECRET in .env} INTERNAL_HOOK_SECRET: ${INTERNAL_HOOK_SECRET:?Set INTERNAL_HOOK_SECRET in .env} CRON_SECRET: ${CRON_SECRET:?Set CRON_SECRET in .env} RUNNER_SECRET: ${RUNNER_SECRET:?Set RUNNER_SECRET in .env} AI_CONFIG_ENCRYPTION_KEY: ${AI_CONFIG_ENCRYPTION_KEY:?Set AI_CONFIG_ENCRYPTION_KEY in .env} WORKFLOW_SECRET_ENCRYPTION_KEY: ${WORKFLOW_SECRET_ENCRYPTION_KEY:?Set WORKFLOW_SECRET_ENCRYPTION_KEY in .env} SITE_URL: ${SITE_URL:-http://localhost:4321} ALLOWED_ORIGINS: ${SITE_URL:-http://localhost:4321} GIT_REPOS_PATH: /data/repos REPOS_PATH: /data/repos GIT_SSH_PORT: 2222 GIT_SSH_HOST_KEY: /data/ssh/host_key STORAGE_TYPE: ${STORAGE_TYPE:-local} STORAGE_PATH: /data/storage RATE_LIMIT_ENABLED: "true" RATE_LIMIT_SKIP_DEV: "false" CSRF_SKIP_DEV: "false" ports: - "${WEB_PORT:-4321}:4321" # Web UI + API + Git HTTP volumes: - repos-data:/data/repos - storage-data:/data/storage - ssh-data:/data/ssh - cache-data:/data/cache depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - opencodehub-internal - opencodehub-external healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4321/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 20s deploy: resources: limits: memory: 2G cpus: "2.0" # ── SSH Git server ───────────────────────────────────────── ssh-git: build: context: . dockerfile: Dockerfile container_name: opencodehub-ssh restart: unless-stopped environment: NODE_ENV: production PROCESS_TYPE: ssh DATABASE_DRIVER: postgres DATABASE_URL: postgresql://${POSTGRES_USER:-opencodehub}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@postgres:5432/${POSTGRES_DB:-opencodehub} REDIS_URL: redis://:${REDIS_PASSWORD:?Set REDIS_PASSWORD in .env}@redis:6379 JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET in .env} INTERNAL_HOOK_SECRET: ${INTERNAL_HOOK_SECRET:?Set INTERNAL_HOOK_SECRET in .env} GIT_REPOS_PATH: /data/repos REPOS_PATH: /data/repos GIT_SSH_PORT: 2222 GIT_SSH_HOST_KEY: /data/ssh/host_key ports: - "${SSH_PORT:-2222}:2222" # SSH Git volumes: - repos-data:/data/repos - storage-data:/data/storage - ssh-data:/data/ssh - cache-data:/data/cache depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - opencodehub-internal - opencodehub-external healthcheck: test: ["CMD-SHELL", "nc -z localhost 2222 || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 15s deploy: resources: limits: memory: 512M cpus: "1.0" # ── Background worker (merge queue, webhooks, mirrors, digests) ── worker: build: context: . dockerfile: Dockerfile container_name: opencodehub-worker restart: unless-stopped environment: NODE_ENV: production PROCESS_TYPE: worker DATABASE_DRIVER: postgres DATABASE_URL: postgresql://${POSTGRES_USER:-opencodehub}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@postgres:5432/${POSTGRES_DB:-opencodehub} REDIS_URL: redis://:${REDIS_PASSWORD:?Set REDIS_PASSWORD in .env}@redis:6379 JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET in .env} INTERNAL_HOOK_SECRET: ${INTERNAL_HOOK_SECRET:?Set INTERNAL_HOOK_SECRET in .env} GIT_REPOS_PATH: /data/repos REPOS_PATH: /data/repos STORAGE_TYPE: ${STORAGE_TYPE:-local} STORAGE_PATH: /data/storage WORKER_HEALTH_PORT: 9090 expose: - "9090" # Worker healthz/ready volumes: - repos-data:/data/repos - storage-data:/data/storage - ssh-data:/data/ssh - cache-data:/data/cache depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - opencodehub-internal healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 20s deploy: resources: limits: memory: 1G cpus: "1.0" # ── PostgreSQL ───────────────────────────────────────────── postgres: image: docker.io/library/postgres:16-alpine container_name: opencodehub-postgres restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-opencodehub} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env} POSTGRES_DB: ${POSTGRES_DB:-opencodehub} ports: - "${POSTGRES_PORT:-5432}:5432" volumes: - postgres-data:/var/lib/postgresql/data networks: - opencodehub-internal healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-opencodehub} -d ${POSTGRES_DB:-opencodehub}"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 1G cpus: "1.0" # ── Redis (sessions, caching, distributed locking, queues) ── redis: image: docker.io/library/redis:7-alpine container_name: opencodehub-redis restart: unless-stopped command: - redis-server - --requirepass - ${REDIS_PASSWORD:?Set REDIS_PASSWORD in .env} - --appendonly - "yes" - --maxmemory - 256mb - --maxmemory-policy - allkeys-lru ports: - "${REDIS_PORT:-6379}:6379" volumes: - redis-data:/data networks: - opencodehub-internal healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 512M cpus: "0.5" # ── CI/CD Runner (Docker-in-Docker, optional) ────────────── runner: build: context: . dockerfile: Dockerfile.runner container_name: opencodehub-runner restart: unless-stopped privileged: true # Required for Docker-in-Docker environment: RUNNER_TOKEN: ${RUNNER_TOKEN:-} SERVER_URL: http://app:4321 DOCKER_HOST: unix:///var/run/docker.sock RUNNER_WORK_DIR: /work RUNNER_CACHE_DIR: /cache volumes: - /var/run/docker.sock:/var/run/docker.sock - runner-work:/work - runner-cache:/cache depends_on: - app networks: - opencodehub-external healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 20s deploy: resources: limits: memory: 2G cpus: "2.0" profiles: - with-runner # ── MinIO (S3-compatible storage, optional) ──────────────── minio: image: minio/minio:latest container_name: opencodehub-minio restart: unless-stopped command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:?Set MINIO_ROOT_USER in .env} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?Set MINIO_ROOT_PASSWORD in .env} ports: - "${MINIO_CONSOLE_PORT:-9001}:9001" # Web console (set 0 to disable) volumes: - minio-data:/data networks: - opencodehub-external healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 30s timeout: 10s retries: 3 profiles: - with-minio volumes: repos-data: driver: local storage-data: driver: local ssh-data: driver: local cache-data: driver: local postgres-data: driver: local redis-data: driver: local runner-work: driver: local runner-cache: driver: local minio-data: driver: local networks: opencodehub-internal: driver: bridge opencodehub-external: driver: bridge