新增 /v1beta/cachedContents 的创建、列表、查询、更新有效期与删除接口。 参与账号:官方地址的 AI Studio API Key 账号、Vertex service account 账号, 以及开启"上游支持显式缓存"的自定义地址 API Key 账号。 - 网关自发缓存 ID,绑定上游资源名、持有账号与创建它的 API Key (迁移 243 gemini_cached_contents);list/get 只读本地记录 - 引用缓存的 generateContent / streamGenerateContent / countTokens 改写为上游资源名,只发往持有缓存的账号,不参与会话粘性、不换号; 拒绝重复键与 snake_case 写法;在持有账号上重试耗尽后, 上游 429 / 5xx 原样透传,401 / 403 映射为 502 - 计费:创建时一次性收取缓存 token 输入费与整个有效期的存储费; 延长按库中实际推进的时长收费,纯存储费不算一次请求;缩短与删除不退费 - 存储单价随计费模型取价,来自定价覆盖文件字段 cache_storage_cost_per_token_per_hour,未配置的模型拒绝创建; 存储费同时计入账号统计成本,渠道按 token 重算成本时叠加且不重复计入 - 扣费前校验:创建在上游建成后按确定金额校验余额 / 订阅额度 / API Key 额度并登记不封顶的在途预留,不足时删除上游缓存、只收输入费; 延长在调用上游前按增量时长校验 - 有效期上限 gateway.gemini_cached_content_max_ttl_seconds,默认 86400, 有效期向上取整到秒;创建请求保留数字原文、兼容 snake_case 元数据字段 - 上游调用与落库同客户端连接脱钩;2xx 不可用响应不换号并删除已建缓存 - 缓存不存在:AI Studio 的 403、Vertex 生成请求的 400 与缓存资源接口的 404 统一识别;原生转发(含流式)不重试、不换号、不改账号状态, 向客户端返回标准 403,不暴露上游缓存资源 ID,上游原始错误登记到 ops; PATCH 遇上游 404 移除本地记录并返回 403,DELETE 视为成功 - 自建网关上游:账号开关 explicit_cache_upstream,缓存接口发往账号自身 base_url;可选 explicit_cache_upstream_max_ttl_seconds 对齐上游 TTL 上限, 显式 TTL 超限时创建跳过该账号(全部超限返回 400),未显式时按上限创建, PATCH 取本站与账号上限的较小值;绑定缓存的请求在网关账号上收到 429 / 5xx 时不重试、不限流该账号;前端创建 / 编辑账号弹窗新增开关与上限输入框 - 用量与 ops 端点统计:带缓存 ID 的路径归一化为 /v1beta/cachedContents, 缓存操作的上游端点记为 /v1beta/cachedContents
Sub2API Deployment Files
This directory contains files for deploying Sub2API on Linux servers and Apple-silicon Macs.
Deployment Methods
| Method | Best For | Setup Wizard |
|---|---|---|
| Docker Compose | Quick setup, all-in-one | Not needed (auto-setup) |
| Apple container | Native local stack on macOS 26 | Not needed (auto-setup) |
| Binary Install | Production servers, systemd | Web-based wizard |
Files
| File | Description |
|---|---|
docker-compose.yml |
Docker Compose configuration (named volumes) |
docker-compose.local.yml |
Docker Compose configuration (local directories, easy migration) |
docker-deploy.sh |
One-click Docker deployment script (recommended) |
apple-container.sh |
Native Apple container lifecycle script |
APPLE_CONTAINER.md |
Apple container deployment and operations guide |
.env.example |
Container environment variables template |
DOCKER.md |
Docker Hub documentation |
install.sh |
One-click binary installation script |
install-datamanagementd.sh |
datamanagementd 一键安装脚本 |
sub2api.service |
Systemd service unit file |
sub2api-datamanagementd.service |
datamanagementd systemd service unit file |
DATAMANAGEMENTD_CN.md |
datamanagementd 部署与联动说明(中文) |
config.example.yaml |
Example configuration file |
EDGE_SECURITY.md |
Reverse proxy, CDN/WAF, trusted proxy, and ingress hardening guide |
Apple container Deployment
Apple-silicon Macs running macOS 26 can run the complete Sub2API, PostgreSQL, and Redis stack with Apple container 1.1.0 or newer:
./apple-container.sh init
./apple-container.sh up
./apple-container.sh status
./apple-container.sh logs app -f
The script uses Apple named volumes, starts dependencies in order, and performs live readiness checks. The application container supervises the Sub2API process so the Web UI's update-and-restart flow can relaunch an updated binary. It does not provide host-level automatic startup; run ./apple-container.sh up after a host reboot. Docker Compose remains the recommended production deployment path.
See APPLE_CONTAINER.md for configuration, upgrades, persistence, networking behavior, and limitations.
Docker Deployment (Recommended)
Method 1: One-Click Deployment (Recommended)
Use the automated preparation script for the easiest setup:
# Download and run the preparation script
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/docker-deploy.sh | bash
# Or download first, then run
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/docker-deploy.sh -o docker-deploy.sh
chmod +x docker-deploy.sh
./docker-deploy.sh
What the script does:
- Downloads
docker-compose.local.ymland.env.example - Automatically generates secure secrets (JWT_SECRET, TOTP_ENCRYPTION_KEY, POSTGRES_PASSWORD)
- Creates
.envfile with generated secrets - Creates necessary data directories (data/, postgres_data/, redis_data/)
- Displays generated credentials (POSTGRES_PASSWORD, JWT_SECRET, etc.)
After running the script:
# Start services
docker compose -f docker-compose.local.yml up -d
# View logs
docker compose -f docker-compose.local.yml logs -f sub2api
# If admin email/password were auto-generated, find them in logs:
docker compose -f docker-compose.local.yml logs sub2api | grep "Generated admin"
# Access Web UI
# http://localhost:8080
Method 2: Manual Deployment
If you prefer manual control:
# Clone repository
git clone https://github.com/Wei-Shaw/sub2api.git
cd sub2api/deploy
# Configure environment
cp .env.example .env
chmod 600 .env
nano .env # Set POSTGRES_PASSWORD and other required variables
# Generate secure secrets (recommended)
JWT_SECRET=$(openssl rand -hex 32)
TOTP_ENCRYPTION_KEY=$(openssl rand -hex 32)
echo "JWT_SECRET=${JWT_SECRET}" >> .env
echo "TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}" >> .env
# Create data directories
mkdir -p data postgres_data redis_data
# Start all services using local directory version
docker compose -f docker-compose.local.yml up -d
# View logs (check for auto-generated admin email and password)
docker compose -f docker-compose.local.yml logs -f sub2api
# Access Web UI
# http://localhost:8080
Deployment Version Comparison
| Version | Data Storage | Migration | Best For |
|---|---|---|---|
| docker-compose.local.yml | Local directories (./data, ./postgres_data, ./redis_data) | ✅ Easy (tar entire directory) | Production, need frequent backups/migration |
| docker-compose.yml | Named volumes (/var/lib/docker/volumes/) | ⚠️ Requires docker commands | Simple setup, don't need migration |
Recommendation: Use docker-compose.local.yml (deployed by docker-deploy.sh) for easier data management and migration.
How Auto-Setup Works
When using Docker Compose with AUTO_SETUP=true:
-
On first run, the system automatically:
- Connects to PostgreSQL and Redis
- Applies database migrations (SQL files in
backend/migrations/*.sql) and records them inschema_migrations - Generates JWT secret (if not provided)
- Creates admin account (email and password auto-generated if not provided; a provided password must be 8-72 bytes)
- Writes config.yaml
-
No manual Setup Wizard needed - just configure
.envand start -
If
ADMIN_EMAIL/ADMIN_PASSWORDare not set, check logs for the generated admin email (login username) and password:docker compose logs sub2api | grep "Generated admin"
Startup and Database Recovery
Sub2API applies database migrations during application startup. PostgreSQL can remain in its recovery/startup phase briefly after a host or Docker daemon restart. The application retries transient PostgreSQL startup and connection errors with bounded exponential backoff, then starts automatically when the database becomes ready. Authentication errors, migration checksum mismatches, SQL errors, and other permanent configuration or data errors fail immediately.
The Compose example also uses a PostgreSQL health check that verifies both
server readiness and a simple SQL query. depends_on: condition: service_healthy
controls dependency ordering for a fresh Compose start, but it is not a
replacement for application-level retries when Docker restores existing
containers after a host restart.
For systemd deployments, keep Restart=always and RestartSec configured in
sub2api.service; the application retry covers transient database startup,
while systemd remains the supervisor for permanent process exits. For
Kubernetes, use a PostgreSQL readiness probe and retain the Sub2API startup
retry behavior; configure the application liveness probe separately so a
database recovery period is not treated as a permanent process failure.
Database Migration Notes (PostgreSQL)
- Migrations are applied in lexicographic order (e.g.
001_...sql,002_...sql). schema_migrationstracks applied migrations (filename + checksum).- Migrations are forward-only; rollback requires a DB backup restore or a manual compensating SQL script.
Verify users.allowed_groups → user_allowed_groups backfill
During the incremental GORM→Ent migration, users.allowed_groups (legacy BIGINT[]) is being replaced by a normalized join table user_allowed_groups(user_id, group_id).
Run this query to compare the legacy data vs the join table:
WITH old_pairs AS (
SELECT DISTINCT u.id AS user_id, x.group_id
FROM users u
CROSS JOIN LATERAL unnest(u.allowed_groups) AS x(group_id)
WHERE u.allowed_groups IS NOT NULL
)
SELECT
(SELECT COUNT(*) FROM old_pairs) AS old_pair_count,
(SELECT COUNT(*) FROM user_allowed_groups) AS new_pair_count;
datamanagementd(数据管理)联动
如需启用管理后台“数据管理”功能,请额外部署宿主机 datamanagementd:
- 主进程固定探测
/tmp/sub2api-datamanagement.sock - Docker 场景下需把宿主机 Socket 挂载到容器内同路径
- 详细步骤见:
deploy/DATAMANAGEMENTD_CN.md
Commands
For local directory version (docker-compose.local.yml):
# Start services
docker compose -f docker-compose.local.yml up -d
# Stop services
docker compose -f docker-compose.local.yml down
# View logs
docker compose -f docker-compose.local.yml logs -f sub2api
# Restart Sub2API only
docker compose -f docker-compose.local.yml restart sub2api
# Update to latest version
docker compose -f docker-compose.local.yml pull
docker compose -f docker-compose.local.yml up -d
# Remove all data (caution!)
docker compose -f docker-compose.local.yml down
rm -rf data/ postgres_data/ redis_data/
For named volumes version (docker-compose.yml):
# Start services
docker compose up -d
# Stop services
docker compose down
# View logs
docker compose logs -f sub2api
# Restart Sub2API only
docker compose restart sub2api
# Update to latest version
docker compose pull
docker compose up -d
# Remove all data (caution!)
docker compose down -v
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
POSTGRES_PASSWORD |
Yes | - | PostgreSQL password |
JWT_SECRET |
Recommended | (auto-generated) | JWT secret (fixed for persistent sessions) |
TOTP_ENCRYPTION_KEY |
Recommended | (auto-generated) | TOTP encryption key (fixed for persistent 2FA) |
SERVER_PORT |
No | 8080 |
Server port |
ADMIN_EMAIL |
No | (auto-generated) | Admin email (login username) |
ADMIN_PASSWORD |
No | (auto-generated) | Admin password (8-72 bytes) |
TZ |
No | Asia/Shanghai |
Timezone |
UPDATE_GITHUB_TOKEN |
No | (empty) | Token for api.github.com release checks only; asset downloads remain anonymous. |
GEMINI_OAUTH_CLIENT_ID |
No | (builtin) | Google OAuth client ID (Gemini OAuth). Leave empty to use the built-in Gemini CLI client. |
GEMINI_OAUTH_CLIENT_SECRET |
No | (builtin) | Google OAuth client secret (Gemini OAuth). Leave empty to use the built-in Gemini CLI client. |
GEMINI_OAUTH_SCOPES |
No | (default) | OAuth scopes (Gemini OAuth) |
GEMINI_QUOTA_POLICY |
No | (empty) | JSON overrides for Gemini local quota simulation (Code Assist only). |
See .env.example for all available options.
Note: The
docker-deploy.shscript automatically generatesJWT_SECRET,TOTP_ENCRYPTION_KEY, andPOSTGRES_PASSWORDfor you.
Easy Migration (Local Directory Version)
When using docker-compose.local.yml, all data is stored in local directories, making migration simple:
# On source server: Stop services and create archive
cd /path/to/deployment
docker compose -f docker-compose.local.yml down
cd ..
tar czf sub2api-complete.tar.gz deployment/
# Transfer to new server
scp sub2api-complete.tar.gz user@new-server:/path/to/destination/
# On new server: Extract and start
tar xzf sub2api-complete.tar.gz
cd deployment/
docker compose -f docker-compose.local.yml up -d
Your entire deployment (configuration + data) is migrated!
Gemini OAuth Configuration
Sub2API supports three methods to connect to Gemini:
Method 1: Code Assist OAuth (Recommended for GCP Users)
No configuration needed - always uses the built-in Gemini CLI OAuth client (public).
- Leave
GEMINI_OAUTH_CLIENT_IDandGEMINI_OAUTH_CLIENT_SECRETempty - In the Admin UI, create a Gemini OAuth account and select "Code Assist" type
- Complete the OAuth flow in your browser
Note: Even if you configure
GEMINI_OAUTH_CLIENT_ID/GEMINI_OAUTH_CLIENT_SECRETfor AI Studio OAuth, Code Assist OAuth will still use the built-in Gemini CLI client.
Requirements:
- Google account with access to Google Cloud Platform
- A GCP project (auto-detected or manually specified)
How to get Project ID (if auto-detection fails):
- Go to Google Cloud Console
- Click the project dropdown at the top of the page
- Copy the Project ID (not the project name) from the list
- Common formats:
my-project-123456orcloud-ai-companion-xxxxx
Method 2: AI Studio OAuth (For Regular Google Accounts)
Requires your own OAuth client credentials.
Step 1: Create OAuth Client in Google Cloud Console
- Go to Google Cloud Console - Credentials
- Create a new project or select an existing one
- Enable the Generative Language API:
- Go to "APIs & Services" → "Library"
- Search for "Generative Language API"
- Click "Enable"
- Configure OAuth Consent Screen (if not done):
- Go to "APIs & Services" → "OAuth consent screen"
- Choose "External" user type
- Fill in app name, user support email, developer contact
- Add scopes:
https://www.googleapis.com/auth/generative-language.retriever(and optionallyhttps://www.googleapis.com/auth/cloud-platform) - Add test users (your Google account email)
- Create OAuth 2.0 credentials:
- Go to "APIs & Services" → "Credentials"
- Click "Create Credentials" → "OAuth client ID"
- Application type: Web application (or Desktop app)
- Name: e.g., "Sub2API Gemini"
- Authorized redirect URIs: Add
http://localhost:1455/auth/callback
- Copy the Client ID and Client Secret
- ⚠️ Publish to Production (IMPORTANT):
- Go to "APIs & Services" → "OAuth consent screen"
- Click "PUBLISH APP" to move from Testing to Production
- Testing mode limitations:
- Only manually added test users can authenticate (max 100 users)
- Refresh tokens expire after 7 days
- Users must be re-added periodically
- Production mode: Any Google user can authenticate, tokens don't expire
- Note: For sensitive scopes, Google may require verification (demo video, privacy policy)
Step 2: Configure Environment Variables
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
- Create a Gemini OAuth account and select "AI Studio" type
- Complete the OAuth flow
- After consent, your browser will be redirected to
http://localhost:1455/auth/callback?code=...&state=... - Copy the full callback URL (recommended) or just the
codeand paste it back into the Admin UI
- After consent, your browser will be redirected to
Method 3: API Key (Simplest)
- Go to Google AI Studio
- Click "Create API key"
- In Admin UI, create a Gemini API Key account
- Paste your API key (starts with
AIza...)
Comparison Table
| Feature | Code Assist OAuth | AI Studio OAuth | API Key |
|---|---|---|---|
| Setup Complexity | Easy (no config) | Medium (OAuth client) | Easy |
| GCP Project Required | Yes | No | No |
| Custom OAuth Client | No (built-in) | Yes (required) | N/A |
| Rate Limits | GCP quota | Standard | Standard |
| Best For | GCP developers | Regular users needing OAuth | Quick testing |
Binary Installation
For production servers using systemd.
One-Line Installation
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/install.sh | sudo bash
Manual Installation
- Download the latest release from GitHub Releases
- Extract and copy the binary to
/opt/sub2api/ - Copy
sub2api.serviceto/etc/systemd/system/ - Run:
sudo systemctl daemon-reload sudo systemctl enable sub2api sudo systemctl start sub2api - Open the Setup Wizard in your browser to complete configuration
Commands
# Install
sudo ./install.sh
# Upgrade
sudo ./install.sh upgrade
# Uninstall
sudo ./install.sh uninstall
Service Management
# Start the service
sudo systemctl start sub2api
# Stop the service
sudo systemctl stop sub2api
# Restart the service
sudo systemctl restart sub2api
# Check status
sudo systemctl status sub2api
# View logs
sudo journalctl -u sub2api -f
# Enable auto-start on boot
sudo systemctl enable sub2api
Configuration
Server Address and Port
During installation, you will be prompted to configure the server listen address and port. These settings are stored in the systemd service file as environment variables.
To change after installation:
-
Edit the systemd service:
sudo systemctl edit sub2api -
Add or modify:
[Service] Environment=SERVER_HOST=0.0.0.0 Environment=SERVER_PORT=3000 -
Reload and restart:
sudo systemctl daemon-reload sudo systemctl restart sub2api
Gemini OAuth Configuration
If you need to use AI Studio OAuth for Gemini accounts, add the OAuth client credentials to the systemd service file:
-
Edit the service file:
sudo nano /etc/systemd/system/sub2api.service -
Add your OAuth credentials in the
[Service]section (after the existingEnvironment=lines):Environment=GEMINI_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com Environment=GEMINI_OAUTH_CLIENT_SECRET=GOCSPX-your-client-secret如需使用“内置 Gemini CLI OAuth Client”(Code Assist / Google One),还需要注入:
Environment=GEMINI_CLI_OAUTH_CLIENT_SECRET=GOCSPX-your-built-in-secret -
Reload and restart:
sudo systemctl daemon-reload sudo systemctl restart sub2api
Note: Code Assist OAuth does not require any configuration - it uses the built-in Gemini CLI client. See the Gemini OAuth Configuration section above for detailed setup instructions.
Application Configuration
The main config file is at /etc/sub2api/config.yaml (created by Setup Wizard).
Prerequisites
- Linux server (Ubuntu 20.04+, Debian 11+, CentOS 8+, etc.)
- PostgreSQL 14+
- Redis 6+
- systemd
Directory Structure
/opt/sub2api/
├── sub2api # Main binary
├── sub2api.backup # Backup (after upgrade)
└── data/ # Runtime data
/etc/sub2api/
└── config.yaml # Configuration file
Troubleshooting
Docker
For local directory version:
# Check container status
docker compose -f docker-compose.local.yml ps
# View detailed logs
docker compose -f docker-compose.local.yml logs --tail=100 sub2api
# Check database connection
docker compose -f docker-compose.local.yml exec postgres pg_isready
# Check Redis connection
docker compose -f docker-compose.local.yml exec redis redis-cli ping
# Restart all services
docker compose -f docker-compose.local.yml restart
# Check data directories
ls -la data/ postgres_data/ redis_data/
For named volumes version:
# Check container status
docker compose ps
# View detailed logs
docker compose logs --tail=100 sub2api
# Check database connection
docker compose exec postgres pg_isready
# Check Redis connection
docker compose exec redis redis-cli ping
# Restart all services
docker compose restart
Binary Install
# Check service status
sudo systemctl status sub2api
# View recent logs
sudo journalctl -u sub2api -n 50
# Check config file
sudo cat /etc/sub2api/config.yaml
# Check PostgreSQL
sudo systemctl status postgresql
# Check Redis
sudo systemctl status redis
Common Issues
- Port already in use: Change
SERVER_PORTin.envor systemd config - Database connection failed: Check PostgreSQL is running and credentials are correct
- Redis connection failed: Check Redis is running and password is correct
- Permission denied: Ensure proper file ownership for binary install
TLS Fingerprint Configuration
Sub2API supports TLS fingerprint simulation to make requests appear as if they come from the official Claude CLI (Node.js client).
💡 Tip: Visit tls.sub2api.org to get TLS fingerprint information for different devices and browsers.
Default Behavior
- Built-in
claude_cli_v2profile simulates Node.js 20.x + OpenSSL 3.x - JA3 Hash:
1a28e69016765d92e3b381168d68922c - JA4:
t13d5911h1_a33745022dd6_1f22a2ca17c4 - Profile selection:
accountID % profileCount
Configuration
gateway:
tls_fingerprint:
enabled: true # Global switch
profiles:
# Simple profile (uses default cipher suites)
profile_1:
name: "Profile 1"
# Profile with custom cipher suites (use compact array format)
profile_2:
name: "Profile 2"
cipher_suites: [4866, 4867, 4865, 49199, 49195, 49200, 49196]
curves: [29, 23, 24]
point_formats: 0
# Another custom profile
profile_3:
name: "Profile 3"
cipher_suites: [4865, 4866, 4867, 49199, 49200]
curves: [29, 23, 24, 25]
Profile Fields
| Field | Type | Description |
|---|---|---|
name |
string | Display name (required) |
cipher_suites |
[]uint16 | Cipher suites in decimal. Empty = default |
curves |
[]uint16 | Elliptic curves in decimal. Empty = default |
point_formats |
[]uint8 | EC point formats. Empty = default |
Common Values Reference
Cipher Suites (TLS 1.3): 4865 (AES_128_GCM), 4866 (AES_256_GCM), 4867 (CHACHA20)
Cipher Suites (TLS 1.2): 49195, 49196, 49199, 49200 (ECDHE variants)
Curves: 29 (X25519), 23 (P-256), 24 (P-384), 25 (P-521)