sub2api/deploy/docker-compose.yml
win 002066e700 chore(wip): 保存订制改动以便合并上游
- windsurf: client/pool/local_ls/tool_emulation/tool_names/models 调整
- handler: admin account_data / failover_loop / gateway_handler
- repository: scheduler_cache 及测试
- service: windsurf_chat_service / windsurf_gateway_service
- deploy: compose 合并为单文件(含 windsurf-ls profile),Dockerfile.ls
- cmd: 新增 dump_ls_models / dump_preamble / test_windsurf_tools 辅助工具
2026-04-24 11:14:36 +08:00

253 lines
9.5 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# =============================================================================
# Sub2API - Docker Compose Configuration (All-in-One)
# =============================================================================
# 包含服务:
# - sub2api 主应用
# - postgres 数据库
# - redis 缓存
# - windsurf-ls 可选: Windsurf Language Server (通过 profile 启用)
#
# 启动方式:
# 默认三件套: docker compose up -d
# 含 Windsurf LS: docker compose --profile windsurf up -d
#
# 注意:
# - 首次启动前先复制 .env.example 为 .env 并填写必填变量
# - JWT_SECRET / TOTP_ENCRYPTION_KEY 多实例必须固定
# - windsurf-ls 镜像仅支持 linux/amd64, arm64 宿主机会通过 QEMU 模拟
# =============================================================================
services:
# ===========================================================================
# Sub2API Application
# ===========================================================================
sub2api:
image: docker.io/zfc931912343/sub2api:latest
container_name: sub2api
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:-}
# --- Windsurf (账号管理/登录,不依赖 LS) ---
- WINDSURF_ENABLED=${WINDSURF_ENABLED:-false}
- WINDSURF_FIREBASE_API_KEY=${WINDSURF_FIREBASE_API_KEY:-}
# --- Windsurf Language Server (可选,启用 windsurf profile 时生效) ---
- WINDSURF_DOCKER_HOST=${WINDSURF_DOCKER_HOST:-windsurf-ls}
- WINDSURF_DOCKER_PORT=${WINDSURF_DOCKER_PORT:-42099}
- WINDSURF_DOCKER_CSRF_TOKEN=${WINDSURF_DOCKER_CSRF_TOKEN:-}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
windsurf-ls:
condition: service_healthy
required: false
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 在镜像内部匿名卷,必须显式指定才能持久化到命名卷
# 与旧版 compose 保持一致: PGDATA=/var/lib/postgresql/data迁移无感
- 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}
# 默认不对外暴露端口。如需从宿主机调试,取消注释:
# ports:
# - "127.0.0.1:5433:5432"
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: 15s
# ===========================================================================
# 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 'if [ -n "$$REDIS_PASSWORD" ]; then
exec redis-server --requirepass "$$REDIS_PASSWORD" --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru;
else
exec redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru;
fi'
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
# 默认不对外暴露端口。如需调试取消注释:
# ports:
# - "127.0.0.1:6380:6379"
networks:
- sub2api-network
healthcheck:
test: [ "CMD-SHELL", "if [ -n \"$$REDIS_PASSWORD\" ]; then redis-cli -a \"$$REDIS_PASSWORD\" ping; else redis-cli ping; fi" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
# ===========================================================================
# Windsurf Language Server (可选)
# ---------------------------------------------------------------------------
# 启用方式: docker compose --profile windsurf up -d
#
# 架构说明:
# - LS 本体只能绑 127.0.0.1:LS_INTERNAL_PORTCSRF 仅允许 loopback peer
# - 容器内 socat 把 0.0.0.0:42099 → 127.0.0.1:42099
# 使 compose 同网络内的服务可直接通过 `windsurf-ls:42099` 访问。
#
# 架构限制: 官方 LS 二进制仅提供 linux/amd64 & linux/arm64非匹配平台通过 QEMU 模拟。
# 资源建议: CPU 1-2 cores, Memory 512MB - 1GB
# ===========================================================================
windsurf-ls:
image: docker.io/zfc931912343/sub2api-windsurf-ls:latest
container_name: sub2api-windsurf-ls
restart: unless-stopped
profiles: [ "windsurf" ]
volumes:
- windsurf_ls_data:/data
environment:
# Dockerfile.ls 的 ENTRYPOINT 消费这些键,不要改名
# LS_PORT : 容器对外暴露端口socat 监听)
# LS_INTERNAL_PORT: LS 本体监听端口socat 转发目的端口);两者必须不同
- LS_PORT=42099
- LS_INTERNAL_PORT=42098
- LS_CSRF_TOKEN=${WINDSURF_DOCKER_CSRF_TOKEN:?WINDSURF_DOCKER_CSRF_TOKEN is required when windsurf profile is enabled}
- LS_API_SERVER_URL=${LS_API_SERVER_URL:-https://server.self-serve.windsurf.com}
- HTTPS_PROXY=${LS_HTTPS_PROXY:-}
- HTTP_PROXY=${LS_HTTP_PROXY:-}
- TZ=${TZ:-Asia/Shanghai}
# 默认不对外暴露端口,仅通过内部网络通信
# 如需从宿主机调试,取消注释:
# ports:
# - "127.0.0.1:42099:42099"
networks:
- sub2api-network
healthcheck:
test: [ "CMD", "nc", "-z", "127.0.0.1", "42099" ]
interval: 10s
timeout: 3s
retries: 5
start_period: 20s
networks:
sub2api-network:
name: sub2api-network
driver: bridge
volumes:
sub2api_data:
name: sub2api_data
postgres_data:
name: sub2api_postgres_data
redis_data:
name: sub2api_redis_data
windsurf_ls_data:
name: sub2api_windsurf_ls_data