| # Sub2API Deployment Files |
|
|
| This directory contains files for deploying Sub2API on Linux servers. |
|
|
| ## Deployment Methods |
|
|
| | Method | Best For | Setup Wizard | |
| |--------|----------|--------------| |
| | **Docker Compose** | Quick setup, all-in-one | 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)** | |
| | `.env.example` | Docker 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 | |
|
|
| --- |
|
|
| ## Docker Deployment (Recommended) |
|
|
| ### Method 1: One-Click Deployment (Recommended) |
|
|
| Use the automated preparation script for the easiest setup: |
|
|
| ```bash |
| # 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.yml` and `.env.example` |
| - Automatically generates secure secrets (JWT_SECRET, TOTP_ENCRYPTION_KEY, POSTGRES_PASSWORD) |
| - Creates `.env` file with generated secrets |
| - Creates necessary data directories (data/, postgres_data/, redis_data/) |
| - **Displays generated credentials** (POSTGRES_PASSWORD, JWT_SECRET, etc.) |
|
|
| **After running the script:** |
| ```bash |
| # 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 password was auto-generated, find it in logs: |
| docker compose -f docker-compose.local.yml logs sub2api | grep "admin password" |
| |
| # Access Web UI |
| # http://localhost:8080 |
| ``` |
|
|
| ### Method 2: Manual Deployment |
|
|
| If you prefer manual control: |
|
|
| ```bash |
| # Clone repository |
| git clone https://github.com/Wei-Shaw/sub2api.git |
| cd sub2api/deploy |
| |
| # Configure environment |
| cp .env.example .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 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`: |
|
|
| 1. On first run, the system automatically: |
| - Connects to PostgreSQL and Redis |
| - Applies database migrations (SQL files in `backend/migrations/*.sql`) and records them in `schema_migrations` |
| - Generates JWT secret (if not provided) |
| - Creates admin account (password auto-generated if not provided) |
| - Writes config.yaml |
|
|
| 2. No manual Setup Wizard needed - just configure `.env` and start |
|
|
| 3. If `ADMIN_PASSWORD` is not set, check logs for the generated password: |
| ```bash |
| docker compose logs sub2api | grep "admin password" |
| ``` |
|
|
| ### Database Migration Notes (PostgreSQL) |
|
|
| - Migrations are applied in lexicographic order (e.g. `001_...sql`, `002_...sql`). |
| - `schema_migrations` tracks 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: |
| |
| ```sql |
| 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): |
| |
| ```bash |
| # 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): |
| |
| ```bash |
| # 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 | `admin@sub2api.local` | Admin email | |
| | `ADMIN_PASSWORD` | No | *(auto-generated)* | Admin password | |
| | `TZ` | No | `Asia/Shanghai` | Timezone | |
| | `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.sh` script automatically generates `JWT_SECRET`, `TOTP_ENCRYPTION_KEY`, and `POSTGRES_PASSWORD` for you. |
|
|
| ### Easy Migration (Local Directory Version) |
|
|
| When using `docker-compose.local.yml`, all data is stored in local directories, making migration simple: |
|
|
| ```bash |
| # 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). |
|
|
| 1. Leave `GEMINI_OAUTH_CLIENT_ID` and `GEMINI_OAUTH_CLIENT_SECRET` empty |
| 2. In the Admin UI, create a Gemini OAuth account and select **"Code Assist"** type |
| 3. Complete the OAuth flow in your browser |
|
|
| > Note: Even if you configure `GEMINI_OAUTH_CLIENT_ID` / `GEMINI_OAUTH_CLIENT_SECRET` for 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):** |
| 1. Go to [Google Cloud Console](https://console.cloud.google.com/) |
| 2. Click the project dropdown at the top of the page |
| 3. Copy the Project ID (not the project name) from the list |
| 4. Common formats: `my-project-123456` or `cloud-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** |
|
|
| 1. Go to [Google Cloud Console - Credentials](https://console.cloud.google.com/apis/credentials) |
| 2. Create a new project or select an existing one |
| 3. **Enable the Generative Language API:** |
| - Go to "APIs & Services" → "Library" |
| - Search for "Generative Language API" |
| - Click "Enable" |
| 4. **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 optionally `https://www.googleapis.com/auth/cloud-platform`) |
| - Add test users (your Google account email) |
| 5. **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` |
| 6. Copy the **Client ID** and **Client Secret** |
| 7. **⚠️ 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** |
|
|
| ```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** |
|
|
| 1. Create a Gemini OAuth account and select **"AI Studio"** type |
| 2. 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 `code` and paste it back into the Admin UI |
|
|
| ### Method 3: API Key (Simplest) |
|
|
| 1. Go to [Google AI Studio](https://aistudio.google.com/app/apikey) |
| 2. Click "Create API key" |
| 3. In Admin UI, create a Gemini **API Key** account |
| 4. 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 |
|
|
| ```bash |
| curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/install.sh | sudo bash |
| ``` |
|
|
| ### Manual Installation |
|
|
| 1. Download the latest release from [GitHub Releases](https://github.com/Wei-Shaw/sub2api/releases) |
| 2. Extract and copy the binary to `/opt/sub2api/` |
| 3. Copy `sub2api.service` to `/etc/systemd/system/` |
| 4. Run: |
| ```bash |
| sudo systemctl daemon-reload |
| sudo systemctl enable sub2api |
| sudo systemctl start sub2api |
| ``` |
| 5. Open the Setup Wizard in your browser to complete configuration |
|
|
| ### Commands |
|
|
| ```bash |
| # Install |
| sudo ./install.sh |
| |
| # Upgrade |
| sudo ./install.sh upgrade |
| |
| # Uninstall |
| sudo ./install.sh uninstall |
| ``` |
|
|
| ### Service Management |
|
|
| ```bash |
| # 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: |
|
|
| 1. Edit the systemd service: |
| ```bash |
| sudo systemctl edit sub2api |
| ``` |
|
|
| 2. Add or modify: |
| ```ini |
| [Service] |
| Environment=SERVER_HOST=0.0.0.0 |
| Environment=SERVER_PORT=3000 |
| ``` |
|
|
| 3. Reload and restart: |
| ```bash |
| 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: |
|
|
| 1. Edit the service file: |
| ```bash |
| sudo nano /etc/systemd/system/sub2api.service |
| ``` |
|
|
| 2. Add your OAuth credentials in the `[Service]` section (after the existing `Environment=` lines): |
| ```ini |
| 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),还需要注入: |
| ```ini |
| Environment=GEMINI_CLI_OAUTH_CLIENT_SECRET=GOCSPX-your-built-in-secret |
| ``` |
|
|
| 3. Reload and restart: |
| ```bash |
| 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](#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**: |
|
|
| ```bash |
| # 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**: |
|
|
| ```bash |
| # 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 |
|
|
| ```bash |
| # 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 |
|
|
| 1. **Port already in use**: Change `SERVER_PORT` in `.env` or systemd config |
| 2. **Database connection failed**: Check PostgreSQL is running and credentials are correct |
| 3. **Redis connection failed**: Check Redis is running and password is correct |
| 4. **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](https://tls.sub2api.org/)** to get TLS fingerprint information for different devices and browsers. |
|
|
| ### Default Behavior |
|
|
| - Built-in `claude_cli_v2` profile simulates Node.js 20.x + OpenSSL 3.x |
| - JA3 Hash: `1a28e69016765d92e3b381168d68922c` |
| - JA4: `t13d5911h1_a33745022dd6_1f22a2ca17c4` |
| - Profile selection: `accountID % profileCount` |
|
|
| ### Configuration |
|
|
| ```yaml |
| 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) |
|
|