---
url: /host/j9p5aqds/index.md
description: 使用 Docker Compose 部署 Sub2api，复用宿主机已有的 PostgreSQL 与 Redis，避免在容器内重复部署数据库。
---
本文讲解如何使用 Docker Compose 部署 [Sub2api](https://github.com/Wei-Shaw/sub2api)，并复用宿主机上已有的 PostgreSQL 与 Redis，避免在容器内重复部署数据库。

::: warning 前提条件

* 宿主机已安装并能正常访问 PostgreSQL 与 Redis。
* 本配置使用 `network_mode: host`，容器直接共享宿主机网络，因此数据库地址填 `127.0.0.1` 即可访问宿主机服务。若你的数据库在远程或 Docker 网络中，请相应修改地址。
  :::

## 1. 准备数据库

部署前需在本地 PostgreSQL 中创建专用数据库与用户：

```sql
CREATE USER sub2api WITH PASSWORD '123456';
CREATE DATABASE sub2api OWNER sub2api;
```

Redis 无需特殊准备，只需确认端口与密码；若与其他业务共用同一 Redis，建议指定一个独立的 `db` 编号（本文使用 `9`）以避免键冲突。

## 2. 下载部署脚本

```shell
# 创建部署目录
mkdir -p sub2api-deploy && cd sub2api-deploy

# 下载并运行部署准备脚本
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/docker-deploy.sh | bash
```

脚本执行后会在当前目录生成 `docker-compose.yml` 等部署文件。其默认版本会在容器内自带 PostgreSQL 与 Redis，**下一步需将其替换为下方复用本地数据库的版本**。

## 3. 修改 docker-compose.yml

将生成的 `docker-compose.yml` 内容替换为以下配置，并按需修改标注的必改项：

::: tip 必改项速览

* `SERVER_PORT`：Sub2api 对外端口（示例 `10086`）
* `DATABASE_*`：本地 PostgreSQL 连接信息
* `REDIS_*`：本地 Redis 连接信息（无密码则注释 `REDIS_PASSWORD`）
* `ADMIN_EMAIL`：管理员账号，**必须是邮箱格式**，否则无法登录
* `ADMIN_PASSWORD`：管理员密码
* `JWT_SECRET` / `TOTP_ENCRYPTION_KEY`：**务必显式设置**，留空则每次重启随机生成，会导致登录态失效、2FA 无法登录
  :::

```yaml
# =============================================================================
# Sub2API Docker Compose - Local Directory Version
# =============================================================================
# This configuration uses local directories for data storage instead of named
# volumes, making it easy to migrate the entire deployment by simply copying
# the deploy directory.
#
# Quick Start:
#   1. Copy .env.example to .env and configure
#   2. mkdir -p data postgres_data redis_data
#   3. docker-compose -f docker-compose.local.yml up -d
#   4. Check logs: docker-compose -f docker-compose.local.yml logs -f sub2api
#   5. Access: http://localhost:8080
#
# Migration to New Server:
#   1. docker-compose -f docker-compose.local.yml down
#   2. tar czf sub2api-deploy.tar.gz deploy/
#   3. Transfer to new server and extract
#   4. docker-compose -f docker-compose.local.yml up -d
# =============================================================================

services:
  # ===========================================================================
  # Sub2API Application
  # ===========================================================================
  sub2api:
    image: weishaw/sub2api:latest
    container_name: sub2api
    restart: unless-stopped
    network_mode: host
    ulimits:
      nofile:
        soft: 100000
        hard: 100000
    volumes:
      # Local directory mapping for easy migration
      - ./data:/app/data:Z
      # Optional: Mount custom config.yaml (uncomment and create the file first)
      # Copy config.example.yaml to config.yaml, modify it, then uncomment:
      # - ./config.yaml:/app/data/config.yaml
    environment:
      # =======================================================================
      # Auto Setup (REQUIRED for Docker deployment)
      # =======================================================================
      - AUTO_SETUP=true

      # =======================================================================
      # Server Configuration
      # =======================================================================
      - SERVER_HOST=0.0.0.0
      # 这里配置 sub2api 的端口
      - SERVER_PORT=10086
      - SERVER_MODE=${SERVER_MODE:-release}
      - RUN_MODE=${RUN_MODE:-standard}

      # =======================================================================
      # Database Configuration (PostgreSQL)
      # =======================================================================
      # 这里改为本地的 postgresql 配置
      - DATABASE_HOST=127.0.0.1
      - DATABASE_PORT=5432
      - DATABASE_USER=sub2api
      - DATABASE_PASSWORD=123456
      - DATABASE_DBNAME=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 Configuration
      # =======================================================================
      # 这里改为本地的 redis 配置，如果没有密码则注释掉，db 可以选择一个与当前业务不相关的
      - REDIS_HOST=127.0.0.1
      - REDIS_PORT=6379
      - REDIS_PASSWORD=123456
      - REDIS_DB=9
      - REDIS_POOL_SIZE=${REDIS_POOL_SIZE:-1024}
      - REDIS_MIN_IDLE_CONNS=${REDIS_MIN_IDLE_CONNS:-10}
      - REDIS_ENABLE_TLS=${REDIS_ENABLE_TLS:-false}

      # =======================================================================
      # Admin Account (auto-created on first run)
      # =======================================================================
      # 这里设置用户名和密码，注意️：用户名必须是邮箱账号，否则无法登录
      - ADMIN_EMAIL=123@qq.com
      - ADMIN_PASSWORD=12345678

      # =======================================================================
      # JWT Configuration
      # =======================================================================
      # IMPORTANT: Set a fixed JWT_SECRET to prevent login sessions from being
      # invalidated after container restarts. If left empty, a random secret
      # will be generated on each startup.
      # Generate a secure secret: openssl rand -hex 32
      - JWT_SECRET=${JWT_SECRET:-}
      - JWT_EXPIRE_HOUR=${JWT_EXPIRE_HOUR:-24}

      # =======================================================================
      # TOTP (2FA) Configuration
      # =======================================================================
      # IMPORTANT: Set a fixed encryption key for TOTP secrets. If left empty,
      # a random key will be generated on each startup, causing all existing
      # TOTP configurations to become invalid (users won't be able to login
      # with 2FA).
      # Generate a secure key: openssl rand -hex 32
      - TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY:-}

      # =======================================================================
      # Timezone Configuration
      # This affects ALL time operations in the application:
      # - Database timestamps
      # - Usage statistics "today" boundary
      # - Subscription expiry times
      # - Log timestamps
      # Common values: Asia/Shanghai, America/New_York, Europe/London, UTC
      # =======================================================================
      - TZ=${TZ:-Asia/Shanghai}

      # =======================================================================
      # Gemini OAuth Configuration (for Gemini accounts)
      # =======================================================================
      - 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:-}

      # Built-in OAuth client secrets (optional)
      # SECURITY: This repo does not embed third-party client_secret.
      - GEMINI_CLI_OAUTH_CLIENT_SECRET=${GEMINI_CLI_OAUTH_CLIENT_SECRET:-}
      - ANTIGRAVITY_OAUTH_CLIENT_SECRET=${ANTIGRAVITY_OAUTH_CLIENT_SECRET:-}
      - ANTIGRAVITY_USER_AGENT_VERSION=${ANTIGRAVITY_USER_AGENT_VERSION:-}

      # =======================================================================
      # Security Configuration (URL Allowlist)
      # =======================================================================
      # Enable URL allowlist validation (false to skip allowlist checks)
      - SECURITY_URL_ALLOWLIST_ENABLED=${SECURITY_URL_ALLOWLIST_ENABLED:-false}
      # Allow insecure HTTP URLs when allowlist is disabled (default: false, requires https)
      - SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=${SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP:-false}
      # Allow private IP addresses for upstream/pricing/CRS (for internal deployments)
      - SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS=${SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS:-false}
      # Upstream hosts whitelist (comma-separated, only used when enabled=true)
      - SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS=${SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS:-}

      # =======================================================================
      # Update Configuration (在线更新配置)
      # =======================================================================
      # Proxy for accessing GitHub (online updates + pricing data)
      # Examples: http://host:port, socks5://host:port
      - UPDATE_PROXY_URL=${UPDATE_PROXY_URL:-}

      # =======================================================================
      # Image Generation Stream & Concurrency
      # =======================================================================
      # OpenAI HTTP upstream protocol/timeout
      - GATEWAY_OPENAI_RESPONSE_HEADER_TIMEOUT=${GATEWAY_OPENAI_RESPONSE_HEADER_TIMEOUT:-0}
      - GATEWAY_OPENAI_HTTP2_ENABLED=${GATEWAY_OPENAI_HTTP2_ENABLED:-true}
      - GATEWAY_OPENAI_HTTP2_ALLOW_PROXY_FALLBACK_TO_HTTP1=${GATEWAY_OPENAI_HTTP2_ALLOW_PROXY_FALLBACK_TO_HTTP1:-true}
      - GATEWAY_OPENAI_HTTP2_FALLBACK_ERROR_THRESHOLD=${GATEWAY_OPENAI_HTTP2_FALLBACK_ERROR_THRESHOLD:-2}
      - GATEWAY_OPENAI_HTTP2_FALLBACK_WINDOW_SECONDS=${GATEWAY_OPENAI_HTTP2_FALLBACK_WINDOW_SECONDS:-60}
      - GATEWAY_OPENAI_HTTP2_FALLBACK_TTL_SECONDS=${GATEWAY_OPENAI_HTTP2_FALLBACK_TTL_SECONDS:-600}
      - GATEWAY_IMAGE_STREAM_DATA_INTERVAL_TIMEOUT=${GATEWAY_IMAGE_STREAM_DATA_INTERVAL_TIMEOUT:-900}
      - GATEWAY_IMAGE_STREAM_KEEPALIVE_INTERVAL=${GATEWAY_IMAGE_STREAM_KEEPALIVE_INTERVAL:-10}
      - GATEWAY_IMAGE_CONCURRENCY_ENABLED=${GATEWAY_IMAGE_CONCURRENCY_ENABLED:-false}
      - GATEWAY_IMAGE_CONCURRENCY_MAX_CONCURRENT_REQUESTS=${GATEWAY_IMAGE_CONCURRENCY_MAX_CONCURRENT_REQUESTS:-0}
      - GATEWAY_IMAGE_CONCURRENCY_OVERFLOW_MODE=${GATEWAY_IMAGE_CONCURRENCY_OVERFLOW_MODE:-reject}
      - GATEWAY_IMAGE_CONCURRENCY_WAIT_TIMEOUT_SECONDS=${GATEWAY_IMAGE_CONCURRENCY_WAIT_TIMEOUT_SECONDS:-30}
      - GATEWAY_IMAGE_CONCURRENCY_MAX_WAITING_REQUESTS=${GATEWAY_IMAGE_CONCURRENCY_MAX_WAITING_REQUESTS:-100}
    healthcheck:
      test: ["CMD", "wget", "-q", "-T", "5", "-O", "/dev/null", "http://localhost:10086/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s
```

::: warning 关于健康检查端口
`healthcheck` 中的端口必须与 `SERVER_PORT` 一致，否则容器健康检查会一直失败。若你修改了 `SERVER_PORT`，请同步修改 `healthcheck.test` 中的端口号。
:::

## 4. 启动服务

```shell
# 启动服务
docker compose up -d

# 查看日志
docker compose logs -f sub2api
```

## 5. 访问

浏览器打开 `http://your-domain-or-ip:10086/`（端口对应 `SERVER_PORT`），使用 `ADMIN_EMAIL` 和 `ADMIN_PASSWORD` 登录即可。
