# ============================================================================= # Sub2API Docker Compose Configuration # ============================================================================= # Quick Start: # 1. Copy .env.example to .env and configure # 2. docker compose up -d # 3. Check logs: docker compose logs -f # # 注意事项: # - JWT_SECRET / TOTP_ENCRYPTION_KEY 必须固定,多实例共享同一个值 # - PostgreSQL / Redis 单实例,不参与水平扩展 # - postgres 端口默认不对外暴露,如需调试取消注释 127.0.0.1:5433:5432 # - redis 端口默认不对外暴露,如需调试取消注释 127.0.0.1:6380:6379 # ============================================================================= services: # =========================================================================== # Sub2API Application # =========================================================================== sub2api: image: docker.io/zfc931912343/sub2api:latest restart: unless-stopped ulimits: nofile: soft: 100000 hard: 100000 ports: - "0.0.0.0:80:8080" volumes: - sub2api_data:/app/data # Optional: 挂载自定义 config.yaml(先从 config.example.yaml 复制并修改) # - ./config.yaml:/app/data/config.yaml # Optional: 自定义 Codex instructions 模板 # - ./codex-instructions.md.tmpl:/app/data/codex-instructions.md.tmpl:ro environment: - AUTO_SETUP=true # --- Server --- - SERVER_HOST=0.0.0.0 - SERVER_PORT=8080 - SERVER_MODE=${SERVER_MODE:-release} - RUN_MODE=${RUN_MODE:-standard} # --- Database (PostgreSQL) --- - DATABASE_HOST=postgres - DATABASE_PORT=5432 - DATABASE_USER=${POSTGRES_USER:-sub2api} - DATABASE_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} - DATABASE_DBNAME=${POSTGRES_DB:-sub2api} - DATABASE_SSLMODE=disable - DATABASE_MAX_OPEN_CONNS=${DATABASE_MAX_OPEN_CONNS:-50} - DATABASE_MAX_IDLE_CONNS=${DATABASE_MAX_IDLE_CONNS:-10} - DATABASE_CONN_MAX_LIFETIME_MINUTES=${DATABASE_CONN_MAX_LIFETIME_MINUTES:-30} - DATABASE_CONN_MAX_IDLE_TIME_MINUTES=${DATABASE_CONN_MAX_IDLE_TIME_MINUTES:-5} # --- Redis --- - REDIS_HOST=redis - REDIS_PORT=6379 - REDIS_PASSWORD=${REDIS_PASSWORD:-} - REDIS_DB=${REDIS_DB:-0} - REDIS_POOL_SIZE=${REDIS_POOL_SIZE:-1024} - REDIS_MIN_IDLE_CONNS=${REDIS_MIN_IDLE_CONNS:-10} - REDIS_ENABLE_TLS=${REDIS_ENABLE_TLS:-false} # --- Admin(仅首次启动生效)--- - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local} - ADMIN_PASSWORD=${ADMIN_PASSWORD:-} # --- JWT(多实例必须固定,否则重启后 session 失效)--- # 生成: openssl rand -hex 32 - JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required for multi-instance} - JWT_EXPIRE_HOUR=${JWT_EXPIRE_HOUR:-24} # --- TOTP 2FA(多实例必须固定,否则 2FA 失效)--- # 生成: openssl rand -hex 32 - TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY:?TOTP_ENCRYPTION_KEY is required for multi-instance} # --- Timezone --- - TZ=${TZ:-Asia/Shanghai} # --- Gemini OAuth --- - GEMINI_OAUTH_CLIENT_ID=${GEMINI_OAUTH_CLIENT_ID:-} - GEMINI_OAUTH_CLIENT_SECRET=${GEMINI_OAUTH_CLIENT_SECRET:-} - GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-} - GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-} - GEMINI_CLI_OAUTH_CLIENT_SECRET=${GEMINI_CLI_OAUTH_CLIENT_SECRET:-} - ANTIGRAVITY_OAUTH_CLIENT_SECRET=${ANTIGRAVITY_OAUTH_CLIENT_SECRET:-} # --- Security --- - SECURITY_URL_ALLOWLIST_ENABLED=${SECURITY_URL_ALLOWLIST_ENABLED:-false} - SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=${SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP:-false} - SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS=${SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS:-false} - SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS=${SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS:-} # --- Update Proxy(国内机器可配置代理访问 GitHub)--- - UPDATE_PROXY_URL=${UPDATE_PROXY_URL:-} depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - sub2api-network healthcheck: test: [ "CMD", "wget", "-q", "-T", "5", "-O", "/dev/null", "http://localhost:8080/health" ] interval: 30s timeout: 10s retries: 3 start_period: 30s # =========================================================================== # PostgreSQL Database # =========================================================================== postgres: image: postgres:18-alpine container_name: sub2api-postgres restart: unless-stopped ulimits: nofile: soft: 100000 hard: 100000 volumes: - postgres_data:/var/lib/postgresql/data environment: # postgres:18-alpine 默认 PGDATA 在镜像内部匿名卷,必须显式指定才能持久化到命名卷 - PGDATA=/var/lib/postgresql/data - POSTGRES_USER=${POSTGRES_USER:-sub2api} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} - POSTGRES_DB=${POSTGRES_DB:-sub2api} - TZ=${TZ:-Asia/Shanghai} networks: - sub2api-network healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-sub2api} -d ${POSTGRES_DB:-sub2api}" ] interval: 10s timeout: 5s retries: 5 start_period: 10s # 默认不对外暴露,如需本地调试取消注释 # ports: # - "127.0.0.1:5433:5432" # =========================================================================== # Redis Cache # =========================================================================== redis: image: redis:8-alpine container_name: sub2api-redis restart: unless-stopped ulimits: nofile: soft: 100000 hard: 100000 volumes: - redis_data:/data command: > sh -c ' redis-server --save 60 1 --appendonly yes --appendfsync everysec ${REDIS_PASSWORD:+--requirepass "$REDIS_PASSWORD"}' environment: - TZ=${TZ:-Asia/Shanghai} - REDISCLI_AUTH=${REDIS_PASSWORD:-} networks: - sub2api-network healthcheck: test: [ "CMD", "redis-cli", "ping" ] interval: 10s timeout: 5s retries: 5 start_period: 5s # 默认不对外暴露,如需本地调试取消注释 # ports: # - "127.0.0.1:6380:6379" # ============================================================================= # Volumes # ============================================================================= volumes: sub2api_data: driver: local postgres_data: driver: local redis_data: driver: local # ============================================================================= # Networks # ============================================================================= networks: sub2api-network: driver: bridge