English | 简体中文
This document describes SublinkPro configuration methods and parameters.
SublinkPro supports several configuration methods. Priority from highest to lowest:
- Command line flags, useful for temporary overrides such as
--port 9000 - Environment variables, recommended for Docker deployments
- Configuration file,
db/config.yaml - Database stored settings, used for sensitive configuration
- Default values, built into the program
| Environment variable | Description | Default |
|---|---|---|
SUBLINK_PORT |
Service port | 8000 |
SUBLINK_DSN |
Database DSN, supports sqlite/mysql/postgres | SQLite by default: sqlite://./db/sublink.db |
SUBLINK_DB_PATH |
Local data directory and default SQLite database directory | ./db |
SUBLINK_LOG_PATH |
Log directory | ./logs |
SUBLINK_JWT_SECRET |
JWT signing secret | Generated automatically |
SUBLINK_API_ENCRYPTION_KEY |
API encryption key | Generated automatically |
SUBLINK_EXPIRE_DAYS |
Token expiration days | 14 |
SUBLINK_LOGIN_FAIL_COUNT |
Login failure limit | 5 |
SUBLINK_LOGIN_FAIL_WINDOW |
Login failure window, in minutes | 1 |
SUBLINK_LOGIN_BAN_DURATION |
Login ban duration, in minutes | 10 |
SUBLINK_GEOIP_PATH |
GeoIP database path | ./db/GeoLite2-City.mmdb |
SUBLINK_CAPTCHA_MODE |
CAPTCHA mode, 1=off, 2=image, 3=Turnstile | 2 |
SUBLINK_TURNSTILE_SITE_KEY |
Cloudflare Turnstile Site Key | - |
SUBLINK_TURNSTILE_SECRET_KEY |
Cloudflare Turnstile Secret Key | - |
SUBLINK_TURNSTILE_PROXY_LINK |
Proxy link for Turnstile verification, mihomo format | - |
SUBLINK_TRUSTED_PROXIES |
Trusted reverse proxy IP/CIDR list, comma separated | 127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10 |
SUBLINK_WEB_BASE_PATH |
Frontend base path for hiding the site entry | - |
SUBLINK_ADMIN_PASSWORD |
Initial admin password | 123456 |
SUBLINK_ADMIN_PASSWORD_REST |
Reset admin password | Enter the new admin password |
SUBLINK_MFA_RESET_SECRET |
Secret used to generate restricted TOTP emergency reset tokens, environment variable only | - |
SUBLINK_DEMO_MODE |
Enable demo mode, memory database and some sensitive operations disabled | false |
SUBLINK_FEATURE |
Experimental feature flags | Reserved experimental flags, comma separated. Node preview is now stable and no longer needs configuration |
SublinkPro can use an external Sub-Store backend as an optional sidecar for additional subscription output formats. Native clash/mihomo, surge, and v2ray links stay handled by SublinkPro. Expanded targets such as loon, egern, stash, surfboard, shadowrocket, quanx, sing-box, uri, and json first generate SublinkPro's mihomo/Clash bridge YAML, then send the proxy list to Sub-Store's /api/proxy/parse endpoint.
Sign in and open Application Settings -> Sub-Store to enable the sidecar, set its base URL, adjust timeout/response limits, choose allowed targets, and test the connection. Sub-Store settings are page-managed only; this integration is not configured through environment variables or config.yaml keys.
Keep the Sub-Store service on a private network or loopback address. SublinkPro does not embed or vendor Sub-Store code; the sidecar is a separate service boundary because Sub-Store is a Node project with GPL/AGPL licensing considerations. The one-shot parser converts proxy nodes and does not preserve full Clash strategy groups, rules, or DNS sections.
The Cloudflare Tunnel tab in Application Settings can host the local cloudflared process and connect the current SublinkPro instance to a remotely managed Tunnel in Cloudflare Zero Trust.
- The Docker image includes
cloudflared, so you usually only need to enter the Tunnel token on the page and start it. - Non Docker deployments need
cloudflaredinstalled first, with thecloudflaredcommand available inPATH. - The page never echoes the raw token. Status APIs only return a masked token.
At runtime this is equivalent to cloudflared tunnel --no-autoupdate run. The token is passed through the TUNNEL_TOKEN environment variable so it does not appear in process arguments.
See the full guide at Cloudflare Tunnel remote access.
# Show help
./sublinkpro help
# Start with a specific port
./sublinkpro run --port 9000
# Use a specific SQLite database
./sublinkpro run --dsn "sqlite:///data/sublink.db"
# Use MySQL
./sublinkpro run --dsn "mysql://user:pass@tcp(127.0.0.1:3306)/sublink?charset=utf8mb4&parseTime=True&loc=Local"
# Use PostgreSQL
./sublinkpro run --dsn "postgres://user:pass@127.0.0.1:5432/sublink?sslmode=disable"
# Set the local data directory, used for config file, GeoIP, and default SQLite
./sublinkpro run --db /data
# Reset admin password
./sublinkpro setting -username admin -password newpassSublinkPro now supports unified database connection configuration through dsn, with these dialects:
sqlite://mysql://postgres://postgresql://
If dsn is empty, the system falls back to SQLite and uses db_path/sublink.db as the database file.
dsn: sqlite:///app/db/sublink.dbdsn: mysql://user:pass@tcp(mysql:3306)/sublink?charset=utf8mb4&parseTime=True&loc=Localdsn: postgres://user:pass@postgres:5432/sublink?sslmode=disableTip
When using MySQL or PostgreSQL, db_path is still used for local config files and GeoIP database storage. It no longer decides the actual database backend.
If an old instance has always used SQLite and you want to migrate to MySQL or PostgreSQL, use the built in “Data Migration” feature.
- Prepare a new empty MySQL or PostgreSQL database.
- Configure database
DSNfor the new instance. - Confirm that the old instance can sign in normally.
- If you need to keep old
AccessKeyvalues, confirm thatSUBLINK_API_ENCRYPTION_KEYis the same on both instances.
You can configure the database for the new instance in any of these ways:
- Environment variable:
SUBLINK_DSN - Config file:
dsn:indb/config.yaml - Command line flag:
./sublinkpro run --dsn "..."
Example:
# MySQL
dsn: mysql://user:pass@tcp(mysql:3306)/sublink?charset=utf8mb4&parseTime=True&loc=Local
# PostgreSQL
dsn: postgres://user:pass@postgres:5432/sublink?sslmode=disableImportant
A fresh empty target database is recommended. Don't import directly into a database that already has business data.
After signing in to the old instance:
- Click the avatar menu in the upper right.
- Choose System Backup.
- Download the generated
backup.zip.
Using backup.zip is recommended because it includes:
- The SQLite database file from the
dbdirectory - Template files from the
templatedirectory
Tip
You can also upload a .db, .sqlite, or .sqlite3 file directly, but that only migrates database records and won't restore the template directory.
After starting the new instance, open:
Settings -> Data Migration
Then:
- Upload the
backup.zipexported from the old instance. - Choose whether to migrate
AccessKey. - Choose whether to migrate subscription access logs.
- Check “I confirm that this import will overwrite business data in the current instance”.
- Click Start Migration.
The migration task runs in the background. You can view progress and results in:
- The task progress panel in the lower right
Task Center
- Check whether the migration result is successful.
- If it reports “N warnings”, open the corresponding “Database Migration” task in
Task Centerto view details. - Manually restart the project instance.
- Sign in again and check that important data is normal.
- This import overwrites business data in the current instance.
- It is recommended only for first time migration into a newly deployed MySQL / PostgreSQL instance.
- Subscription access logs are usually large, so migrating them is not recommended by default.
- If old
AccessKeyvalues cannot be used after migration, check whetherSUBLINK_API_ENCRYPTION_KEYmatches the old instance. - If login state behaves oddly after migration, sign in again.
Tip
JWT Secret and API encryption key are sensitive settings. The system handles them in this order:
- Read from environment variables first.
- If not set in environment variables, read from the database.
- If missing from the database too, generate random keys automatically and store them in the database.
Special note: If you set these values through environment variables, the system automatically syncs them to the database. That lets the system recover them from the database later even if you forget to set the environment variables, which helps migration and deployment.
Warning
If you need multi instance deployment or cluster deployment, set the same SUBLINK_JWT_SECRET and SUBLINK_API_ENCRYPTION_KEY through environment variables for all instances. This keeps login state and API Keys consistent across instances.
SublinkPro supports TOTP based multi factor authentication. When enabled, login becomes:
- Username + password + CAPTCHA
- Authenticator code or one time recovery code
- Start setup in
Settings -> Personal Settings -> Multi Factor Authentication (TOTP). - After scanning the QR code, enter the current 6 digit code once to enable it.
- The system generates a set of one time recovery codes. Save them offline, separate from account passwords.
- If the current account has TOTP enabled, changing password, changing username or nickname, disabling TOTP, or resetting recovery codes requires the current dynamic code again.
- Recovery codes can be used for login only after TOTP is fully enabled.
- Each recovery code can be used once.
- Old recovery codes become invalid immediately after recovery codes are regenerated.
SUBLINK_MFA_RESET_SECRET is used to generate restricted emergency TOTP reset tokens. It is for operators helping users who lost their authenticator and cannot use recovery codes.
This setting has these constraints:
- Environment variable only, it is not written to config files
- It does not provide a global universal login bypass
- It can only clear TOTP for an account after username + password have been verified
- It is recommended only as a temporary operations setting, with careful rotation
- Temporarily set
SUBLINK_MFA_RESET_SECRET. - Generate a reset token with an expiration time for the target user.
- Call
/api/v1/auth/mfa/resetwith:usernamepasswordresetToken
- The user signs in again and binds TOTP again.
Warning
Don't keep SUBLINK_MFA_RESET_SECRET as a permanent public setting, and don't treat it as a backdoor for bypassing MFA login. It is only for restricted TOTP reset when the account password is known.
SublinkPro supports three CAPTCHA modes through SUBLINK_CAPTCHA_MODE:
| Mode | Description |
|---|---|
| 1 | Disable CAPTCHA, not recommended, only for internal networks |
| 2 | Traditional image CAPTCHA, default |
| 3 | Cloudflare Turnstile, recommended and more secure |
To use Turnstile:
- Open the Cloudflare Turnstile console and create a site.
- Get the Site Key and Secret Key.
- Configure environment variables:
environment:
- SUBLINK_CAPTCHA_MODE=3
- SUBLINK_TURNSTILE_SITE_KEY=your-site-key
- SUBLINK_TURNSTILE_SECRET_KEY=your-secret-keyNote
Fallback behavior: If Turnstile mode is configured but complete keys are missing, the system automatically falls back to traditional image CAPTCHA.
If your server cannot access the Cloudflare API directly, you may see a context deadline exceeded timeout. Configure a proxy in that case:
environment:
- SUBLINK_TURNSTILE_PROXY_LINK=vless://your-proxy-link...Tip
Proxy link format: Use proxy links supported by mihomo, such as vless://, vmess://, ss://, and others. This is similar to Telegram proxy configuration.
Cloudflare Turnstile supports three verification modes. Choose one when creating the Site Key in the Cloudflare console:
| Mode | Description |
|---|---|
| Managed | Cloudflare decides whether interaction is needed. Most users pass without noticing. |
| Non-Interactive | Shows a loading indicator but requires no user interaction. |
| Invisible | Fully invisible, verification completes silently in the background. |
The frontend widget renders automatically based on the mode associated with the Site Key. No extra configuration is needed.
Set SUBLINK_WEB_BASE_PATH to hide the admin site entry, similar to custom path features in 3x-ui.
environment:
- SUBLINK_WEB_BASE_PATH=/adminAfter setting it:
http://domain/returns 404http://domain/adminopens the admin UI- API paths (
/api/*) and subscription fetch paths (/c/*) are not affected
Tip
Paths work with or without a leading slash. admin and /admin have the same effect.
If you access SublinkPro through Nginx, Caddy, BaoTa, Docker reverse proxy, Cloudflare Tunnel, or another proxy, the client IP in access logs depends on whether the server trusts that proxy.
- By default, local addresses and common private network ranges are trusted, so reverse proxies on the host or container network usually expose the real source IP automatically.
- If logs keep showing proxy addresses like
127.0.0.1or172.x.x.x, the proxy egress is usually not in the trusted list. - Add proxy IPs or CIDRs through
SUBLINK_TRUSTED_PROXIESortrusted_proxiesinconfig.yaml.
Example:
trusted_proxies:
- 127.0.0.1
- ::1
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- 100.64.0.0/10
- 203.0.113.10
- 198.51.100.0/24Docker Compose environment variable form:
environment:
- SUBLINK_TRUSTED_PROXIES=127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10If you are sure you do not want to trust any proxy headers, explicitly disable them:
trusted_proxies: []services:
sublinkpro:
image: zerodeng/sublink-pro:latest
container_name: sublinkpro
ports:
- "8000:8000"
volumes:
- "./db:/app/db"
- "./template:/app/template"
- "./logs:/app/logs"
environment:
- SUBLINK_PORT=8000
# Database DSN, optional. SQLite is used by default when unset.
# - SUBLINK_DSN=mysql://user:pass@mysql:3306/sublink?charset=utf8mb4&parseTime=True&loc=Local
- SUBLINK_EXPIRE_DAYS=14
- SUBLINK_LOGIN_FAIL_COUNT=5
# Local data directory, optional, default for config.yaml / GeoIP / SQLite
# - SUBLINK_DB_PATH=/app/db
# GeoIP database path, optional, defaults to ./db/GeoLite2-City.mmdb
# - SUBLINK_GEOIP_PATH=/app/db/GeoLite2-City.mmdb
# Trusted reverse proxies, optional, comma separated. Host or private network reverse proxies usually need no extra change.
# - SUBLINK_TRUSTED_PROXIES=127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10
# Sensitive configuration, optional, generated automatically when unset
# - SUBLINK_JWT_SECRET=your-secret-key
# - SUBLINK_API_ENCRYPTION_KEY=your-encryption-key
# - SUBLINK_MFA_RESET_SECRET=your-break-glass-secret
restart: unless-stoppedNote
For the full Docker Compose template, see docker-compose.example.yml in the project root.