Merge upstream/main: v0.1.85-v0.1.86 updates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,52 @@ SERVER_PORT=8080
|
||||
# Server mode: release or debug
|
||||
SERVER_MODE=release
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Logging Configuration
|
||||
# 日志配置
|
||||
# -----------------------------------------------------------------------------
|
||||
# 日志级别:debug/info/warn/error
|
||||
LOG_LEVEL=info
|
||||
# 日志格式:json/console
|
||||
LOG_FORMAT=json
|
||||
# 每条日志附带的 service 字段
|
||||
LOG_SERVICE_NAME=sub2api
|
||||
# 每条日志附带的 env 字段
|
||||
LOG_ENV=production
|
||||
# 是否输出调用方位置信息
|
||||
LOG_CALLER=true
|
||||
# 堆栈输出阈值:none/error/fatal
|
||||
LOG_STACKTRACE_LEVEL=error
|
||||
|
||||
# 输出开关(建议容器内保持双输出)
|
||||
# 是否输出到 stdout/stderr
|
||||
LOG_OUTPUT_TO_STDOUT=true
|
||||
# 是否输出到文件
|
||||
LOG_OUTPUT_TO_FILE=true
|
||||
# 日志文件路径(留空自动推导):
|
||||
# - 设置 DATA_DIR:${DATA_DIR}/logs/sub2api.log
|
||||
# - 未设置 DATA_DIR:/app/data/logs/sub2api.log
|
||||
LOG_OUTPUT_FILE_PATH=
|
||||
|
||||
# 滚动配置
|
||||
# 单文件最大体积(MB)
|
||||
LOG_ROTATION_MAX_SIZE_MB=100
|
||||
# 保留历史文件数量(0 表示不限制)
|
||||
LOG_ROTATION_MAX_BACKUPS=10
|
||||
# 历史日志保留天数(0 表示不限制)
|
||||
LOG_ROTATION_MAX_AGE_DAYS=7
|
||||
# 是否压缩历史日志
|
||||
LOG_ROTATION_COMPRESS=true
|
||||
# 滚动文件时间戳是否使用本地时间
|
||||
LOG_ROTATION_LOCAL_TIME=true
|
||||
|
||||
# 采样配置(高频重复日志降噪)
|
||||
LOG_SAMPLING_ENABLED=false
|
||||
# 每秒前 N 条日志不采样
|
||||
LOG_SAMPLING_INITIAL=100
|
||||
# 之后每 N 条保留 1 条
|
||||
LOG_SAMPLING_THEREAFTER=100
|
||||
|
||||
# Global max request body size in bytes (default: 100MB)
|
||||
# 全局最大请求体大小(字节,默认 100MB)
|
||||
# Applies to all requests, especially important for h2c first request memory protection
|
||||
@@ -58,13 +104,67 @@ TZ=Asia/Shanghai
|
||||
POSTGRES_USER=sub2api
|
||||
POSTGRES_PASSWORD=change_this_secure_password
|
||||
POSTGRES_DB=sub2api
|
||||
# PostgreSQL 监听端口(同时用于 PG 服务端和应用连接,默认 5432)
|
||||
DATABASE_PORT=5432
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PostgreSQL 服务端参数(可选;主要用于 deploy/docker-compose-aicodex.yml)
|
||||
# -----------------------------------------------------------------------------
|
||||
# POSTGRES_MAX_CONNECTIONS:PostgreSQL 服务端允许的最大连接数。
|
||||
# 必须 >=(所有 Sub2API 实例的 DATABASE_MAX_OPEN_CONNS 之和)+ 预留余量(例如 20%)。
|
||||
POSTGRES_MAX_CONNECTIONS=1024
|
||||
# POSTGRES_SHARED_BUFFERS:PostgreSQL 用于缓存数据页的共享内存。
|
||||
# 常见建议:物理内存的 10%~25%(容器内存受限时请按实际限制调整)。
|
||||
# 8GB 内存容器参考:1GB。
|
||||
POSTGRES_SHARED_BUFFERS=1GB
|
||||
# POSTGRES_EFFECTIVE_CACHE_SIZE:查询规划器“假设可用的 OS 缓存大小”(不等于实际分配)。
|
||||
# 常见建议:物理内存的 50%~75%。
|
||||
# 8GB 内存容器参考:6GB。
|
||||
POSTGRES_EFFECTIVE_CACHE_SIZE=4GB
|
||||
# POSTGRES_MAINTENANCE_WORK_MEM:维护操作内存(VACUUM/CREATE INDEX 等)。
|
||||
# 值越大维护越快,但会占用更多内存。
|
||||
# 8GB 内存容器参考:128MB。
|
||||
POSTGRES_MAINTENANCE_WORK_MEM=128MB
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PostgreSQL 连接池参数(可选,默认与程序内置一致)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 说明:
|
||||
# - 这些参数控制 Sub2API 进程到 PostgreSQL 的连接池大小(不是 PostgreSQL 自身的 max_connections)。
|
||||
# - 多实例/多副本部署时,总连接上限约等于:实例数 * DATABASE_MAX_OPEN_CONNS。
|
||||
# - 连接池过大可能导致:数据库连接耗尽、内存占用上升、上下文切换增多,反而变慢。
|
||||
# - 建议结合 PostgreSQL 的 max_connections 与机器规格逐步调优:
|
||||
# 通常把应用总连接上限控制在 max_connections 的 50%~80% 更稳妥。
|
||||
#
|
||||
# DATABASE_MAX_OPEN_CONNS:最大打开连接数(活跃+空闲),达到后新请求会等待可用连接。
|
||||
# 典型范围:50~500(取决于 DB 规格、实例数、SQL 复杂度)。
|
||||
DATABASE_MAX_OPEN_CONNS=256
|
||||
# DATABASE_MAX_IDLE_CONNS:最大空闲连接数(热连接),建议 <= MAX_OPEN。
|
||||
# 太小会频繁建连增加延迟;太大会长期占用数据库资源。
|
||||
DATABASE_MAX_IDLE_CONNS=128
|
||||
# DATABASE_CONN_MAX_LIFETIME_MINUTES:单个连接最大存活时间(单位:分钟)。
|
||||
# 用于避免连接长期不重建导致的中间件/LB/NAT 异常或服务端重启后的“僵尸连接”。
|
||||
# 设置为 0 表示不限制(一般不建议生产环境)。
|
||||
DATABASE_CONN_MAX_LIFETIME_MINUTES=30
|
||||
# DATABASE_CONN_MAX_IDLE_TIME_MINUTES:空闲连接最大存活时间(单位:分钟)。
|
||||
# 超过该时间的空闲连接会被回收,防止长时间闲置占用连接数。
|
||||
# 设置为 0 表示不限制(一般不建议生产环境)。
|
||||
DATABASE_CONN_MAX_IDLE_TIME_MINUTES=5
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Redis Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
# Redis 监听端口(同时用于应用连接和 Redis 服务端,默认 6379)
|
||||
REDIS_PORT=6379
|
||||
# Leave empty for no password (default for local development)
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DB=0
|
||||
# Redis 服务端最大客户端连接数(可选;主要用于 deploy/docker-compose-aicodex.yml)
|
||||
REDIS_MAXCLIENTS=50000
|
||||
# Redis 连接池大小(默认 1024)
|
||||
REDIS_POOL_SIZE=4096
|
||||
# Redis 最小空闲连接数(默认 10)
|
||||
REDIS_MIN_IDLE_CONNS=256
|
||||
REDIS_ENABLE_TLS=false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -86,6 +186,11 @@ ADMIN_PASSWORD=
|
||||
# Generate a secure secret: openssl rand -hex 32
|
||||
JWT_SECRET=
|
||||
JWT_EXPIRE_HOUR=24
|
||||
# Access Token 有效期(分钟)
|
||||
# 优先级说明:
|
||||
# - >0: 按分钟生效(优先于 JWT_EXPIRE_HOUR)
|
||||
# - =0: 回退使用 JWT_EXPIRE_HOUR
|
||||
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=0
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TOTP (2FA) Configuration
|
||||
@@ -107,6 +212,19 @@ TOTP_ENCRYPTION_KEY=
|
||||
# Leave unset to use default ./config.yaml
|
||||
#CONFIG_FILE=./config.yaml
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Built-in OAuth Client Secrets (Optional)
|
||||
# -----------------------------------------------------------------------------
|
||||
# SECURITY NOTE:
|
||||
# - 本项目不会在代码仓库中内置第三方 OAuth client_secret。
|
||||
# - 如需使用“内置客户端”(而不是自建 OAuth Client),请在运行环境通过 env 注入。
|
||||
#
|
||||
# Gemini CLI built-in OAuth client_secret(用于 Gemini code_assist/google_one 内置登录流)
|
||||
# GEMINI_CLI_OAUTH_CLIENT_SECRET=
|
||||
#
|
||||
# Antigravity OAuth client_secret(用于 Antigravity OAuth 登录流)
|
||||
# ANTIGRAVITY_OAUTH_CLIENT_SECRET=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Rate Limiting (Optional)
|
||||
# 速率限制(可选)
|
||||
@@ -119,6 +237,19 @@ RATE_LIMIT_OVERLOAD_COOLDOWN_MINUTES=10
|
||||
# Gateway Scheduling (Optional)
|
||||
# 调度缓存与受控回源配置(缓存就绪且命中时不读 DB)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Force Codex CLI mode: treat all /openai/v1/responses requests as Codex CLI.
|
||||
# 强制按 Codex CLI 处理 /openai/v1/responses 请求(用于网关未透传/改写 User-Agent 的兜底)。
|
||||
#
|
||||
# 注意:开启后会影响所有客户端的行为(不仅限于 VS Code / Codex CLI),请谨慎开启。
|
||||
#
|
||||
# 默认:false
|
||||
GATEWAY_FORCE_CODEX_CLI=false
|
||||
# 上游连接池:每主机最大连接数(默认 1024;流式/HTTP1.1 场景可调大,如 2400/4096)
|
||||
GATEWAY_MAX_CONNS_PER_HOST=2048
|
||||
# 上游连接池:最大空闲连接总数(默认 2560;账号/代理隔离 + 高并发场景可调大)
|
||||
GATEWAY_MAX_IDLE_CONNS=8192
|
||||
# 上游连接池:每主机最大空闲连接(默认 120)
|
||||
GATEWAY_MAX_IDLE_CONNS_PER_HOST=4096
|
||||
# 粘性会话最大排队长度
|
||||
GATEWAY_SCHEDULING_STICKY_SESSION_MAX_WAITING=3
|
||||
# 粘性会话等待超时(时间段,例如 45s)
|
||||
|
||||
@@ -1,39 +1,6 @@
|
||||
# =============================================================================
|
||||
# Sub2API Caddy Reverse Proxy Configuration (宿主机部署)
|
||||
# =============================================================================
|
||||
# 使用方法:
|
||||
# 1. 安装 Caddy: https://caddyserver.com/docs/install
|
||||
# 2. 修改下方 example.com 为你的域名
|
||||
# 3. 确保域名 DNS 已指向服务器
|
||||
# 4. 复制配置: sudo cp Caddyfile /etc/caddy/Caddyfile
|
||||
# 5. 重载配置: sudo systemctl reload caddy
|
||||
#
|
||||
# Caddy 会自动申请和续期 Let's Encrypt SSL 证书
|
||||
# =============================================================================
|
||||
|
||||
# 全局配置
|
||||
{
|
||||
# Let's Encrypt 邮箱通知
|
||||
email admin@example.com
|
||||
|
||||
# 服务器配置
|
||||
servers {
|
||||
# 启用 HTTP/2 和 HTTP/3
|
||||
protocols h1 h2 h3
|
||||
|
||||
# 超时配置
|
||||
timeouts {
|
||||
read_body 30s
|
||||
read_header 10s
|
||||
write 300s
|
||||
idle 300s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 修改为你的域名
|
||||
example.com {
|
||||
# =========================================================================
|
||||
api.sub2api.com {
|
||||
# =========================================================================
|
||||
# 静态资源长期缓存(高优先级,放在最前面)
|
||||
# 带 hash 的文件可以永久缓存,浏览器和 CDN 都会缓存
|
||||
# =========================================================================
|
||||
@@ -93,10 +60,7 @@ example.com {
|
||||
write_buffer 16KB
|
||||
compression off
|
||||
}
|
||||
|
||||
# SSE/流式传输优化:禁用响应缓冲,立即刷新数据给客户端
|
||||
flush_interval -1
|
||||
|
||||
|
||||
# 故障转移
|
||||
fail_duration 30s
|
||||
max_fails 3
|
||||
@@ -111,10 +75,6 @@ example.com {
|
||||
gzip 6
|
||||
minimum_length 256
|
||||
match {
|
||||
# SSE 请求通常会带 Accept: text/event-stream,需排除压缩
|
||||
not header Accept text/event-stream*
|
||||
# 排除已知 SSE 路径(即便 Accept 缺失)
|
||||
not path /v1/messages /v1/responses /responses /antigravity/v1/messages /v1beta/models/* /antigravity/v1beta/models/*
|
||||
header Content-Type text/*
|
||||
header Content-Type application/json*
|
||||
header Content-Type application/javascript*
|
||||
@@ -124,53 +84,6 @@ example.com {
|
||||
}
|
||||
}
|
||||
|
||||
# =========================================================================
|
||||
# 速率限制 (需要 caddy-ratelimit 插件)
|
||||
# 如未安装插件,请注释掉此段
|
||||
# =========================================================================
|
||||
# rate_limit {
|
||||
# zone api {
|
||||
# key {remote_host}
|
||||
# events 100
|
||||
# window 1m
|
||||
# }
|
||||
# }
|
||||
|
||||
# =========================================================================
|
||||
# 安全响应头
|
||||
# =========================================================================
|
||||
header {
|
||||
# 防止点击劫持
|
||||
X-Frame-Options "SAMEORIGIN"
|
||||
|
||||
# XSS 保护
|
||||
X-XSS-Protection "1; mode=block"
|
||||
|
||||
# 防止 MIME 类型嗅探
|
||||
X-Content-Type-Options "nosniff"
|
||||
|
||||
# 引用策略
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
|
||||
# HSTS - 强制 HTTPS (max-age=1年)
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
|
||||
# 内容安全策略 (根据需要调整)
|
||||
# Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:;"
|
||||
|
||||
# 权限策略
|
||||
Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
|
||||
|
||||
# 跨域资源策略
|
||||
Cross-Origin-Opener-Policy "same-origin"
|
||||
Cross-Origin-Embedder-Policy "require-corp"
|
||||
Cross-Origin-Resource-Policy "same-origin"
|
||||
|
||||
# 移除敏感头
|
||||
-Server
|
||||
-X-Powered-By
|
||||
}
|
||||
|
||||
# =========================================================================
|
||||
# 请求大小限制 (防止大文件攻击)
|
||||
# =========================================================================
|
||||
@@ -198,7 +111,3 @@ example.com {
|
||||
respond "{err.status_code} {err.status_text}"
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# HTTP 重定向到 HTTPS (Caddy 默认自动处理,此处显式声明)
|
||||
# =============================================================================
|
||||
|
||||
111
deploy/Dockerfile
Normal file
111
deploy/Dockerfile
Normal file
@@ -0,0 +1,111 @@
|
||||
# =============================================================================
|
||||
# Sub2API Multi-Stage Dockerfile
|
||||
# =============================================================================
|
||||
# Stage 1: Build frontend
|
||||
# Stage 2: Build Go backend with embedded frontend
|
||||
# Stage 3: Final minimal image
|
||||
# =============================================================================
|
||||
|
||||
ARG NODE_IMAGE=node:24-alpine
|
||||
ARG GOLANG_IMAGE=golang:1.25.5-alpine
|
||||
ARG ALPINE_IMAGE=alpine:3.20
|
||||
ARG GOPROXY=https://goproxy.cn,direct
|
||||
ARG GOSUMDB=sum.golang.google.cn
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Stage 1: Frontend Builder
|
||||
# -----------------------------------------------------------------------------
|
||||
FROM ${NODE_IMAGE} AS frontend-builder
|
||||
|
||||
WORKDIR /app/frontend
|
||||
|
||||
# Install pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Install dependencies first (better caching)
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy frontend source and build
|
||||
COPY frontend/ ./
|
||||
RUN pnpm run build
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Stage 2: Backend Builder
|
||||
# -----------------------------------------------------------------------------
|
||||
FROM ${GOLANG_IMAGE} AS backend-builder
|
||||
|
||||
# Build arguments for version info (set by CI)
|
||||
ARG VERSION=docker
|
||||
ARG COMMIT=docker
|
||||
ARG DATE
|
||||
ARG GOPROXY
|
||||
ARG GOSUMDB
|
||||
|
||||
ENV GOPROXY=${GOPROXY}
|
||||
ENV GOSUMDB=${GOSUMDB}
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache git ca-certificates tzdata
|
||||
|
||||
WORKDIR /app/backend
|
||||
|
||||
# Copy go mod files first (better caching)
|
||||
COPY backend/go.mod backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy backend source first
|
||||
COPY backend/ ./
|
||||
|
||||
# Copy frontend dist from previous stage (must be after backend copy to avoid being overwritten)
|
||||
COPY --from=frontend-builder /app/backend/internal/web/dist ./internal/web/dist
|
||||
|
||||
# Build the binary (BuildType=release for CI builds, embed frontend)
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-tags embed \
|
||||
-ldflags="-s -w -X main.Commit=${COMMIT} -X main.Date=${DATE:-$(date -u +%Y-%m-%dT%H:%M:%SZ)} -X main.BuildType=release" \
|
||||
-o /app/sub2api \
|
||||
./cmd/server
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Stage 3: Final Runtime Image
|
||||
# -----------------------------------------------------------------------------
|
||||
FROM ${ALPINE_IMAGE}
|
||||
|
||||
# Labels
|
||||
LABEL maintainer="Wei-Shaw <github.com/Wei-Shaw>"
|
||||
LABEL description="Sub2API - AI API Gateway Platform"
|
||||
LABEL org.opencontainers.image.source="https://github.com/Wei-Shaw/sub2api"
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
curl \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1000 sub2api && \
|
||||
adduser -u 1000 -G sub2api -s /bin/sh -D sub2api
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy binary from builder
|
||||
COPY --from=backend-builder /app/sub2api /app/sub2api
|
||||
|
||||
# Create data directory
|
||||
RUN mkdir -p /app/data && chown -R sub2api:sub2api /app
|
||||
|
||||
# Switch to non-root user
|
||||
USER sub2api
|
||||
|
||||
# Expose port (can be overridden by SERVER_PORT env var)
|
||||
EXPOSE 8080
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||
CMD curl -f http://localhost:${SERVER_PORT:-8080}/health || exit 1
|
||||
|
||||
# Run the application
|
||||
ENTRYPOINT ["/app/sub2api"]
|
||||
@@ -303,6 +303,10 @@ Requires your own OAuth client credentials.
|
||||
```bash
|
||||
GEMINI_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
|
||||
GEMINI_OAUTH_CLIENT_SECRET=GOCSPX-your-client-secret
|
||||
|
||||
# 可选:如需使用 Gemini CLI 内置 OAuth Client(Code Assist / Google One)
|
||||
# 安全说明:本仓库不会内置该 client_secret,请在运行环境通过环境变量注入。
|
||||
# GEMINI_CLI_OAUTH_CLIENT_SECRET=GOCSPX-your-built-in-secret
|
||||
```
|
||||
|
||||
**Step 3: Create Account in Admin UI**
|
||||
@@ -430,6 +434,11 @@ If you need to use AI Studio OAuth for Gemini accounts, add the OAuth client cre
|
||||
Environment=GEMINI_OAUTH_CLIENT_SECRET=GOCSPX-your-client-secret
|
||||
```
|
||||
|
||||
如需使用“内置 Gemini CLI OAuth Client”(Code Assist / Google One),还需要注入:
|
||||
```ini
|
||||
Environment=GEMINI_CLI_OAUTH_CLIENT_SECRET=GOCSPX-your-built-in-secret
|
||||
```
|
||||
|
||||
3. Reload and restart:
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# 本地构建镜像的快速脚本,避免在命令行反复输入构建参数。
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
docker build -t sub2api:latest \
|
||||
--build-arg GOPROXY=https://goproxy.cn,direct \
|
||||
--build-arg GOSUMDB=sum.golang.google.cn \
|
||||
-f Dockerfile \
|
||||
.
|
||||
-f "${REPO_ROOT}/Dockerfile" \
|
||||
"${REPO_ROOT}"
|
||||
|
||||
@@ -20,6 +20,10 @@ server:
|
||||
# Mode: "debug" for development, "release" for production
|
||||
# 运行模式:"debug" 用于开发,"release" 用于生产环境
|
||||
mode: "release"
|
||||
# Frontend base URL used to generate external links in emails (e.g. password reset)
|
||||
# 用于生成邮件中的外部链接(例如:重置密码链接)的前端基础地址
|
||||
# Example: "https://example.com"
|
||||
frontend_url: ""
|
||||
# Trusted proxies for X-Forwarded-For parsing (CIDR/IP). Empty disables trusted proxies.
|
||||
# 信任的代理地址(CIDR/IP 格式),用于解析 X-Forwarded-For 头。留空则禁用代理信任。
|
||||
trusted_proxies: []
|
||||
@@ -108,9 +112,9 @@ security:
|
||||
# 白名单禁用时是否允许 http:// URL(默认: false,要求 https)
|
||||
allow_insecure_http: true
|
||||
response_headers:
|
||||
# Enable configurable response header filtering (disable to use default allowlist)
|
||||
# 启用可配置的响应头过滤(禁用则使用默认白名单)
|
||||
enabled: false
|
||||
# Enable configurable response header filtering (default: true)
|
||||
# 启用可配置的响应头过滤(默认启用,过滤上游敏感响应头)
|
||||
enabled: true
|
||||
# Extra allowed response headers from upstream
|
||||
# 额外允许的上游响应头
|
||||
additional_allowed: []
|
||||
@@ -142,6 +146,42 @@ gateway:
|
||||
# Max request body size in bytes (default: 100MB)
|
||||
# 请求体最大字节数(默认 100MB)
|
||||
max_body_size: 104857600
|
||||
# Max bytes to read for non-stream upstream responses (default: 8MB)
|
||||
# 非流式上游响应体读取上限(默认 8MB)
|
||||
upstream_response_read_max_bytes: 8388608
|
||||
# Max bytes to read for proxy probe responses (default: 1MB)
|
||||
# 代理探测响应体读取上限(默认 1MB)
|
||||
proxy_probe_response_read_max_bytes: 1048576
|
||||
# Enable Gemini upstream response header debug logs (default: false)
|
||||
# 是否开启 Gemini 上游响应头调试日志(默认 false)
|
||||
gemini_debug_response_headers: false
|
||||
# Sora max request body size in bytes (0=use max_body_size)
|
||||
# Sora 请求体最大字节数(0=使用 max_body_size)
|
||||
sora_max_body_size: 268435456
|
||||
# Sora stream timeout (seconds, 0=disable)
|
||||
# Sora 流式请求总超时(秒,0=禁用)
|
||||
sora_stream_timeout_seconds: 900
|
||||
# Sora non-stream timeout (seconds, 0=disable)
|
||||
# Sora 非流式请求超时(秒,0=禁用)
|
||||
sora_request_timeout_seconds: 180
|
||||
# Sora stream enforcement mode: force/error
|
||||
# Sora stream 强制策略:force/error
|
||||
sora_stream_mode: "force"
|
||||
# Sora model filters
|
||||
# Sora 模型过滤配置
|
||||
sora_model_filters:
|
||||
# Hide prompt-enhance models by default
|
||||
# 默认隐藏 prompt-enhance 模型
|
||||
hide_prompt_enhance: true
|
||||
# Require API key for /sora/media proxy (default: false)
|
||||
# /sora/media 是否强制要求 API Key(默认 true)
|
||||
sora_media_require_api_key: true
|
||||
# Sora media temporary signing key (empty disables signed URL)
|
||||
# Sora 媒体临时签名密钥(为空则禁用签名)
|
||||
sora_media_signing_key: ""
|
||||
# Signed URL TTL seconds (<=0 disables)
|
||||
# 临时签名 URL 有效期(秒,<=0 表示禁用)
|
||||
sora_media_signed_url_ttl_seconds: 900
|
||||
# Connection pool isolation strategy:
|
||||
# 连接池隔离策略:
|
||||
# - proxy: Isolate by proxy, same proxy shares connection pool (suitable for few proxies, many accounts)
|
||||
@@ -151,17 +191,25 @@ gateway:
|
||||
# - account_proxy: Isolate by account+proxy combination (default, finest granularity)
|
||||
# - account_proxy: 按账户+代理组合隔离(默认,最细粒度)
|
||||
connection_pool_isolation: "account_proxy"
|
||||
# Force Codex CLI mode: treat all /openai/v1/responses requests as Codex CLI.
|
||||
# 强制按 Codex CLI 处理 /openai/v1/responses 请求(用于网关未透传/改写 User-Agent 的兜底)。
|
||||
#
|
||||
# 注意:开启后会影响所有客户端的行为(不仅限于 VS Code / Codex CLI),请谨慎开启。
|
||||
force_codex_cli: false
|
||||
# OpenAI 透传模式是否放行客户端超时头(如 x-stainless-timeout)
|
||||
# 默认 false:过滤超时头,降低上游提前断流风险。
|
||||
openai_passthrough_allow_timeout_headers: false
|
||||
# HTTP upstream connection pool settings (HTTP/2 + multi-proxy scenario defaults)
|
||||
# HTTP 上游连接池配置(HTTP/2 + 多代理场景默认值)
|
||||
# Max idle connections across all hosts
|
||||
# 所有主机的最大空闲连接数
|
||||
max_idle_conns: 240
|
||||
max_idle_conns: 2560
|
||||
# Max idle connections per host
|
||||
# 每个主机的最大空闲连接数
|
||||
max_idle_conns_per_host: 120
|
||||
# Max connections per host
|
||||
# 每个主机的最大连接数
|
||||
max_conns_per_host: 240
|
||||
max_conns_per_host: 1024
|
||||
# Idle connection timeout (seconds)
|
||||
# 空闲连接超时时间(秒)
|
||||
idle_conn_timeout_seconds: 90
|
||||
@@ -246,9 +294,177 @@ gateway:
|
||||
# name: "Custom Profile 1"
|
||||
# profile_2:
|
||||
# name: "Custom Profile 2"
|
||||
# cipher_suites: [4866, 4867, 4865, 49199, 49195, 49200, 49196]
|
||||
# curves: [29, 23, 24]
|
||||
# point_formats: [0]
|
||||
|
||||
# =============================================================================
|
||||
# Logging Configuration
|
||||
# 日志配置
|
||||
# =============================================================================
|
||||
log:
|
||||
# Log level: debug/info/warn/error
|
||||
# 日志级别:debug/info/warn/error
|
||||
level: "info"
|
||||
# Log format: json/console
|
||||
# 日志格式:json/console
|
||||
format: "console"
|
||||
# Service name field written into each log line
|
||||
# 每条日志都会附带 service 字段
|
||||
service_name: "sub2api"
|
||||
# Environment field written into each log line
|
||||
# 每条日志都会附带 env 字段
|
||||
env: "production"
|
||||
# Include caller information
|
||||
# 是否输出调用方位置信息
|
||||
caller: true
|
||||
# Stacktrace threshold: none/error/fatal
|
||||
# 堆栈输出阈值:none/error/fatal
|
||||
stacktrace_level: "error"
|
||||
output:
|
||||
# Keep stdout/stderr output for container log collection
|
||||
# 保持标准输出用于容器日志采集
|
||||
to_stdout: true
|
||||
# Enable file output (default path auto-derived)
|
||||
# 启用文件输出(默认路径自动推导)
|
||||
to_file: true
|
||||
# Empty means:
|
||||
# - DATA_DIR set: {{DATA_DIR}}/logs/sub2api.log
|
||||
# - otherwise: /app/data/logs/sub2api.log
|
||||
# 留空时:
|
||||
# - 设置 DATA_DIR:{{DATA_DIR}}/logs/sub2api.log
|
||||
# - 否则:/app/data/logs/sub2api.log
|
||||
file_path: ""
|
||||
rotation:
|
||||
# Max file size before rotation (MB)
|
||||
# 单文件滚动阈值(MB)
|
||||
max_size_mb: 100
|
||||
# Number of rotated files to keep (0 means unlimited)
|
||||
# 保留历史文件数量(0 表示不限制)
|
||||
max_backups: 10
|
||||
# Number of days to keep old log files (0 means unlimited)
|
||||
# 历史日志保留天数(0 表示不限制)
|
||||
max_age_days: 7
|
||||
# Compress rotated files
|
||||
# 是否压缩历史日志
|
||||
compress: true
|
||||
# Use local time for timestamp in rotated filename
|
||||
# 滚动文件名时间戳使用本地时区
|
||||
local_time: true
|
||||
sampling:
|
||||
# Enable zap sampler (reduce high-frequency repetitive logs)
|
||||
# 启用 zap 采样(减少高频重复日志)
|
||||
enabled: false
|
||||
# Number of first entries per second to always log
|
||||
# 每秒无采样保留的前 N 条日志
|
||||
initial: 100
|
||||
# Thereafter keep 1 out of N entries per second
|
||||
# 之后每 N 条保留 1 条
|
||||
thereafter: 100
|
||||
|
||||
# =============================================================================
|
||||
# Sora Direct Client Configuration
|
||||
# Sora 直连配置
|
||||
# =============================================================================
|
||||
sora:
|
||||
client:
|
||||
# Sora backend base URL
|
||||
# Sora 上游 Base URL
|
||||
base_url: "https://sora.chatgpt.com/backend"
|
||||
# Request timeout (seconds)
|
||||
# 请求超时(秒)
|
||||
timeout_seconds: 120
|
||||
# Max retries for upstream requests
|
||||
# 上游请求最大重试次数
|
||||
max_retries: 3
|
||||
# Account+proxy cooldown window after Cloudflare challenge (seconds, 0 to disable)
|
||||
# Cloudflare challenge 后按账号+代理冷却窗口(秒,0 表示关闭)
|
||||
cloudflare_challenge_cooldown_seconds: 900
|
||||
# Poll interval (seconds)
|
||||
# 轮询间隔(秒)
|
||||
poll_interval_seconds: 2
|
||||
# Max poll attempts
|
||||
# 最大轮询次数
|
||||
max_poll_attempts: 600
|
||||
# Recent task query limit (image)
|
||||
# 最近任务查询数量(图片轮询)
|
||||
recent_task_limit: 50
|
||||
# Recent task query max limit (fallback)
|
||||
# 最近任务查询最大数量(回退)
|
||||
recent_task_limit_max: 200
|
||||
# Enable debug logs for Sora upstream requests
|
||||
# 启用 Sora 直连调试日志
|
||||
# 调试日志会输出上游请求尝试、重试、响应摘要;Authorization/openai-sentinel-token 等敏感头会自动脱敏
|
||||
debug: false
|
||||
# Allow Sora client to fetch token via OpenAI token provider
|
||||
# 是否允许 Sora 客户端通过 OpenAI token provider 取 token(默认 false,避免误走 OpenAI 刷新链路)
|
||||
use_openai_token_provider: false
|
||||
# Optional custom headers (key-value)
|
||||
# 额外请求头(键值对)
|
||||
headers: {}
|
||||
# Default User-Agent for Sora requests
|
||||
# Sora 默认 User-Agent
|
||||
user_agent: "Sora/1.2026.007 (Android 15; 24122RKC7C; build 2600700)"
|
||||
# Disable TLS fingerprint for Sora upstream
|
||||
# 关闭 Sora 上游 TLS 指纹伪装
|
||||
disable_tls_fingerprint: false
|
||||
# curl_cffi sidecar for Sora only (required)
|
||||
# 仅 Sora 链路使用的 curl_cffi sidecar(必需)
|
||||
curl_cffi_sidecar:
|
||||
# Sora 强制通过 sidecar 请求,必须启用
|
||||
# Sora is forced to use sidecar only; keep enabled=true
|
||||
enabled: true
|
||||
# Sidecar base URL (default endpoint: /request)
|
||||
# sidecar 基础地址(默认请求端点:/request)
|
||||
base_url: "http://sora-curl-cffi-sidecar:8080"
|
||||
# curl_cffi impersonate profile, e.g. chrome131/chrome124/safari18_0
|
||||
# curl_cffi 指纹伪装 profile,例如 chrome131/chrome124/safari18_0
|
||||
impersonate: "chrome131"
|
||||
# Sidecar request timeout (seconds)
|
||||
# sidecar 请求超时(秒)
|
||||
timeout_seconds: 60
|
||||
# Reuse session key per account+proxy to let sidecar persist cookies/session
|
||||
# 按账号+代理复用 session key,让 sidecar 持久化 cookies/session
|
||||
session_reuse_enabled: true
|
||||
# Session TTL in sidecar (seconds)
|
||||
# sidecar 会话 TTL(秒)
|
||||
session_ttl_seconds: 3600
|
||||
storage:
|
||||
# Storage type (local only for now)
|
||||
# 存储类型(首发仅支持 local)
|
||||
type: "local"
|
||||
# Local base path; empty uses /app/data/sora
|
||||
# 本地存储基础路径;为空使用 /app/data/sora
|
||||
local_path: ""
|
||||
# Fallback to upstream URL when download fails
|
||||
# 下载失败时回退到上游 URL
|
||||
fallback_to_upstream: true
|
||||
# Max concurrent downloads
|
||||
# 并发下载上限
|
||||
max_concurrent_downloads: 4
|
||||
# Download timeout (seconds)
|
||||
# 下载超时(秒)
|
||||
download_timeout_seconds: 120
|
||||
# Max download bytes
|
||||
# 最大下载字节数
|
||||
max_download_bytes: 209715200
|
||||
# Enable debug logs for media storage
|
||||
# 启用媒体存储调试日志
|
||||
debug: false
|
||||
cleanup:
|
||||
# Enable cleanup task
|
||||
# 启用清理任务
|
||||
enabled: true
|
||||
# Retention days
|
||||
# 保留天数
|
||||
retention_days: 7
|
||||
# Cron schedule
|
||||
# Cron 调度表达式
|
||||
schedule: "0 3 * * *"
|
||||
|
||||
# Token refresh behavior
|
||||
# token 刷新行为控制
|
||||
token_refresh:
|
||||
# Whether OpenAI refresh flow is allowed to sync linked Sora accounts
|
||||
# 是否允许 OpenAI 刷新流程同步覆盖 linked_openai_account_id 关联的 Sora 账号 token
|
||||
sync_linked_sora_accounts: false
|
||||
|
||||
# =============================================================================
|
||||
# API Key Auth Cache Configuration
|
||||
@@ -352,6 +568,30 @@ usage_cleanup:
|
||||
# 单次任务最大执行时长(秒)
|
||||
task_timeout_seconds: 1800
|
||||
|
||||
# =============================================================================
|
||||
# HTTP 写接口幂等配置
|
||||
# Idempotency Configuration
|
||||
# =============================================================================
|
||||
idempotency:
|
||||
# Observe-only 模式:
|
||||
# true: 观察期,不带 Idempotency-Key 仍放行(但会记录)
|
||||
# false: 强制期,不带 Idempotency-Key 直接拒绝(仅对接入幂等保护的接口生效)
|
||||
observe_only: true
|
||||
# 关键写接口幂等记录 TTL(秒)
|
||||
default_ttl_seconds: 86400
|
||||
# 系统操作接口(update/rollback/restart)幂等记录 TTL(秒)
|
||||
system_operation_ttl_seconds: 3600
|
||||
# processing 锁超时(秒)
|
||||
processing_timeout_seconds: 30
|
||||
# 可重试失败退避窗口(秒)
|
||||
failed_retry_backoff_seconds: 5
|
||||
# 持久化响应体最大长度(字节)
|
||||
max_stored_response_len: 65536
|
||||
# 过期幂等记录清理周期(秒)
|
||||
cleanup_interval_seconds: 60
|
||||
# 每轮清理最大删除条数
|
||||
cleanup_batch_size: 500
|
||||
|
||||
# =============================================================================
|
||||
# Concurrency Wait Configuration
|
||||
# 并发等待配置
|
||||
@@ -381,9 +621,22 @@ database:
|
||||
# Database name
|
||||
# 数据库名称
|
||||
dbname: "sub2api"
|
||||
# SSL mode: disable, require, verify-ca, verify-full
|
||||
# SSL 模式:disable(禁用), require(要求), verify-ca(验证CA), verify-full(完全验证)
|
||||
sslmode: "disable"
|
||||
# SSL mode: disable, prefer, require, verify-ca, verify-full
|
||||
# SSL 模式:disable(禁用), prefer(优先加密,默认), require(要求), verify-ca(验证CA), verify-full(完全验证)
|
||||
# 默认值为 "prefer",数据库支持 SSL 时自动使用加密连接,不支持时回退明文
|
||||
sslmode: "prefer"
|
||||
# Max open connections (高并发场景建议 256+,需配合 PostgreSQL max_connections 调整)
|
||||
# 最大打开连接数
|
||||
max_open_conns: 256
|
||||
# Max idle connections (建议为 max_open_conns 的 50%,减少频繁建连开销)
|
||||
# 最大空闲连接数
|
||||
max_idle_conns: 128
|
||||
# Connection max lifetime (minutes)
|
||||
# 连接最大存活时间(分钟)
|
||||
conn_max_lifetime_minutes: 30
|
||||
# Connection max idle time (minutes)
|
||||
# 空闲连接最大存活时间(分钟)
|
||||
conn_max_idle_time_minutes: 5
|
||||
|
||||
# =============================================================================
|
||||
# Redis Configuration
|
||||
@@ -402,6 +655,12 @@ redis:
|
||||
# Database number (0-15)
|
||||
# 数据库编号(0-15)
|
||||
db: 0
|
||||
# Connection pool size (max concurrent connections)
|
||||
# 连接池大小(最大并发连接数)
|
||||
pool_size: 1024
|
||||
# Minimum number of idle connections (高并发场景建议 128+,保持足够热连接)
|
||||
# 最小空闲连接数
|
||||
min_idle_conns: 128
|
||||
# Enable TLS/SSL connection
|
||||
# 是否启用 TLS/SSL 连接
|
||||
enable_tls: false
|
||||
@@ -428,9 +687,14 @@ jwt:
|
||||
# 重要:生产环境中请更改为随机字符串!
|
||||
# Generate with / 生成命令: openssl rand -hex 32
|
||||
secret: "change-this-to-a-secure-random-string"
|
||||
# Token expiration time in hours (max 24)
|
||||
# 令牌过期时间(小时,最大 24)
|
||||
# Token expiration time in hours (max 168)
|
||||
# 令牌过期时间(小时,最大 168)
|
||||
expire_hour: 24
|
||||
# Access Token 过期时间(分钟)
|
||||
# 优先级说明:
|
||||
# - >0: 按分钟生效(优先于 expire_hour)
|
||||
# - =0: 回退使用 expire_hour
|
||||
access_token_expire_minutes: 0
|
||||
|
||||
# =============================================================================
|
||||
# TOTP (2FA) Configuration
|
||||
@@ -517,10 +781,10 @@ rate_limit:
|
||||
pricing:
|
||||
# URL to fetch model pricing data (default: LiteLLM)
|
||||
# 获取模型定价数据的 URL(默认:LiteLLM)
|
||||
remote_url: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json"
|
||||
remote_url: "https://github.com/Wei-Shaw/model-price-repo/raw/refs/heads/main/model_prices_and_context_window.json"
|
||||
# Hash verification URL (optional)
|
||||
# 哈希校验 URL(可选)
|
||||
hash_url: ""
|
||||
hash_url: "https://github.com/Wei-Shaw/model-price-repo/raw/refs/heads/main/model_prices_and_context_window.sha256"
|
||||
# Local data directory for caching
|
||||
# 本地数据缓存目录
|
||||
data_dir: "./data"
|
||||
@@ -583,10 +847,14 @@ turnstile:
|
||||
# 默认:使用 Gemini CLI 的公开 OAuth 凭证(与 Google 官方 CLI 工具相同)
|
||||
gemini:
|
||||
oauth:
|
||||
# Gemini CLI public OAuth credentials (works for both Code Assist and AI Studio)
|
||||
# Gemini CLI 公开 OAuth 凭证(适用于 Code Assist 和 AI Studio)
|
||||
client_id: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com"
|
||||
client_secret: "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"
|
||||
# OAuth 客户端配置说明:
|
||||
# 1) 留空 client_id/client_secret:使用 Gemini CLI 内置 OAuth Client(其 client_secret 需通过环境变量注入)
|
||||
# - GEMINI_CLI_OAUTH_CLIENT_SECRET
|
||||
# 2) 同时设置 client_id/client_secret:使用你自建的 OAuth Client(推荐,权限更完整)
|
||||
#
|
||||
# 注意:client_id 与 client_secret 必须同时为空或同时非空。
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Optional scopes (space-separated). Leave empty to auto-select based on oauth_type.
|
||||
# 可选的权限范围(空格分隔)。留空则根据 oauth_type 自动选择。
|
||||
scopes: ""
|
||||
|
||||
@@ -33,7 +33,7 @@ services:
|
||||
# Data persistence (config.yaml will be auto-generated here)
|
||||
- sub2api_data:/app/data
|
||||
# Mount custom config.yaml (optional, overrides auto-generated config)
|
||||
- ./config.yaml:/app/data/config.yaml:ro
|
||||
# - ./config.yaml:/app/data/config.yaml:ro
|
||||
environment:
|
||||
# =======================================================================
|
||||
# Auto Setup (REQUIRED for Docker deployment)
|
||||
@@ -57,6 +57,10 @@ services:
|
||||
- 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
|
||||
@@ -65,6 +69,8 @@ services:
|
||||
- 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}
|
||||
|
||||
# =======================================================================
|
||||
# Admin Account (auto-created on first run)
|
||||
@@ -98,6 +104,11 @@ services:
|
||||
- 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)
|
||||
# =======================================================================
|
||||
@@ -131,6 +142,10 @@ services:
|
||||
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}
|
||||
@@ -150,7 +165,7 @@ services:
|
||||
# Redis Cache
|
||||
# ===========================================================================
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
image: redis:8-alpine
|
||||
container_name: sub2api-redis
|
||||
restart: unless-stopped
|
||||
ulimits:
|
||||
|
||||
@@ -62,6 +62,10 @@ services:
|
||||
- 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
|
||||
@@ -70,6 +74,8 @@ services:
|
||||
- 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}
|
||||
|
||||
# =======================================================================
|
||||
@@ -117,6 +123,11 @@ services:
|
||||
- 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)
|
||||
# =======================================================================
|
||||
|
||||
@@ -48,6 +48,10 @@ services:
|
||||
- DATABASE_PASSWORD=${DATABASE_PASSWORD:?DATABASE_PASSWORD is required}
|
||||
- DATABASE_DBNAME=${DATABASE_DBNAME:-sub2api}
|
||||
- DATABASE_SSLMODE=${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 - Required
|
||||
@@ -56,6 +60,8 @@ services:
|
||||
- REDIS_PORT=${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}
|
||||
|
||||
# =======================================================================
|
||||
@@ -82,6 +88,11 @@ services:
|
||||
- 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:-}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
|
||||
@@ -46,12 +46,18 @@ services:
|
||||
- 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
|
||||
- REDIS_HOST=${REDIS_HOST}
|
||||
- REDIS_PORT=${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
|
||||
@@ -88,6 +94,30 @@ services:
|
||||
- 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
|
||||
@@ -117,10 +147,13 @@ services:
|
||||
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}
|
||||
- PGDATA=/var/lib/postgresql/data
|
||||
- TZ=${TZ:-Asia/Shanghai}
|
||||
networks:
|
||||
- sub2api-network
|
||||
|
||||
Reference in New Issue
Block a user