# OpenCodeHub — NAS / home-server stack # ============================================================ # Runs everything on a dedicated disk or NAS share by binding every # data directory to a host path you control (default /mnt/och). # # 1. cp .env.example .env # 2. Set required secrets (JWT_SECRET, SESSION_SECRET, INTERNAL_HOOK_SECRET, # CRON_SECRET, RUNNER_SECRET, AI_CONFIG_ENCRYPTION_KEY, # WORKFLOW_SECRET_ENCRYPTION_KEY, POSTGRES_PASSWORD, REDIS_PASSWORD) # 3. (Optional) point OCH_DATA_DIR at your NAS mount or dedicated disk: # OCH_DATA_DIR=/mnt/nas/opencodehub # or /volume1/opencodehub on Synology # 4. docker compose -f docker-compose.nas.yml up -d # # Storage backends (local + S3 only): # - local: STORAGE_TYPE=local, everything under ${OCH_DATA_DIR}/storage # - s3: STORAGE_TYPE=s3 with STORAGE_ENDPOINT/BUCKET/ACCESS_KEY/SECRET # # Optional profiles: # --profile cloudflare Cloudflare Tunnel for external access # --profile tailscale Tailscale sidecar # ============================================================ x-och-env: &och-env NODE_ENV: production 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} STORAGE_TYPE: ${STORAGE_TYPE:-local} STORAGE_PATH: /data/storage GIT_REPOS_PATH: /data/repos REPOS_PATH: /data/repos GIT_SSH_HOST_KEY: /data/ssh/host_key GIT_SSH_PORT: 2222 RATE_LIMIT_ENABLED: "true" RATE_LIMIT_SKIP_DEV: "false" CSRF_SKIP_DEV: "false" TRUSTED_PROXIES: ${TRUSTED_PROXIES:-127.0.0.1,172.16.0.0/12,100.64.0.0/10} x-och-common: &och-common image: opencodehub/opencodehub:latest restart: unless-stopped environment: <<: *och-env volumes: - ${OCH_DATA_DIR:-/mnt/och}/repos:/data/repos - ${OCH_DATA_DIR:-/mnt/och}/storage:/data/storage - ${OCH_DATA_DIR:-/mnt/och}/ssh:/data/ssh - ${OCH_DATA_DIR:-/mnt/och}/cache:/data/cache depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - opencodehub-network services: # ── Main application (web + API + Git HTTP) ──────────────── app: <<: *och-common container_name: opencodehub environment: <<: *och-env PROCESS_TYPE: app PORT: 4321 ports: - "${WEB_PORT:-4321}:4321" 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: <<: *och-common container_name: opencodehub-ssh environment: <<: *och-env PROCESS_TYPE: ssh ports: - "${SSH_PORT:-2222}:2222" deploy: resources: limits: memory: 512M cpus: "1.0" # ── Background worker ────────────────────────────────────── worker: <<: *och-common container_name: opencodehub-worker environment: <<: *och-env PROCESS_TYPE: worker WORKER_HEALTH_PORT: 9090 expose: - "9090" 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} volumes: - ${OCH_DATA_DIR:-/mnt/och}/postgres:/var/lib/postgresql/data networks: - opencodehub-network 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 ────────────────────────────────────────────────── 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 volumes: - ${OCH_DATA_DIR:-/mnt/och}/redis:/data networks: - opencodehub-network healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 512M cpus: "0.5" # ── Cloudflare Tunnel (optional) ─────────────────────────── cloudflared: image: cloudflare/cloudflared:latest container_name: opencodehub-cloudflared restart: unless-stopped command: tunnel --no-autoupdate run environment: - TUNNEL_TOKEN=${TUNNEL_TOKEN:-} networks: - opencodehub-network profiles: - cloudflare # ── Tailscale (optional) ─────────────────────────────────── tailscale: image: tailscale/tailscale:latest container_name: opencodehub-tailscale hostname: opencodehub-nas restart: unless-stopped environment: - TS_AUTHKEY=${TS_AUTHKEY:-} - TS_STATE_DIR=/var/lib/tailscale - TS_USERSPACE=false volumes: - ${OCH_DATA_DIR:-/mnt/och}/tailscale:/var/lib/tailscale - /dev/net/tun:/dev/net/tun cap_add: - net_admin - sys_module networks: - opencodehub-network profiles: - tailscale networks: opencodehub-network: driver: bridge