File size: 10,256 Bytes
8059bf0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# =============================================================================
# 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 sub2api
#   4. Access: http://localhost:8080
#
# All configuration is done via environment variables.
# No Setup Wizard needed - the system auto-initializes on first run.
# =============================================================================

services:
  # ===========================================================================
  # Sub2API Application
  # ===========================================================================
  sub2api:
    image: weishaw/sub2api:latest
    container_name: sub2api
    restart: unless-stopped
    ulimits:
      nofile:
        soft: 100000
        hard: 100000
    ports:
      - "${BIND_HOST:-0.0.0.0}:${SERVER_PORT:-8080}:8080"
    volumes:
      # Data persistence (config.yaml will be auto-generated here)
      - sub2api_data:/app/data
      # 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
      - SERVER_PORT=8080
      - SERVER_MODE=${SERVER_MODE:-release}
      - RUN_MODE=${RUN_MODE:-standard}

      # =======================================================================
      # Database Configuration (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 Configuration
      # =======================================================================
      - 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 Account (auto-created on first run)
      # =======================================================================
      - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD:-}

      # =======================================================================
      # 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:-}

      # =======================================================================
      # 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:-}
    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=/var/lib/postgresql/18/docker(位于镜像声明的匿名卷 /var/lib/postgresql 内)。
      # 若不显式设置 PGDATA,则即使挂载了 postgres_data 到 /var/lib/postgresql/data,数据也不会落盘到该命名卷,
      # docker compose down/up 后会触发 initdb 重新初始化,导致用户/密码等数据丢失。
      - 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 is used by redis-cli for authentication (safer than -a flag)
      - REDISCLI_AUTH=${REDIS_PASSWORD:-}
    networks:
      - sub2api-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 5s

# =============================================================================
# Volumes
# =============================================================================
volumes:
  sub2api_data:
    driver: local
  postgres_data:
    driver: local
  redis_data:
    driver: local

# =============================================================================
# Networks
# =============================================================================
networks:
  sub2api-network:
    driver: bridge