NewAPI+Sub2API 部署搭建教程:TaoToken 统一 Key 接入配置实战
发布时间:2026/9/28 18:12:40来源:尧图网络
1. 为什么要把 NewAPI 和 Sub2API 拼在一起用如果你正在自建 AI 网关大概率会遇到一个很别扭的局面NewAPI 擅长做多模型聚合、渠道分发、令牌计费和用量统计但它本身对「订阅制账号池」这类上游形态支持有限Sub2API 恰好相反它专门处理订阅账号的转换与调度却不太适合直接对外暴露成统一入口。两个项目单独跑都能用可一旦你想让 Cline、CC Switch、Claude Code 这些客户端只认一个 Key、一个 Base URL就会发现问题来了——请求到底该走哪个服务这篇教程要解决的就是这件事把 NewAPI 和 Sub2API 联合部署到同一台机器上再通过 TaoToken 的统一 Key 与 API 通道完成接入让下游工具只需要配置一次就能跑通整条调用链路。适合已经有一台云服务器、懂基本 Docker 操作、想把手里的模型渠道和订阅账号统一管理的开发者。全文给出可复制的config.toml、settings.json骨架以及 CC Switch、Cline 侧的配置示例最后附连通性验证和常见报错排查动作目标是一次跑通多工具调用。我试过把两个服务分别暴露成两个域名结果客户端配置翻倍、密钥管理混乱后来改成统一入口才清爽下来。下面按部署顺序一步步来。2. 部署前的环境准备与 TaoToken 前置2.1 服务器与依赖基线系统建议 Ubuntu 22.04 或 24.04内存至少 2 GB磁盘 20 GB 起步。先确认系统版本cat /etc/os-release | head -5安装 Docker 与 Compose 插件sudo apt-get update -y sudo apt-get install -y ca-certificates curl gnupg lsb-release vim sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod ar /etc/apt/keyrings/docker.asc写入 apt 源并安装CODENAME$(. /etc/os-release echo $VERSION_CODENAME) ARCH$(dpkg --print-architecture) echo deb [arch$ARCH signed-by/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $CODENAME stable | sudo tee /etc/apt/sources.list.d/docker.list sudo apt-get update -y sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker sudo usermod -aG docker $USER验证docker --version docker compose version注意usermod -aG docker之后要重新登录 SSH 才不用 sudo 跑 docker本文命令仍带 sudo 以兼容。2.2 配置镜像加速与日志限制sudo tee /etc/docker/daemon.json /dev/null EOF { registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.1panel.live ], log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } } EOF sudo systemctl restart docker docker info | grep -A3 Registry Mirrorslog-opts把单容器日志限制在 30 MB 以内长跑不会撑爆磁盘。2.3 TaoToken 侧的准备TaoToken 在这里扮演统一 Key 与 API 通道的角色你在它那边拿到一个 Key下游所有工具都指向同一个 Base URL再由它把请求分发到 NewAPI 或 Sub2API 背后的渠道。先去控制台创建 Key控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deployAPI Key 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deployAPI 基础地址统一用https://taotoken.net/api不加 UTM。拿到 Key 后先记到密码管理器后面config.toml和settings.json都要填。3. NewAPI 部署与可复制配置3.1 目录与密钥生成sudo mkdir -p /opt/new-api/{data,logs,mysql,redis} sudo chown -R $USER:$USER /opt/new-api cd /opt/new-api一次性生成 4 个随机密码只生成一次丢了就要全部重置cat /opt/new-api/.env.secret EOF MYSQL_ROOT_PASSWORD$(openssl rand -base64 24 | tr -d / | cut -c1-24) MYSQL_USERnewapi MYSQL_PASSWORD$(openssl rand -base64 24 | tr -d / | cut -c1-24) SESSION_SECRET$(openssl rand -hex 32) EOF chmod 600 /opt/new-api/.env.secret cat /opt/new-api/.env.secret把输出抄进密码管理器。3.2 docker-compose.yml 骨架set -a; source /opt/new-api/.env.secret; set a cat /opt/new-api/docker-compose.yml EOF services: new-api: image: calciumion/new-api:latest container_name: new-api restart: unless-stopped depends_on: mysql: condition: service_healthy redis: condition: service_started ports: - 3000:3000 environment: TZ: Asia/Shanghai SQL_DSN: newapi:\${MYSQL_PASSWORD}tcp(mysql:3306)/new-api?charsetutf8mb4parseTimeTruelocLocal REDIS_CONN_STRING: redis://redis:6379/0 SESSION_SECRET: \${SESSION_SECRET} CRYPTO_SECRET: \${SESSION_SECRET} SYSTEM_NAME: WeskyApi GIN_MODE: release ERROR_LOG_ENABLED: true volumes: - ./data:/data - ./logs:/app/logs healthcheck: test: [CMD-SHELL, wget -qO- http://127.0.0.1:3000/api/status /dev/null || exit 1] interval: 30s timeout: 5s retries: 10 mysql: image: mysql:8.4 container_name: new-api-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: new-api MYSQL_USER: newapi MYSQL_PASSWORD: \${MYSQL_PASSWORD} TZ: Asia/Shanghai command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_unicode_ci - --innodb-buffer-pool-size128M - --max-connections200 - --performance-schemaOFF volumes: - ./mysql:/var/lib/mysql healthcheck: test: [CMD, mysqladmin, ping, -h, 127.0.0.1, -uroot, -p\${MYSQL_ROOT_PASSWORD}] interval: 10s timeout: 5s retries: 20 redis: image: redis:7-alpine container_name: new-api-redis restart: unless-stopped command: [redis-server, --maxmemory, 128mb, --maxmemory-policy, allkeys-lru, --save, 900, 1] volumes: - ./redis:/data EOF小内存机器必须调优MySQL 的--innodb-buffer-pool-size128M防止自适应吃满内存--performance-schemaOFF省约 50 MBRedis 的--maxmemory 128mb加 LRU 防止无限增长。3.3 启动与初始化cd /opt/new-api sudo docker compose pull sudo docker compose up -d sudo docker compose ps等服务就绪for i in $(seq 1 36); do if curl -fsS http://127.0.0.1:3000/api/status /dev/null; then echo ok; break; fi echo 等待中 $i/36; sleep 5 done当前版本 NewAPI 不再预置默认账户必须主动调/api/setupROOT_USERroot ROOT_PASSWORDWesky-$(openssl rand -base64 16 | tr -d / | cut -c1-16) echo ROOT_USERNAME$ROOT_USER | sudo tee -a /opt/new-api/.env.secret echo ROOT_PASSWORD$ROOT_PASSWORD | sudo tee -a /opt/new-api/.env.secret curl -sS -X POST http://127.0.0.1:3000/api/setup \ -H Content-Type: application/json \ -d {\Username\:\$ROOT_USER\,\Password\:\$ROOT_PASSWORD\,\ConfirmPassword\:\$ROOT_PASSWORD\,\SelfUseModeEnabled\:false,\DemoSiteEnabled\:false}期望返回{message:系统初始化成功,success:true}。登录拿 cookie 和 uidLOGIN_RESP$(curl -sS -c /tmp/newapi_cookie.txt -X POST http://127.0.0.1:3000/api/user/login \ -H Content-Type: application/json \ -d {\username\:\$ROOT_USER\,\password\:\$ROOT_PASSWORD\}) UID$(echo $LOGIN_RESP | python3 -c import sys,json;print(json.load(sys.stdin)[data][id])) echo UID$UID关键坑调任何管理员接口都要带New-Api-User: $UID这个 HTTP 头仅 cookie 不够否则会得到Unauthorized, New-Api-User header not provided。4. Sub2API 部署与统一 Key 接入配置4.1 目录与机密sudo mkdir -p /opt/sub2api/{data,postgres} sudo chown -R $USER:$USER /opt/sub2api cd /opt/sub2api cat /opt/sub2api/.env.secret EOF POSTGRES_PASSWORD$(openssl rand -base64 24 | tr -d / | cut -c1-24) JWT_SECRET$(openssl rand -hex 32) TOTP_ENCRYPTION_KEY$(openssl rand -hex 32) ADMIN_EMAILadminweskyapi.local ADMIN_PASSWORDWesky-$(openssl rand -base64 16 | tr -d / | cut -c1-16) EOF chmod 600 /opt/sub2api/.env.secret cat /opt/sub2api/.env.secretJWT_SECRET和TOTP_ENCRYPTION_KEY必须固定变了会导致所有用户被踢下线、2FA 全部失效。4.2 docker-compose.yml 骨架set -a; source /opt/sub2api/.env.secret; set a cat /opt/sub2api/docker-compose.yml EOF services: sub2api: image: weishaw/sub2api:latest container_name: sub2api restart: unless-stopped ulimits: nofile: { soft: 65535, hard: 65535 } ports: - 127.0.0.1:8080:8080 depends_on: postgres: condition: service_healthy volumes: - ./data:/app/data environment: AUTO_SETUP: true SERVER_HOST: 0.0.0.0 SERVER_PORT: 8080 SERVER_MODE: release RUN_MODE: standard DATABASE_HOST: postgres DATABASE_PORT: 5432 DATABASE_USER: sub2api DATABASE_PASSWORD: \${POSTGRES_PASSWORD} DATABASE_DBNAME: sub2api DATABASE_SSLMODE: disable DATABASE_MAX_OPEN_CONNS: 30 DATABASE_MAX_IDLE_CONNS: 5 REDIS_HOST: new-api-redis REDIS_PORT: 6379 REDIS_DB: 1 REDIS_POOL_SIZE: 128 REDIS_MIN_IDLE_CONNS: 4 JWT_SECRET: \${JWT_SECRET} JWT_EXPIRE_HOUR: 168 TOTP_ENCRYPTION_KEY: \${TOTP_ENCRYPTION_KEY} ADMIN_EMAIL: \${ADMIN_EMAIL} ADMIN_PASSWORD: \${ADMIN_PASSWORD} TZ: Asia/Shanghai networks: - sub2api-network - newapi-shared healthcheck: test: [CMD, wget, -q, -T, 5, -O, /dev/null, http://localhost:8080/health] interval: 30s timeout: 10s retries: 5 start_period: 60s postgres: image: postgres:18-alpine container_name: sub2api-postgres restart: unless-stopped shm_size: 128mb environment: PGDATA: /var/lib/postgresql/data POSTGRES_USER: sub2api POSTGRES_PASSWORD: \${POSTGRES_PASSWORD} POSTGRES_DB: sub2api TZ: Asia/Shanghai command: - postgres - -c - shared_buffers64MB - -c - effective_cache_size192MB - -c - max_connections80 volumes: - ./postgres:/var/lib/postgresql/data networks: - sub2api-network healthcheck: test: [CMD-SHELL, pg_isready -U sub2api -d sub2api] interval: 10s timeout: 5s retries: 10 start_period: 30s networks: sub2api-network: driver: bridge newapi-shared: external: true name: new-api_default EOF三个不能省的细节PGDATA必须显式设为/var/lib/postgresql/data否则挂载卷不落数据重启就 initdbshm_size: 128mb防止复杂查询报共享内存不足newapi-shared外部网络让 Sub2API 能通过容器名new-api-redis复用 NewAPI 的 Redis。4.3 启动与验证cd /opt/sub2api sudo docker compose pull sudo docker compose up -d sudo docker compose ps for i in $(seq 1 36); do if curl -fsS http://127.0.0.1:8080/health /dev/null; then echo ok; break; fi echo 等待中 $i; sleep 5 done curl -sS http://127.0.0.1:8080/health期望{status:ok}且sub2api的 PORTS 列是127.0.0.1:8080而不是0.0.0.0。4.4 统一 Key 接入config.toml 与 settings.json下游工具统一指向 TaoToken 的 API 通道Key 用同一个。先看config.toml骨架适用于支持 TOML 配置的客户端# ~/.config/taotoken/config.toml [provider] name taotoken base_url https://taotoken.net/api api_key sk-你的TaoToken密钥 model claude-sonnet-4-5 timeout_seconds 120 [provider.headers] X-Gateway-Source newapi-sub2api [fallback] enabled true base_url https://taotoken.net/api再看settings.json骨架适用于 Cline、CC Switch 这类 JSON 配置的客户端{ apiProvider: openai-compatible, baseUrl: https://taotoken.net/api, apiKey: sk-你的TaoToken密钥, model: claude-sonnet-4-5, headers: { X-Gateway-Source: newapi-sub2api }, timeout: 120, retry: { maxAttempts: 3, backoffMs: 800 } }CC Switch 侧配置示例多环境切换{ profiles: [ { name: taotoken-unified, baseUrl: https://taotoken.net/api, apiKey: sk-你的TaoToken密钥, model: claude-sonnet-4-5 } ], activeProfile: taotoken-unified }Cline 侧在设置面板里选 OpenAI CompatibleBase URL 填https://taotoken.net/apiAPI Key 填同一个模型名按需选。这样 NewAPI 和 Sub2API 背后的渠道都通过 TaoToken 统一分发客户端只认一个入口。5. 连通性验证与成功结果5.1 本地服务健康检查curl -sS http://127.0.0.1:3000/api/status | head -c 200 curl -sS http://127.0.0.1:8080/health两个都返回正常即服务层没问题。5.2 通过 TaoToken 通道验证模型调用curl -sS https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的TaoToken密钥 \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 只回复两个字通了}], max_tokens: 16 }期望返回结构里choices[0].message.content有内容usage字段有 token 计数。如果只想快速验证模型是否可用可以直接在模型对话页试模型对话https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deploy5.3 客户端侧验证在 Cline 里发一条简单指令观察是否正常返回CC Switch 切到taotoken-unifiedprofile 后同样发一条。两边都能通说明统一 Key 链路跑通了。5.4 端口与服务清单sudo docker ps --format table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}} sudo ss -tlnp | grep -E :(3000|8080) 服务监听用途new-api0.0.0.0:3000NewAPI Web/APIsub2api127.0.0.1:8080Sub2API Web/APInew-api-mysql仅容器内 3306MySQL不暴露new-api-redis仅容器内 6379RedisDB0newapiDB1sub2apisub2api-postgres仅容器内 5432PostgreSQL不暴露6. 本篇常见报错排查症状可能原因处置docker compose pull卡死镜像源不可达配置加速器后sudo systemctl restart dockerMySQL OOM 自动重启buffer-pool 没限制确认 compose 里有--innodb-buffer-pool-size128M加 swapUnauthorized, New-Api-User header not provided调管理员接口忘带 header所有/api/option、/api/user/...必须带-H New-Api-User: $UID第二次跑 setup 报用户名密码不正确DB 已有 root用.env.secret里的 ROOT_PASSWORD不要重新生成Sub2API 启动报POSTGRES_PASSWORD is requiredenv 没带过去检查set -a; source .env.secret; set a后再启动Sub2API 重启数据全丢PGDATA 没显式设按 4.2 节把PGDATA设为/var/lib/postgresql/dataSub2API 连不上 redisexternal 网络名错docker network ls看 NewAPI 网络名是不是new-api_default客户端报 401Key 或 Base URL 填错确认 Base URL 是https://taotoken.net/apiKey 无多余空格客户端超时网络或模型响应慢把timeout调到 120 秒以上开启 retry排查接入类问题时优先去 API Keys 页面核对 Key 状态API Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deploy接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deploy7. 长期编码与 Agent 场景的接入建议如果你打算把这条链路用在长期编码或 Agent 任务上比如让 Claude Code 或自建 Agent 持续调用建议单独走 Coding Plan避免和临时调试共用额度导致互相挤占Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deployClaude Code 接入https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentnewapi_sub2api_deploy配置上把config.toml的timeout_seconds提到 300retry.maxAttempts设 3长任务不容易断。日常运维记得定期备份sudo docker exec new-api-mysql sh -c \ MYSQL_PWD$(grep ^MYSQL_PASSWORD /opt/new-api/.env.secret | cut -d -f2) \ mysqldump -unewapi --single-transaction --quick --lock-tablesfalse new-api \ | sudo tee /opt/backup/new-api-$(date %F).sql /dev/null sudo docker exec sub2api-postgres pg_dump -U sub2api sub2api \ | gzip | sudo tee /opt/backup/sub2api-$(date %F).sql.gz /dev/null最后提醒一句.env.secret两个文件都保持chmod 600MySQL、Postgres、Redis 端口都不要暴露宿主机部署完把 SSH 改成只留密钥登录。这套组合跑顺之后NewAPI 管渠道、Sub2API 管订阅、TaoToken 管统一入口客户端只配一次就能长期用下去。
网站建设高端定制企业官网