免责说明:本教程仅用于学习使用,请勿用于商业用途、生产用途或其他不合规用途。由此导致的任何损失或者风险,本人不承担任何责任。
强烈建议优先阅读以下两个教程,可以帮助理解本文教程过程:
newapi:
sub2api :
本人服务器环境: Ubuntu 24.04

使用下面命令,可以查看自己的服务器系统。建议云服务器使用硅谷节点,或者其他欧美地区的。采用靠谱厂家,但不要选择TX和ALI,也不要选择AWS等国际一线的。具体原由,可以自行查找A厂合规要求,以及O厂、G厂等等。
cat/etc/os-release | head-5 安装 Docker + Docker Compose
先安装基础工具包
sudo apt -getupdate-y sudo apt -getinstall -y ca -certificates curl gnupg lsb -releasevim 加 Docker 官方 GPG(中国大陆建议清华源)
sudoinstall -m 0755 -d /etc/apt/keyrings 优先官方,失败自动尝试清华
sudocurl -fsSL --connect-timeout 8 https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc 或者
sudocurl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc文件授权
sudochmoda+r /etc/apt/keyrings/docker.asc 写 apt 源(自动用清华镜像,拉不通再换官方),命令顺序如下
CODENAME=$(. /etc/os-release && echo"$VERSION_CODENAME")
ARCH=$(dpkg --print-architecture)
REPO=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu
curl -fsSI -- connect-timeout 5"$REPO/dists/$CODENAME/Release"> /dev/null || REPO=https: //download.docker.com/linux/ubuntu
echo"deb [arch=$ARCHsigned-by=/etc/apt/keyrings/docker.asc] $REPO$CODENAMEstable" | sudotee/etc/apt/sources.list.d/docker.list
sudo apt -getupdate-y 接下来需要安装 Docker
sudoapt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudosystemctl enable--now docker
sudousermod -aG docker $USER验证docker
docker --version
dockercompose version 
> ⚠️ `usermod -aG docker` 加组之后,重新登录 SSH 后才不用 sudo 跑 docker。本教程后面命令仍带 `sudo` 兼容。
配置镜像加速
sudotee/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"}}
sudosystemctl restart docker
dockerinfo| grep -A3 'Registry Mirrors'`log-opts` 限制单容器日志最多 30 MB(10×3),避免长跑日志撑爆磁盘。
部署 new-api
创建目录
sudomkdir-p /opt/new-api/{data,logs,mysql,redis}
sudochown-R $USER: $USER/opt/new-api
cd/opt/new-api 
生成密码并保存
执行下面这段会一次性生成 4 个随机密码并写入 `.env.secret`,只生成一次,丢了就要全部重置:
cat> /opt/new-api/.env.secret << EOF
MYSQL_ROOT_PASSWORD=$(openssl rand -base64 24| tr -d '=+/'| cut -c1- 24) MYSQL_USER=newapi MYSQL_PASSWORD=$(openssl rand -base64 24| tr -d '=+/'| cut -c1- 24) SESSION_SECRET=$(openssl rand -hex 32)
chmod600 /opt/new-api/.env.secret
cat/opt/new-api/.env.secret # 复制到自己的密码管理器把上面输出的 4 行抄到密码管理器(KeePass、1Password 等)。
写 docker-compose.yml
# 加载刚生成的密码到 shell 变量
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:latestcontainer_name: new-apirestart: unless-stoppeddepends_on:mysql:condition: service_healthyredis:condition: service_startedports:- "3000:3000"environment:TZ: Asia/ShanghaiSQL_DSN: "newapi:${MYSQL_PASSWORD}@tcp(mysql:3306)/new-api?charset=utf8mb4&parseTime=True&loc=Local"REDIS_CONN_STRING: "redis://redis:6379/0"SESSION_SECRET: "${SESSION_SECRET}"CRYPTO_SECRET: "${SESSION_SECRET}"SYSTEM_NAME: "WeskyApi"GIN_MODE: releaseERROR_LOG_ENABLED: "true"volumes:- ./data:/data- ./logs:/app/logshealthcheck:test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/status >/dev/null || exit 1"] interval: 30stimeout: 5s retries: 10mysql:image: mysql:8.4container_name: new-api-mysqlrestart: unless-stoppedenvironment:MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"MYSQL_DATABASE: "new-api"MYSQL_USER: "newapi"MYSQL_PASSWORD: "${MYSQL_PASSWORD}"TZ: Asia/Shanghaicommand: - --character-set-server=utf8mb4- --collation-server=utf8mb4_unicode_ci- --innodb-buffer-pool-size=128M- --max-connections=200- --performance-schema=OFFvolumes:- ./mysql:/var/lib/mysqlhealthcheck:test: [ "CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"] interval: 10stimeout: 5s retries: 20redis:image: redis:7-alpinecontainer_name: new-api-redisrestart: unless-stoppedcommand: [ "redis-server", "--maxmemory", "128mb", "--maxmemory-policy", "allkeys-lru", "--save", "900", "1"] volumes:- ./redis:/dataEOF> 关键调优(小内存机器必须):
> - MySQL`--innodb-buffer-pool-size=128M`:默认会自适应到 25% 内存 > - MySQL`--performance-schema=OFF`:省 ~ 50MB> - Redis`--maxmemory 128mb`+ LRU:防止无限增长 拉镜像并启动
cd/opt/new-api sudodocker compose pull # 首次约 200 MB,国内 1-3 分钟sudodocker compose up -d sudodocker compose ps 等服务就绪
fori in$( seq1 36); doifcurl -fsS http://127.0.0.1:3000/api/status >/dev/null; thenecho"ok"; breakfiecho"等待中 $i/36"; sleep5 done成功的话最后显示 `ok`,否则看日志:
sudodocker logs -- tail100 new-api sudodocker logs -- tail100 new-api-mysql 完成首次初始化(创建 root 管理员)
当前版本 new-api 不再预置默认账户,必须主动调 `/api/setup` 接口。先生成 root 密码:
ROOT_USER=rootROOT_PASSWORD= "Wesky-$(openssl rand -base64 16 | tr -d '=+/' | cut -c1-16)"echo"ROOT_USERNAME=$ROOT_USER"| sudotee-a /opt/new-api/.env.secret echo"ROOT_PASSWORD=$ROOT_PASSWORD"| sudotee-a /opt/new-api/.env.secret echo">>> 务必记下: $ROOT_USER/ $ROOT_PASSWORD"调用 setup 接口:
curl -sS -X POST http://127.0.0.1:3000/api/setup -H 'Content-Type: application/json' -d "$(cat < { "Username": "$ROOT_USER", "Password": "$ROOT_PASSWORD", "ConfirmPassword": "$ROOT_PASSWORD", "SelfUseModeEnabled":false, "DemoSiteEnabled":false} EOF)"echo期望返回 `{"message":"系统初始化成功","success":true}`。
登录拿 cookie + uid
LOGIN_RESP=$(curl -sS -c /tmp/newapi_cookie.txt -XPOSThttp: //127.0.0.1:3000/api/user/login -H' Content-Type: application /json' -d "{"username":"$ROOT_USER","password":"$ROOT_PASSWORD"}") echo "$LOGIN_RESP"UID=$(echo "$LOGIN_RESP"|python3 -c ' importsys,json; print(json.load(sys.stdin)[ "data"][ "id"])') echo "UID=$UID"> ⚠️ 关键坑:调任何管理员接口都要带 `New-Api-User: $UID` 这个 HTTP 头,仅 cookie 不够。否则会得到 `Unauthorized, New-Api-User header not provided`。
写入品牌信息(system_name / footer / 首页 / about)
H= "-H Content-Type:application/json -H Accept:application/json -H New-Api-User:$UID"B=http:// 127.0. 0.1: 3000例如把newapi标题,改为WeskyApi
# system_namecurl -sS -b /tmp/newapi_cookie.txt -XPUT$B/api/option /$H -d '{ "key": "SystemName", "value": "WeskyApi"}'; echo
# Logo(留空→前端渲染 SystemName文字) curl -sS -b /tmp/newapi_cookie.txt -XPUT$B/api/option /$H -d '{ "key": "Logo", "value": ""}'; echo
# 底栏curl -sS -b /tmp/newapi_cookie.txt -XPUT$B/api/option /$H -d '{ "key": "Footer", "value": " "text-align:center">WeskyApi © 2026
"}'; echo
# 首页内容curl -sS -b /tmp/newapi_cookie.txt -XPUT$B/api/option /$H -d '{ "key": "HomePageContent", "value": ""}'; echo "text-align:center;padding:48px 20px"> "font-size:42px;letter-spacing:4px;color:#00e6ff">WeskyApi
"color: #9ab;margin-top:12px ">统一大模型 API 中转服务 · 稳定 · 高速
# 关于curl -sS -b /tmp/newapi_cookie.txt -XPUT$B/api/option /$H -d '{ "key": "About", "value": " WeskyApi 由 Wesky 团队运营与维护。
"}'; echo
每条返回 `{"message":"","success":true}` 即成功。
验证
curl-sS http:// 127.0.0.1:3000/api/status | python3 -c 'import sys,json;d=json.load(sys.stdin)[ "data"];print( "system_name=",d[ "system_name"]);print( "footer_html=",d[ "footer_html"][: 80])' 期望 `system_name= WeskyApi`。
安装 cloudflared 并暴露 new-api
装 cloudflared (Cloudflare 官方 apt 源)
sudomkdir-p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudotee/usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed -by =/usr /share/keyrings /cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared anymain' |sudo tee /etc/apt /sources.list.d/cloudflared.list
sudo apt -getupdate-y sudo apt -getinstall -y cloudflared cloudflared --version # 期望 2026.x
写 systemd 单元 `cloudflared-newapi.service`
sudotee/etc/systemd/system/cloudflared-newapi.service >/dev/null << 'EOF'
[Unit]Deion=cloudflared quick tunnel for new-api (trycloudflare.com)After=network-online.target docker.serviceWants=network-online.target[Service]Type=simpleExecStart=/usr/local/bin/cloudflared tunnel --url http://127.0.0.1:3000 --no-autoupdate --metrics 127.0.0.1:20241Restart=on-failureRestartSec=5User=rootStandardOutput=append:/var/log/cloudflared-newapi.logStandardError=append:/var/log/cloudflared-newapi.logExecStartPre=/bin/sh -c 'command -v cloudflared | xargs -I{} ln -sf {} /usr/local/bin/cloudflared'[Install]WantedBy=multi-user.targetEOF
sudo: > /var/log/cloudflared-newapi.log sudochmod640 /var/log/cloudflared-newapi.log sudosystemctl daemon-reload sudosystemctl enable--now cloudflared-newapi.service sudosystemctl status cloudflared-newapi.service --no-pager | head-10 > `--metrics 127.0.0.1:20241`:第一个 tunnel 占 20241,第二个用 20242,两个不能撞。
拿到 trycloudflare URL
fori in$( seq1 30); doURL=$( sudogrep -oE 'https://[a-z0-9-]+.trycloudflare.com'/var/log/cloudflared-newapi.log | head-1) [ -n "$URL"] && { echo"URL: $URL"; break; } sleep3 doneecho"$URL"| sudotee/opt/new-api/tunnel_url.txt 映射的公网域名地址会被写入到指定的txt文件内,例如

把 URL 写回 new-api(让 Token 详情页生成完整链接)
curl -sS -b /tmp/newapi_cookie.txt -XPUThttp: //127.0.0.1:3000/api/option/ -H' Content-Type: application /json' -H"New-Api-User: $UID" -d "{"key":"ServerAddress","value":"$URL"}"echo从你的电脑(不是服务器)验证
curl -sS https://你的tunnel域名.trycloudflare.com/api/status | head-c 200> ⚠️ 服务器自己 curl trycloudflare.com 可能解析失败(DNS 屏蔽),不影响外部访问。
到这里 NewApi即可整体上线了。浏览器打开 URL 用 root(或者你自己定义的其他用户名) + 生成的密码登录即可。
部署 Sub2API
关键设计
-复用 new-api 的 Redis(不再起新的 Redis 容器) -单独起 PostgreSQL 18-alpine(Sub2API 强依赖) -端口仅绑 `127.0.0.1:8080`,强制走 cloudflared -Postgres 不暴露端口 创建目录
sudomkdir-p /opt/sub2api/{data,postgres} sudochown-R $USER: $USER/opt/sub2api cd/opt/sub2api 生成机密
cat > /opt/sub2api/.env.secret < POSTGRES_PASSWORD= $(openssl rand-base64 24| tr-d '=+/'| cut -c1- 24) JWT_SECRET= $(openssl rand- hex32) TOTP_ENCRYPTION_KEY= $(openssl rand- hex32) ADMIN_EMAIL=admin @weskyapi.local ADMIN_PASSWORD=Wesky- $(openssl rand-base64 16| tr-d '=+/'| cut -c1- 16) EOF
chmod600 /opt/sub2api/.env.secret cat/opt/sub2api/.env.secret # 抄到密码管理器> - `JWT_SECRET` 必须固定:变了所有用户被踢下线
> - `TOTP_ENCRYPTION_KEY` 必须固定:变了所有 2FA 失效
> - `ADMIN_EMAIL` 是登录用户名
写 docker-compose.yml
set-a; source/opt/sub2api/.env.secret; set+a
cat > /opt/sub2api/docker-compose.yml < services:sub2api:image: weishaw/sub2api:latestcontainer_name: sub2apirestart: unless-stoppedulimits:nofile: { soft: 65535, hard: 65535} ports:- "127.0.0.1:8080:8080"depends_on:postgres:condition: service_healthyvolumes:- ./ data:/app/ dataenvironment:AUTO_SETUP: "true"SERVER_HOST: "0.0.0.0"SERVER_PORT: "8080"SERVER_MODE: "release"RUN_MODE: "standard"DATABASE_HOST: postgresDATABASE_PORT: "5432"DATABASE_USER: sub2apiDATABASE_PASSWORD: "${POSTGRES_PASSWORD}"DATABASE_DBNAME: sub2apiDATABASE_SSLMODE: disableDATABASE_MAX_OPEN_CONNS: "30"DATABASE_MAX_IDLE_CONNS: "5"REDIS_HOST: new-api-redisREDIS_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/ShanghaiSECURITY_URL_ALLOWLIST_ENABLED: "false"SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP: "true"SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS: "true"networks:- sub2api-network- newapi-sharedhealthcheck:test: [ "CMD", "wget", "-q", "-T", "5", "-O", "/dev/null", "http://localhost:8080/health"] interval: 30stimeout: 10sretries: 5start_period: 60spostgres:image: postgres: 18-alpine container_name: sub2api-postgresrestart: unless-stoppedshm_size: 128mbenvironment:PGDATA: / var/lib/postgresql/ dataPOSTGRES_USER: sub2apiPOSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"POSTGRES_DB: sub2apiTZ: Asia/Shanghaicommand:- postgres- -c- shared_buffers=64MB- -c- effective_cache_size=192MB- -c- max_connections= 80volumes:- ./postgres:/ var/lib/postgresql/ datanetworks:- sub2api-networkhealthcheck:test: [ "CMD-SHELL", "pg_isready -U sub2api -d sub2api"] interval: 10stimeout: 5sretries: 10start_period: 30snetworks:sub2api-network:driver: bridgenewapi-shared:external: truename: new-api_defaultEOF> 三个不能省的细节:
> 2. `shm_size: 128mb`:PG18 默认 64MB 太小,复杂查询会报 shared memory 不足。
> 3. `networks.newapi-shared.external: true name: new-api_default`:把 sub2api 接入 new-api 的网络,才能用容器名 `new-api-redis` 解析到那个 redis 容器。
启动
cd/opt/sub2api sudodocker compose pull # 首次约 250 MBsudodocker compose up -d sudodocker compose ps 期望两个容器都 `Up (healthy)`:
sub2apiweishaw/sub2api:latest Up (healthy) 127.0.0.1:8080-> 8080/tcp sub2api-postgres postgres: 18-alpine Up (healthy) 5432/tcp 
注意 `sub2api` 的 PORTS 列必须是 `127.0.0.1:8080`,不是 `0.0.0.0`。
等就绪 + 验证
fori in$( seq1 36); doifcurl -fsS http://127.0.0.1:8080/health >/dev/null; thenechook; break; fiecho"等待中 $i"; sleep5 done
curl-sS http:// 127.0.0.1:8080/health # { "status": "ok"} 启动失败时看日志:
sudodocker logs -- tail100 sub2api sudodocker logs -- tail100 sub2api-postgres 暴露 Sub2API(第二个 cloudflared tunnel)
systemd 单元 `cloudflared-sub2api.service`
sudotee/etc/systemd/system/cloudflared-sub2api.service >/dev/null << 'EOF'
[Unit]Deion=cloudflared quick tunnel for Sub2API (trycloudflare.com)After=network-online.target docker.serviceWants=network-online.target[Service]Type=simpleExecStart=/usr/local/bin/cloudflared tunnel --url http://127.0.0.1:8080 --no-autoupdate --metrics 127.0.0.1:20242Restart=on-failureRestartSec=5User=rootStandardOutput=append:/var/log/cloudflared-sub2api.logStandardError=append:/var/log/cloudflared-sub2api.logExecStartPre=/bin/sh -c 'command -v cloudflared | xargs -I{} ln -sf {} /usr/local/bin/cloudflared'[Install]WantedBy=multi-user.targetEOF
sudo: > /var/log/cloudflared-sub2api. logsudochmod640 /var/log/cloudflared-sub2api. logsudosystemctl daemon-reload sudosystemctl enable--now cloudflared-sub2api.service 与第一个单元的 3 处差异:
- `--url` 指向 `8080`
- `--metrics` 用 `20242`
- 日志路径 `cloudflared-sub2api.log`
拿 URL
fori in$( seq1 30); doURL2=$( sudogrep -oE 'https://[a-z0-9-]+.trycloudflare.com'/var/log/cloudflared-sub2api. log| head-1) [ -n "$URL2"] && { echo"Sub2API URL: $URL2"; break; } sleep3 done
echo"$URL2"| sudotee/opt/sub2api/tunnel_url.txt 验证(从其他机器电脑访问)
curl -sS https://你的sub2api.trycloudflare.com/health # 期望: {"status": "ok"} 浏览器打开此 URL,用 `.env.secret` 里的 `ADMIN_EMAIL` / `ADMIN_PASSWORD` 登录。
端口与服务清单(部署完成后查看)
# 容器sudodocker ps --format 'table {{.Names}} {{.Image}} {{.Status}} {{.Ports}}'
# systemd 服务systemctl list-units --type=service -- state=running | grep-E '(docker|cloudflared)'
# 内存占用free-h
# 端口sudoss -tlnp | grep -E ':( 3000| 8080| 20241| 20242) ' 正常情况:
| 服务 | 监听 | 用途 ||---|---|---|| `new-api`| `0.0.0.0:3000`| new-api Web/ API| | `sub2api`| `127.0.0.1:8080`| Sub2APIWeb/ API| | `cloudflared-newapi`| `127.0.0.1:20241`| 第一个 tunnel 指标端口 | | `cloudflared-sub2api`| `127.0.0.1:20242`| 第二个 tunnel 指标端口 | | `new-api-mysql`| 仅容器内 3306| MySQL,不暴露 | | `new-api-redis`| 仅容器内 6379| Redis( DB0=newapi, DB1=sub2api) | | `sub2api-postgres`| 仅容器内 5432| PostgreSQL,不暴露 | 日常运维
看日志
sudodocker logs -f -- tail100 new-api sudodocker logs -f -- tail100 sub2api sudojournalctl -u cloudflared-newapi.service -n 100 --no-pager sudojournalctl -u cloudflared-sub2api.service -n 100 --no-pager sudotail-f /var/log/cloudflared-newapi.log /var/log/cloudflared-sub2api. log重启服务
# 应用容器sudodocker compose -f /opt/new-api/docker-compose.yml restart new-api sudodocker compose -f /opt/sub2api/docker-compose.yml restart sub2api
# Tunnel(重启会换 trycloudflare URL!)sudosystemctl restart cloudflared-newapi.service sudosystemctl restart cloudflared-sub2api.service
# 拿新 URLcat/opt/new-api/tunnel_url.txt cat/opt/sub2api/tunnel_url.txt
# 或直接从日志重抓sudogrep -oE 'https://[a-z0-9-]+.trycloudflare.com'/var/log/cloudflared-newapi.log | tail-1 sudogrep -oE 'https://[a-z0-9-]+.trycloudflare.com'/var/log/cloudflared-sub2api. log| tail-1 升级镜像
cd/opt/new-api && sudodocker compose pull && sudodocker compose up -d cd/opt/sub2api && sudodocker compose pull && sudodocker compose up -d sudodocker image prune -f 备份
sudomkdir-p /opt/backup
# new-api MySQLsudodocker execnew-api-mysql sh -c 'MYSQL_PWD=$(grep ^MYSQL_PASSWORD /opt/new-api/.env.secret | cut -d= -f2) mysqldump -unewapi --single-transaction --quick --lock-tables=false new-api' | sudotee/opt/backup/new-api-$( date+%F).sql >/dev/null
# Sub2API PostgreSQLsudodocker execsub2api-postgres pg_dump -U sub2api sub2api | gzip | sudotee/opt/backup/sub2api-$( date+%F).sql.gz >/dev/null
# 数据目录sudotar czf /opt/backup/new-api-data-$( date+%F).tgz /opt/new-api/{data,logs} sudotar czf /opt/backup/sub2api-data-$( date+%F).tgz /opt/sub2api/data ls-lh /opt/backup/ 加 cron 每天凌晨备份:
sudocrontab -e # 加一行:0 3 * * * /usr/bin/bash -lc '/opt/s/backup.sh'>>/var/log/backup.log 2>&1 升级到正式域名(Named Tunnel)
`trycloudflare.com` 临时域名每次重启 cloudflared 都换,不适合生产。要稳定走自有域名:
域名上 Cloudflare
1. 在 [dash.cloudflare.com](https://dash.cloudflare.com) → Add a Site
2. 把域名 NS 改到 Cloudflare 提供的两条 NS
3. 等 Zone 状态变 Active(一般 5-30 分钟)
在 Zero Trust 创建 Tunnel
[one.dash.cloudflare.com](https://one.dash.cloudflare.com) → Networks → Tunnels →
Create a tunnel→ Cloudflared → 起个名(如 `vps-1`)→ 选 Linux 看到一段安装命令,里面有 `--token eyJhI...`,把 token 复制下来。
在 Public Hostname标签页加两条记录:
| Subdomain| Domain| Type| URL| |---|---|---|---|| `api`| yourdomain. com| HTTP| `localhost:3000`| | `pincc`| yourdomain. com| HTTP| `localhost:8080`| 替换 systemd unit
sudosystemctl stop cloudflared-newapi.service cloudflared-sub2api.service sudotee/etc/systemd/system/cloudflared.service >/dev/null << EOF
[Unit]Deion=cloudflared (named tunnel)After=network-online.target docker.serviceWants=network-online.target[Service]Type=simpleExecStart=/usr/local/bin/cloudflared tunnel run --token
<粘贴你的token>粘贴你的token>Restart=on-failureRestartSec=5User=root[Install]WantedBy=multi-user.targetEOF
sudosystemctl disablecloudflared-newapi.service cloudflared-sub2api.service sudosystemctl daemon-reload sudosystemctl enable--now cloudflared.service sudosystemctl status cloudflared.service --no-pager | head-10 同步 ServerAddress
new-api 上:
重新登录拿 cookie + UID,然后:
curl-sS -b /tmp/newapi_cookie.txt -X PUT http:// 127.0.0.1:3000/api/option/ -H 'Content-Type: application/json' -H "New-Api-User: $UID"-d '{ "key": "ServerAddress", "value": "https://api.yourdomain.com"}' 故障排查速查
| 症状 | 可能原因 | 处置 ||---|---|---|| `docker compose pull`卡死 | 镜像源不可达 | 第 2.5节加加速器后 `sudo systemctl restart docker`| | MySQLOOM自动重启 | buffer-pool 没限制 | 确认 compose 里有 `--innodb-buffer-pool-size=128M`,加 swap | | `Unauthorized, 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 required`| env 没带过去 | 检查 `set -a; source .env.secret; set +a`后再 envsubst | | Sub2API重启数据全丢 | `PGDATA`没显式设 | 第 5.4节关键细节 1| | Sub2API连不上 redis | external 网络名错 | `docker network ls`看 new-api 的网络名是不是 `new-api_default`| | TunnelURL突然不通 | cloudflared 重启换了 URL| `cat /opt/*/tunnel_url.txt`拿新地址,或看日志 | | 服务器自己 curl trycloudflare 失败 | 国内 DNS屏蔽 | 不影响外部,从本机/手机访问验证 | | 两个 tunnel 同时只起来一个 | metrics 端口撞了 | 第二个改成 20242| 安全清单
- - [ ] `/opt/new-api/.env.secret` 与 `/opt/sub2api/.env.secret` 都是 `chmod 600`
- - [ ] MySQL / Postgres / Redis 端口都没暴露宿主机
- - [ ] 想更严的话把 new-api 端口也改成 `127.0.0.1:3000`
- - [ ] 所有密码 ≥24 字节随机生成
- - [ ] `JWT_SECRET` / `TOTP_ENCRYPTION_KEY` 是固定值
- - [ ] 部署完后改 SSH:`PasswordAuthentication no`,只留密钥
- - [ ] 启用 ufw 或腾讯云安全组:只开 22/80/443,封掉 3000/8080
- - [ ] 备份脚本接 cron
- - [ ] 留一条 `df -h` / `free -h` 的监控告警
文件位置速查
|路径 |用途 ||---|---||` /opt/new -api /docker -compose.yml` |new -api 栈定义 ||` /opt/new -api /.env.secret` | new-api MySQL/root 密码 ||` /opt/new -api /data/` |new -api 应用数据 ||` /opt/new -api /mysql/` |MySQL数据 ||` /opt/new -api /redis/` |Redis持久化 ||` /opt/new -api /tunnel_url.txt` |当前 trycloudflare URL||` /opt/sub2api /docker -compose.yml` |Sub2API栈定义 ||` /opt/sub2api /.env.secret` | Sub2API JWT/Postgres/管理员密码 ||` /opt/sub2api /data/` |Sub2API应用数据 ||` /opt/sub2api /postgres/` |PostgreSQL数据 ||` /opt/sub2api /tunnel_url.txt` |当前 trycloudflare URL||` /etc/systemd /system/cloudflared -newapi.service` |new -api tunnel ||` /etc/systemd /system/cloudflared -sub2api.service` |Sub2APItunnel ||` /var/log /cloudflared -newapi.log` |new -api tunnel 日志 ||` /var/log /cloudflared -sub2api.log` |Sub2APItunnel 日志 ||` /etc/docker /daemon.json` |Docker镜像加速 |参考链接
- new-api:https://github.com/Calcium-Ion/new-api- Sub2API:https://github.com/Wei-Shaw/sub2api- Cloudflare Tunnel:https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/知乎图文简易教程链接:
newapi:
sub2api :
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/270608.html