sub2api/docs/agent-specs/2026-05-26-proxy-ng-origin加固-审阅版.md
zizi 6814fa2a62 docs(ops): record proxy-ng deployment hardening
Add deployment traces for the JPpro proxy node, RackNerd origin hosts, catproxy boundary changes, local speed checks, and Sub2API rate-limit behavior.

Keep remote secrets excluded while tracking sanitized nginx, compose, plan, and operational memory documents.
2026-05-26 23:27:41 +08:00

1029 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# proxy-ng origin 加固方案 — 审阅版
日期2026-05-26
状态已执行2026-05-26 有边界调整
适用范围:`proxy.api.lilifamily.com` 公开入口、`catproxy.lilifamily.com` 公开直连主站入口、`origin.proxy.api.lilifamily.com` 受限回源入口、`*.proxy.api.lilifamily.com` proxy-ng 节点扩展
> 2026-05-26 决策变更:`catproxy.lilifamily.com` 不再做 IP 白名单限制,作为 3c4g 公开直连主站域名和回滚入口;只有 `origin.proxy.api.lilifamily.com` 保持来源 IP 白名单和 `X-Proxy-Ng-Token` 校验。本文中早期关于 `catproxy` 受限访问的草案描述已被此决策覆盖,当前运行事实以 `ops/remote/us-racknerd-0526-sub2api/` 为准。
## 1. 结论
当前 JPpro 入口中转已经可以用于稳定性测试,但还不是生产加固架构。后续不依赖 Cloudflare Load Balancing公开入口用普通 DNS 记录指向 proxy-ng 节点,防攻击和主站隐藏由 nginx、防火墙、origin 白名单和 token 完成。
当前已执行链路是:
```mermaid
flowchart LR
U[用户] -->|HTTPS| P[公开入口<br/>proxy.api.lilifamily.com]
P -->|HTTPS| J[JPpro nginx<br/>jp.proxy.api.lilifamily.com]
J -->|HTTPS + 节点 Token| O[3c4g origin nginx<br/>origin.proxy.api.lilifamily.com]
O -->|127.0.0.1:8080| S[Sub2API]
C[直连用户] -->|HTTPS| D[3c4g nginx<br/>catproxy.lilifamily.com]
D -->|127.0.0.1:8080| S
```
推荐生产加固链路是:
```mermaid
flowchart LR
U[用户] -->|HTTPS| D[公开入口<br/>proxy.api.lilifamily.com<br/>普通多 A / 手工切换]
D --> J[JPpro nginx<br/>jp.proxy.api.lilifamily.com]
D --> N[其它 proxy-ng 节点<br/>*.proxy.api.lilifamily.com]
J -->|HTTPS + 节点 Token| O[3c4g origin nginx<br/>origin.proxy.api.lilifamily.com]
N -->|HTTPS + 节点 Token| O
O -->|本机回环| S[Sub2API :8080]
C[普通公网用户] -.->|403 / 拒绝| O
X[未知服务器] -.->|IP 不在白名单| O
```
前置阶段先做域名迁移和入口角色调整:
1. 公开服务入口保留为 `proxy.api.lilifamily.com`,但它不再指向 3c4g而是指向 proxy-ng 节点。
2. 3c4g 原直连入口从 `proxy.api.lilifamily.com` 改为 `catproxy.lilifamily.com`,作为公开直连主站域名和回滚入口。
3. DNS 增加 `origin.proxy.api.lilifamily.com` A 记录,指向 3c4g只给 proxy-ng 回源使用。
4. 其它 proxy-ng 节点统一使用 `<node>.proxy.api.lilifamily.com` 命名。
第一阶段加固只建议做三件事:
1. 在 3c4g 增加独立 origin 入口:`origin.proxy.api.lilifamily.com`
2. origin 入口只允许 JPpro IP 访问,并校验 `X-Proxy-Ng-Token`
3. JPpro 从回源公网主域名改为回源 origin 入口。
4. `proxy.api.lilifamily.com` 的 A 记录只指向 proxy-ng 节点,不再暴露 3c4g。
这三项完成后proxy-ng 才从“能用的公网反代”升级成“信任边界清楚的入口中转”。
## 2. 当前已验证事实
| 项目 | 当前事实 |
|---|---|
| JPpro 服务器 | `个人-JPpro-akile-0504-1c1g` |
| JPpro 公网 IP | `151.242.164.72` |
| JPpro 入口域名 | `jp.proxy.api.lilifamily.com` |
| JPpro 当前职责 | 只运行 nginx proxy-ng不运行 Sub2API、PostgreSQL、Redis、Caddy 或账号出口代理 |
| JPpro 当前回源 | 测试期可临时回源 `https://catproxy.lilifamily.com`,加固后必须改为 `https://origin.proxy.api.lilifamily.com` |
| 3c4g 服务器 | `个人-US-racknerd-0526-3c4g` |
| 公开服务入口域名 | `proxy.api.lilifamily.com`,目标是普通多 A 指向 proxy-ng 节点 |
| 3c4g 公开直连主站域名 | `catproxy.lilifamily.com`,不做 IP 白名单限制 |
| 3c4g origin 域名 | `origin.proxy.api.lilifamily.com`,只给 proxy-ng 回源 |
| 3c4g 当前职责 | nginx 反代到本机 Sub2API `127.0.0.1:8080` |
| 当前风险边界 | 直接回源公网主域名,尚未做独立 origin、后端来源 IP 白名单、`X-Proxy-Ng-Token` 校验 |
## 2.1 域名命名与 DNS 记录
本方案按以下域名边界规划:
| 域名 | DNS 记录 | 角色 | 说明 |
|---|---|---|---|
| `proxy.api.lilifamily.com` | 多个 A -> proxy-ng 节点 IP | 公开服务入口 | 不用 Cloudflare LB普通 DNS 多 A 或手工切换 |
| `catproxy.lilifamily.com` | A -> `216.45.59.243` | 3c4g 公开直连主站入口 | 可直接访问主站,也可作为 proxy-ng 故障时的回滚入口 |
| `origin.proxy.api.lilifamily.com` | A -> `216.45.59.243` | 3c4g 回源入口 | 只给 proxy-ng 节点访问,必须加 IP 白名单和 token |
| `jp.proxy.api.lilifamily.com` | A -> `151.242.164.72` | JPpro proxy-ng 节点 | 当前第一台入口中转节点 |
| `*.proxy.api.lilifamily.com` | 每个节点独立 A/AAAA | 后续 proxy-ng 节点命名空间 | 例如 `us.proxy.api.lilifamily.com``sg.proxy.api.lilifamily.com` |
约束:
- `proxy.api.lilifamily.com` 是用户看到的正式入口,但它只指向 proxy-ng 节点,不直接指向 3c4g。
- `catproxy.lilifamily.com` 是独立公开直连入口proxy-ng 回源不使用它,也不应在 `proxy.api.lilifamily.com` 链路中把它暴露到 `Location``Host`、页面链接或错误页中。
- `*.proxy.api.lilifamily.com` 在本文表示节点命名规则,不等于必须使用一条 wildcard A 记录。
- 多个节点如果 IP 不同,应为每个节点创建独立 A/AAAA 记录;`proxy.api.lilifamily.com` 可以配置多个 A 记录,但这是普通 DNS 轮询,不具备健康检查和按网络质量调度能力。
- `origin.proxy.api.lilifamily.com` 即使有公网 DNS也不应作为用户入口访问控制必须在 nginx 和防火墙层生效。
- `origin` 默认限制公网访问,证书签发不应依赖长期开放 HTTP-01优先使用 DNS-01或在签发/续期窗口临时开放并立即恢复限制。`catproxy` 公开访问,可使用常规 HTTP-01。
当前配置留痕:
| 文件 | 说明 |
|---|---|
| `ops/remote/jppro-sub2api/README.md` | JPpro proxy-ng 部署记录 |
| `ops/remote/jppro-sub2api/current/nginx-jp-proxy-sub2api.conf` | JPpro 当前 nginx 配置副本 |
| `ops/remote/us-racknerd-0526-sub2api/current/nginx-sub2api.conf` | 3c4g 当前 nginx 主入口配置副本 |
| `docs/memorys/2026-05-25-proxy-ng职责边界.md` | proxy-ng 不承担账号出口代理的边界记录 |
| `proxy-ng/README.md` | 多节点 proxy-ng 方案说明 |
| `proxy-ng/nginx/proxy-node.conf.template` | proxy-ng 节点 nginx 模板 |
| `proxy-ng/nginx/backend-gateway.conf.template` | 后端入口网关模板 |
## 3. 目标和非目标
### 目标
- 把用户公开入口和 proxy-ng 回源入口分离。
- 让 3c4g 后端能识别“这是受控 proxy-ng 节点发来的请求”。
- 防止普通公网用户绕过 proxy-ng 直接访问 origin。
- 防止客户端伪造 `X-Proxy-Ng-*``X-Forwarded-*` 头影响日志和安全判断。
- 公开入口 `proxy.api.lilifamily.com` 只解析到 proxy-ng 节点,避免 3c4g 主站直接暴露。
- 保留 `catproxy.lilifamily.com` 作为公开直连主站域名和紧急回滚入口。
- 为后续新增 proxy-ng 节点提供标准流程。
### 非目标
- 不把 JPpro 改造成账号出口代理。
- 不在 proxy-ng 节点部署 Clash、sing-box、Xray、SOCKS、mixed 等代理服务。
- 不改 Sub2API 业务代码作为第一阶段方案。
- 不在仓库提交真实 token、`.env`、API key、数据库密码。
- 不立即强制所有用户流量都走 JPpro。
- 不立即建设复杂的多地域调度系统。
## 4. 设计项解释和实施方案
### 4.1 独立 origin 入口
#### 作用
独立 origin 用来区分两类入口:
| 入口 | 面向对象 | 是否公开给用户 |
|---|---|---|
| `proxy.api.lilifamily.com` | 用户公开访问,解析到 proxy-ng 节点 | 是 |
| `catproxy.lilifamily.com` | 运维直连、临时回滚 | 否 |
| `origin.proxy.api.lilifamily.com` | proxy-ng 节点回源 | 否 |
如果 JPpro 继续回源 `https://catproxy.lilifamily.com`,那么 `catproxy` 就会被放进常规服务链路。它能用于短期迁移,但不能作为生产回源目标。生产回源必须使用 `origin.proxy.api.lilifamily.com`,并通过 IP 白名单和 token 限制访问。
独立 origin 的意义是:回源链路可以单独配置 IP 白名单、token 校验、日志格式和限流策略,不影响用户公开入口。
#### 实施方案
DNS 增加:
```text
proxy.api.lilifamily.com -> 151.242.164.72
proxy.api.lilifamily.com -> <其它 proxy-ng 节点 IP>
catproxy.lilifamily.com -> 216.45.59.243
origin.proxy.api.lilifamily.com -> 216.45.59.243
```
3c4g 新增 nginx server block
```nginx
server {
server_name origin.proxy.api.lilifamily.com;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/origin.proxy.api.lilifamily.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/origin.proxy.api.lilifamily.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host proxy.api.lilifamily.com;
proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_request_buffering off;
}
}
```
JPpro 后续改为:
```nginx
proxy_pass https://origin.proxy.api.lilifamily.com;
proxy_ssl_server_name on;
proxy_ssl_name origin.proxy.api.lilifamily.com;
proxy_set_header Host origin.proxy.api.lilifamily.com;
proxy_set_header X-Forwarded-Host $host;
```
#### 风险
- 新增域名证书签发失败会导致 origin 不可用。
- 如果直接切 JPpro 回源而未保留回滚,会造成 JPpro 入口不可用。
#### 缓解
- 先用 `curl --resolve` 验证 origin再切 JPpro。
- JPpro 原配置保留备份;失败时把 `proxy_pass` 改回 `https://catproxy.lilifamily.com`
### 4.2 来源 IP 白名单
#### 作用
来源 IP 白名单保证 origin 只接受你控制的 proxy-ng 节点访问。
即使别人知道 `origin.proxy.api.lilifamily.com`,只要请求来源 IP 不是 JPpro 或后续受控节点,就会被拒绝。
#### 实施方案
3c4g origin nginx 增加:
```nginx
location / {
allow 151.242.164.72; # JPpro
deny all;
proxy_pass http://127.0.0.1:8080;
}
```
如果服务器防火墙可控,建议同时在系统防火墙层限制:
```text
允许 151.242.164.72 访问 443 或 origin 专用端口
拒绝其他公网来源访问 origin 入口
```
后续新增节点时,只追加节点 IP
```nginx
allow 151.242.164.72; # JPpro
allow x.x.x.x; # 新 proxy-ng 节点
deny all;
```
#### 风险
- 节点 IP 写错会导致 proxy-ng 回源 403。
- VPS 如果更换 IPorigin 会继续拒绝旧配置之外的来源。
#### 缓解
- 每个节点目录必须记录公网 IP。
- 新增或迁移节点时,先更新 origin allowlist再切 DNS 或入口。
### 4.3 `X-Proxy-Ng-Token`
#### 作用
IP 白名单证明“请求来自这台服务器 IP”但不能证明“请求一定来自你配置的 nginx”。
`X-Proxy-Ng-Token` 是第二道校验:
- 防止同一节点上其他进程误打 origin。
- 防止节点配置被部分滥用。
- 为后续多节点密钥轮换提供边界。
正确边界是:
```text
来源 IP 白名单 + X-Proxy-Ng-Token + HTTPS 回源
```
Token 不是防火墙替代品。
#### 实施方案
JPpro 注入 token
```nginx
proxy_set_header X-Proxy-Ng-Token "REDACTED_SECRET";
proxy_set_header X-Proxy-Ng-Node "jppro-akile-0504-1c1g";
```
3c4g origin 校验 token
```nginx
map $http_x_proxy_ng_token $proxy_ng_token_ok {
default 0;
"REDACTED_SECRET" 1;
}
map $http_x_forwarded_host $sub2api_host {
default $http_x_forwarded_host;
"" "proxy.api.lilifamily.com";
}
server {
server_name origin.proxy.api.lilifamily.com;
location / {
if ($proxy_ng_token_ok = 0) {
return 403;
}
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Proxy-Ng-Token "";
}
}
```
真实 token 保存建议:
| 位置 | 规则 |
|---|---|
| 远程服务器 root-only 配置 | 可以保存真实 token权限建议 `600` |
| 仓库 `ops/remote/**/current/` | 只保存脱敏副本 |
| 仓库 `secrets/` | 如需本机私有备份,必须被 `.gitignore` 排除 |
#### 风险
- 所有节点共用一个 token 时,泄露后需要同步更新所有节点。
- nginx 配置中使用明文 token远程文件权限要控制好。
#### 缓解
- 第一阶段可以单 token。
- 第二阶段支持双 token先加新 token再滚动节点最后删旧 token。
- 真实 token 不写入 Git。
### 4.4 覆盖客户端伪造 header
#### 作用
客户端可以自己发送这些 header
```text
X-Proxy-Ng-Token
X-Proxy-Ng-Node
X-Forwarded-For
X-Real-IP
X-Forwarded-Host
```
如果 proxy-ng 不覆盖,后端日志和安全判断可能被伪造。
#### 实施方案
JPpro 对安全相关 header 使用 `proxy_set_header` 覆盖:
```nginx
proxy_set_header X-Proxy-Ng-Token "REDACTED_SECRET";
proxy_set_header X-Proxy-Ng-Node "jppro-akile-0504-1c1g";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $host;
```
3c4g origin 校验后清除 token不继续传给 Sub2API
```nginx
proxy_set_header X-Proxy-Ng-Token "";
proxy_set_header X-Proxy-Ng-Node $http_x_proxy_ng_node;
```
#### 风险
- 如果 `X-Forwarded-For` 处理不当Sub2API 可能拿不到真实客户端 IP。
- 如果信任任意 `X-Forwarded-For`,日志和限流可能被客户端伪造。
#### 缓解
- 第一阶段先让 JPpro 覆盖 `X-Forwarded-For``$remote_addr`,保证不可伪造。
- 后续如接入多级代理,再单独设计可信真实 IP 链路。
### 4.5 入口策略
#### 作用
入口策略决定用户应该访问哪条链路。
如果同时存在多个入口但没有规则,会出现:
- 有的用户走 JPpro。
- 有的用户绕过 JPpro 直连 3c4g。
- 出问题时无法快速判断是哪条链路坏了。
#### 推荐阶段
| 阶段 | 入口策略 | 目的 |
|---|---|---|
| P0 迁移期 | `catproxy.lilifamily.com` 可短期直连,`jp.proxy.api.lilifamily.com` 用于测试中转 | 建立回滚入口 |
| P1 加固期 | JPpro 改走 origin + IP 白名单 + token | 验证安全边界 |
| P2 稳定期 | `proxy.api.lilifamily.com` 多 A 指向 proxy-ng 节点 | 常规用户不直连 3c4g |
#### 实施方案
当前不依赖 Cloudflare LB。公开入口采用普通 DNS 多 A 或手工切换,接受“坏节点不会自动摘除”的限制。
先保持:
```text
proxy.api.lilifamily.com -> 一个或多个 proxy-ng 节点
jp.proxy.api.lilifamily.com -> JPpro proxy-ng
*.proxy.api.lilifamily.com -> 后续 proxy-ng 节点命名空间
origin.proxy.api.lilifamily.com -> 3c4g origin仅供 proxy-ng 回源
catproxy.lilifamily.com -> 3c4g 受限直连/管理/回滚入口
```
稳定期约束:
```text
proxy.api.lilifamily.com 不能解析到 3c4g
proxy-ng 节点不能把 catproxy.lilifamily.com 暴露给用户
catproxy.lilifamily.com 不能作为常规公开业务入口
```
### 4.6 监控
#### 作用
proxy-ng 是多段链路。用户报慢或报错时,需要区分:
- JPpro nginx 是否正常。
- JPpro 到 3c4g origin 是否正常。
- 3c4g nginx 是否正常。
- Sub2API 是否正常。
- 证书是否即将过期。
#### 实施方案
最小监控项:
| 检查项 | 期望 |
|---|---|
| `https://jp.proxy.api.lilifamily.com/health` | `200` |
| `https://proxy.api.lilifamily.com/health` | `200`,且解析到 proxy-ng 节点 |
| `https://catproxy.lilifamily.com/health` 从管理 IP/Tailscale 访问 | `200` |
| `https://catproxy.lilifamily.com/health` 从普通公网访问 | `403``444` |
| `https://origin.proxy.api.lilifamily.com/health` 从非白名单来源访问 | `403` 或连接被拒绝 |
| `https://origin.proxy.api.lilifamily.com/health` 从 JPpro 访问 | `200` |
| `POST /v1/responses` 无授权访问 | `401 API_KEY_REQUIRED` |
| 证书剩余天数 | 小于 15 天告警 |
| nginx 服务状态 | 非 active 告警 |
可以用 Uptime Kuma或先用 cron + webhook。
#### 风险
- 只监控 `/health` 不足以发现 API 路由问题。
- 从本机监控 origin 可能因为 IP 白名单而得到 403这是预期不是故障。
#### 缓解
- 同时监控 `/health` 和未授权 API 路由。
- origin 监控要从 JPpro 节点执行。
### 4.7 日志可观测
#### 作用
响应慢时要知道慢在哪里。
关键区分:
| 字段 | 含义 |
|---|---|
| `request_time` | 当前 nginx 从接收请求到响应完成的总耗时 |
| `upstream_response_time` | 当前 nginx 等上游响应的耗时 |
| `upstream_status` | 上游返回状态,例如 200、401、502、504 |
| `X-Proxy-Ng-Node` | 哪个 proxy-ng 节点处理了请求 |
| `request_id` | 一次请求的追踪 ID |
#### 实施方案
JPpro 和 3c4g origin 都建议增加专用 log format
```nginx
log_format proxy_ng '$remote_addr "$request" status=$status '
'request_time=$request_time '
'upstream_status=$upstream_status '
'upstream_time=$upstream_response_time '
'node=$sent_http_x_proxy_ng_node '
'request_id=$request_id';
access_log /var/log/nginx/proxy-ng-access.log proxy_ng;
```
#### 风险
- access log 过大导致磁盘占满。
#### 缓解
- 配置 logrotate。
- 稳定后可只保留错误日志和采样日志。
### 4.8 无 Cloudflare LB 的防攻击方案
#### 作用
不依赖 Cloudflare LB 后,公网攻击会直接打到 proxy-ng 节点。防攻击目标不是承诺抗大规模 DDoS而是降低常见扫描、CC、小流量洪泛、慢连接和暴力破解对服务的影响并保证攻击不会绕过 proxy-ng 打到 3c4g 主站。
API 网关类服务常见风险:
- 大量并发连接。
- 大请求体。
- 慢速上传。
- 登录和验证码接口被刷。
- 流式响应占用长连接。
- 路径扫描,例如 `/.env``/.git``/wp-login.php`
- 直接扫描 3c4g IP、`catproxy``origin`
#### 实施方案
第一层proxy-ng 节点系统防火墙。
```text
入站允许:
- 80/tcp、443/tcp公网用户访问 proxy-ng
- 22/tcp只允许管理 IP 或 Tailscale/内网管理入口
入站拒绝:
- 其它所有端口
- 1080、7890、mixed、socks、xray、sing-box 等出口代理端口
```
第二层proxy-ng 节点 nginx 基础抗压。
```nginx
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
reset_timedout_connection on;
keepalive_timeout 20s;
keepalive_requests 100;
client_header_timeout 10s;
client_body_timeout 30s;
send_timeout 30s;
client_max_body_size 100m;
client_body_buffer_size 256k;
large_client_header_buffers 4 16k;
limit_conn_zone $binary_remote_addr zone=conn_per_ip:20m;
limit_req_zone $binary_remote_addr zone=req_per_ip:20m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth_per_ip:10m rate=10r/m;
}
```
第三层proxy-ng 节点 nginx 路由限流。
```nginx
location ~ /\.(git|svn|hg|env|aws|ssh) {
return 444;
}
location ~* ^/(wp-admin|wp-login\.php|phpmyadmin|cgi-bin|vendor|boaform) {
return 444;
}
location / {
limit_req zone=req_per_ip burst=30 nodelay;
limit_conn conn_per_ip 50;
proxy_pass https://origin.proxy.api.lilifamily.com;
}
location ~ ^/api/v1/auth/(login|login/2fa|register|send-verify-code|forgot-password|reset-password) {
limit_req zone=auth_per_ip burst=3 nodelay;
limit_conn conn_per_ip 10;
proxy_pass https://origin.proxy.api.lilifamily.com;
}
```
第四层3c4g origin 防绕过。
```text
3c4g 防火墙:
- 只允许 proxy-ng 节点 IP 访问 origin 入口端口
- 只允许管理 IP 或 Tailscale 访问 SSH
- Sub2API 8080 只监听 127.0.0.1 或 Docker 内网,不直接暴露公网
3c4g nginx
- origin server 只 allow proxy-ng 节点 IP
- 必须校验 X-Proxy-Ng-Token
- default_server 对未知 Host 返回 444
- catproxy 入口只用于受限直连/回滚,不作为公开业务入口
```
第五层fail2ban 和日志轮转。
```text
fail2ban 建议规则:
- nginx-404短时间大量 404/444 扫描封禁
- nginx-limit-req短时间大量 429 封禁
- sshdSSH 暴力破解封禁
logrotate
- nginx access/error 日志按大小轮转
- 保留 3-7 份
- 防止攻击流量把磁盘写满
```
第六层Sub2API 成本保护。
```text
- API Key 配额和余额限制
- 单 key 并发限制
- 单 key 速率限制
- 异常 401/429/5xx 告警
- 高额模型调用成本预警
```
#### 风险
- 这些措施不能替代专业 DDoS 清洗;大流量打满 VPS 带宽时仍会不可用。
- 太严格会误伤正常 API 客户端。
- 流式响应连接时间长,连接数限制过低会误伤。
- 多 A 普通 DNS 没有健康摘除;坏节点仍可能被解析到。
#### 缓解
- 先在 JPpro 测试入口启用。
- 观察 429 和连接拒绝日志后再调参。
-`/v1/responses` 等长连接路径不要过度收紧。
- `proxy.api.lilifamily.com` TTL 设低,例如 60-300 秒,故障时手工删除坏节点 A 记录。
- 保留至少一个受限直连回滚入口,但不公开给普通用户。
### 4.9 备份和回滚
#### 作用
proxy-ng 节点无业务数据,真正不能丢的是 3c4g 的数据库、Redis、Sub2API 数据目录和运行配置。
入口改造前必须有回滚方案,否则一次 nginx 配置错误可能导致入口不可用。
#### 实施方案
改动前备份:
```text
3c4g:
- /etc/nginx/sites-available/sub2api.conf
- /etc/nginx/sites-enabled/sub2api.conf
- /opt/sub2api/docker-compose.yml
- /opt/sub2api/.env
- PostgreSQL dump
- /opt/sub2api/data
JPpro:
- /etc/nginx/sites-available/jp-proxy-sub2api.conf
- /etc/nginx/conf.d/proxy-ng-map.conf
```
回滚路径:
| 故障 | 回滚方式 |
|---|---|
| origin 配置失败 | JPpro `proxy_pass` 改回 `https://catproxy.lilifamily.com` |
| token 校验误拦截 | 临时关闭 origin token 校验,恢复后重新加固 |
| IP 白名单误拦截 | 修正 `allow` 节点 IP 或临时回滚到公网主入口 |
| JPpro 故障 | 用户切回 `https://catproxy.lilifamily.com` |
| 3c4g 服务异常 | 使用 3c4g 备份和 Docker Compose 回滚 |
### 4.10 多节点扩展
#### 作用
多节点用于提升入口稳定性,但不是简单“节点越多越好”。
不使用 Cloudflare LB 时,多 A 记录会把用户随机分配到节点。某个节点故障后DNS 仍可能返回坏 IP表现为部分用户随机失败。
#### 实施方案
新增节点标准流程:
```text
1. 新建 ops/remote/<server>-sub2api/
2. 安装 nginx + certbot
3. 配置 proxy-ng node id
4. 回源 origin.proxy.api.lilifamily.com
5. 3c4g origin allow 新节点 IP
6. 给新节点配置 token
7. 验证 /health、/、/v1/responses
8. 加入 `proxy.api.lilifamily.com` 多 A 记录
```
DNS 策略:
| 阶段 | 方案 | 风险 |
|---|---|---|
| P0 | 单节点入口 | 简单,但节点故障需手工切换 |
| P1 | `proxy.api.lilifamily.com` 多 A 记录TTL 60-300 秒 | 成本低,但坏节点不会自动摘除 |
| P2 | 自建监控 + 手工或脚本更新 DNS | 不依赖 Cloudflare LB但需要自己处理摘除 |
当前确认不采用 Cloudflare Load Balancing因此方案不承诺按用户网络质量或节点健康自动调度。节点健康只能通过监控告警后手工移除 DNS 记录,或后续自建 DNS 更新脚本实现。
## 5. 推荐实施顺序
### 阶段 0主站隐藏和入口域名迁移基线
先把公开入口和 3c4g 直连入口拆开,避免 proxy-ng 节点或公开 DNS 暴露主站。
动作:
1. `proxy.api.lilifamily.com` 从 3c4g 移走,改为 A 到 proxy-ng 节点,例如 JPpro。
2. DNS 增加或确认 `catproxy.lilifamily.com -> 216.45.59.243`,但它只作为受限直连、管理和回滚入口。
3. 3c4g nginx 为 `catproxy.lilifamily.com` 签发证书,但访问限制为管理 IP、Tailscale 或临时回滚窗口。
4. Sub2API 对外公开域名应保持为用户访问入口 `proxy.api.lilifamily.com`,避免页面、回调或错误信息暴露 `catproxy.lilifamily.com`
5. JPpro 临时回源可用 `https://catproxy.lilifamily.com`,但只作为切 origin 前的过渡。
目标基线链路:
```text
proxy.api.lilifamily.com -> JPpro/proxy-ng -> catproxy.lilifamily.com(临时) -> 3c4g -> Sub2API
```
验收:
- `proxy.api.lilifamily.com/health` 返回 200且解析到 proxy-ng 节点 IP。
- `jp.proxy.api.lilifamily.com/health` 返回 200。
- `jp.proxy.api.lilifamily.com/` 返回 200。
- 普通公网访问 `catproxy.lilifamily.com` 被拒绝,或仅在明确回滚窗口内允许。
- 未授权 `POST /v1/responses` 返回 401。
### 阶段 13c4g 增加 origin
动作:
1. DNS 增加 `origin.proxy.api.lilifamily.com -> 216.45.59.243`
2. 3c4g nginx 新增 origin server block。
3. certbot 为 origin 域名签发证书。
4. 暂不切 JPpro先验证 origin 本身。
验收:
- 从 3c4g 本机访问 `127.0.0.1:8080/health` 正常。
- 从 JPpro 访问 `https://origin.proxy.api.lilifamily.com/health` 正常。
- 从非白名单来源访问 origin 被拒绝。
### 阶段 2origin 加 IP 白名单和 token
动作:
1. 3c4g origin 允许 JPpro IP `151.242.164.72`
2. 3c4g origin 配置 `X-Proxy-Ng-Token` 校验。
3. JPpro 配置注入 token。
4. token 真实值只保存在远程 root-only 配置。
验收:
- JPpro 带 token 访问 origin 返回 200。
- JPpro 不带 token 访问 origin 返回 403。
- 非 JPpro IP 访问 origin 返回 403 或连接拒绝。
- origin 不把 `X-Proxy-Ng-Token` 继续传给 Sub2API。
### 阶段 3JPpro 切换 origin 回源
动作:
1. 备份 JPpro 当前 nginx 配置。
2. JPpro `proxy_pass``https://catproxy.lilifamily.com` 改为 `https://origin.proxy.api.lilifamily.com`
3. `nginx -t` 后 reload。
4. 公网验证 JPpro 入口。
验收:
- `https://jp.proxy.api.lilifamily.com/health` 返回 200。
- `https://jp.proxy.api.lilifamily.com/` 返回 200。
- 未授权 `POST /v1/responses` 返回 401。
- 3c4g origin access log 能看到 `X-Proxy-Ng-Node=jppro-akile-0504-1c1g`
### 阶段 4完善监控、日志、限流
动作:
1. 增加 proxy-ng 专用 access log。
2. 配置证书到期检查。
3. 配置 JPpro 和 3c4g 健康检查。
4. 先在 JPpro 入口启用保守限流、连接数限制和扫描路径拦截。
5. 配置 fail2ban 和 logrotate。
6. 3c4g 防火墙确认只允许 proxy-ng 节点访问 origin。
验收:
- 能通过日志区分 JPpro 耗时和 3c4g origin 耗时。
- 证书剩余天数低于阈值能告警。
- 429 数量可观测,不误伤正常请求。
- 访问 `/.env``/.git/config``/wp-login.php` 等扫描路径返回 444 或 403。
- 3c4g `8080` 不对公网开放。
### 阶段 5评估是否增加第二个 proxy-ng 节点
动作:
1. 选择第二台节点。
2. 按同样目录规范留痕。
3. 先不进正式 DNS`--resolve` 验证。
4. 通过 `--resolve proxy.api.lilifamily.com:443:<节点IP>` 逐个验证。
5. 验证通过后加入 `proxy.api.lilifamily.com` 多 A 记录。
验收:
- 第二节点独立验证通过。
- origin allowlist 已补第二节点 IP。
- 节点配置副本已保存到项目 `ops/remote/<server>-sub2api/`
- `proxy.api.lilifamily.com` 的多 A 记录不包含 3c4g IP。
## 6. 配置草案
### 6.1 3c4g origin nginx 草案
```nginx
map $http_x_proxy_ng_token $proxy_ng_token_ok {
default 0;
"REDACTED_SECRET" 1;
}
map $http_x_forwarded_host $sub2api_host {
default $http_x_forwarded_host;
"" "proxy.api.lilifamily.com";
}
server {
server_name origin.proxy.api.lilifamily.com;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/origin.proxy.api.lilifamily.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/origin.proxy.api.lilifamily.com/privkey.pem;
server_tokens off;
underscores_in_headers on;
client_max_body_size 100m;
location / {
allow 151.242.164.72;
deny all;
if ($proxy_ng_token_ok = 0) {
return 403;
}
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $sub2api_host;
proxy_set_header X-Real-IP $http_x_real_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
proxy_set_header X-Proxy-Ng-Token "";
proxy_set_header X-Proxy-Ng-Node $http_x_proxy_ng_node;
proxy_redirect https://origin.proxy.api.lilifamily.com/ https://$sub2api_host/;
proxy_redirect https://catproxy.lilifamily.com/ https://$sub2api_host/;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_request_buffering off;
}
}
```
待审阅点:`X-Real-IP``X-Forwarded-For` 是否按第一阶段“不可伪造优先”处理,还是按“保留真实客户端 IP 链路”处理。当前草案偏向保留链路,但需要结合 Sub2API 的 `trusted_proxies` 配置验证。
### 6.2 JPpro nginx 草案
```nginx
server {
server_name proxy.api.lilifamily.com jp.proxy.api.lilifamily.com;
server_tokens off;
underscores_in_headers on;
client_max_body_size 100m;
add_header X-Proxy-Ng-Node "jppro-akile-0504-1c1g" always;
location / {
proxy_pass https://origin.proxy.api.lilifamily.com;
proxy_ssl_server_name on;
proxy_ssl_name origin.proxy.api.lilifamily.com;
proxy_http_version 1.1;
proxy_set_header Host origin.proxy.api.lilifamily.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Proxy-Ng-Node "jppro-akile-0504-1c1g";
proxy_set_header X-Proxy-Ng-Token "REDACTED_SECRET";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_request_buffering off;
}
}
```
待审阅点:当前 JPpro 配置已有 `client_max_body_size 256m`,草案写 `100m` 是为了和 3c4g 主入口一致。是否保留 `256m` 需要根据实际请求体规模确认。
### 6.3 3c4g catproxy 受限直连草案
`catproxy.lilifamily.com` 不作为常规用户入口。它的作用是运维验证和紧急回滚,因此默认应限制来源。
```nginx
server {
server_name catproxy.lilifamily.com;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/catproxy.lilifamily.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/catproxy.lilifamily.com/privkey.pem;
server_tokens off;
underscores_in_headers on;
client_max_body_size 100m;
# 管理 IP、Tailscale 出口或临时回滚窗口内的来源。
allow <ADMIN_OR_TAILSCALE_IP>;
deny all;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host proxy.api.lilifamily.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host proxy.api.lilifamily.com;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_request_buffering off;
}
}
server {
listen 443 ssl default_server;
server_name _;
return 444;
}
```
如果管理 IP 不固定,优先使用 Tailscale、SSH 隧道或临时开放窗口,不建议长期把 `catproxy.lilifamily.com` 暴露给公网。
## 7. 验收清单
### 7.1 基础链路
- [ ] `https://proxy.api.lilifamily.com/health` 返回 200且 DNS 解析结果只包含 proxy-ng 节点 IP。
- [ ] 从管理 IP/Tailscale 访问 `https://catproxy.lilifamily.com/health` 返回 200。
- [ ] `https://jp.proxy.api.lilifamily.com/health` 返回 200。
- [ ] `https://jp.proxy.api.lilifamily.com/` 返回 200。
- [ ] 未授权 `POST https://jp.proxy.api.lilifamily.com/v1/responses` 返回 `401 API_KEY_REQUIRED`
- [ ] 普通公网访问 `https://catproxy.lilifamily.com/` 返回 403/444除非处于明确回滚窗口。
### 7.2 origin 边界
- [ ] JPpro 带 token 访问 `https://origin.proxy.api.lilifamily.com/health` 返回 200。
- [ ] JPpro 不带 token 访问 origin 返回 403。
- [ ] 非 JPpro IP 访问 origin 返回 403 或连接被拒绝。
- [ ] origin 日志能看到 `X-Proxy-Ng-Node`
- [ ] origin 不把 `X-Proxy-Ng-Token` 继续传给 Sub2API。
### 7.3 回滚验证
- [ ] JPpro 配置可一条改回 `proxy_pass https://catproxy.lilifamily.com`
- [ ] 3c4g 受限入口 `catproxy.lilifamily.com` 对管理 IP/Tailscale 可访问,对普通公网不可访问。
- [ ] 远程配置备份路径已记录。
### 7.4 运维验证
- [ ] `nginx -t` 通过。
- [ ] `systemctl is-active nginx` 返回 `active`
- [ ] 证书到期时间已记录。
- [ ] 访问日志可区分 `request_time``upstream_response_time`
- [ ] 限流启用后没有误伤正常 API 请求。
- [ ] `/.env``/.git/config``/wp-login.php` 等扫描路径返回 444/403。
- [ ] fail2ban 对高频 404/429 和 SSH 爆破生效。
- [ ] logrotate 已限制 nginx 日志增长。
- [ ] `proxy.api.lilifamily.com` 的任一 A 记录故障时,有手工摘除流程。
## 8. 风险和取舍
| 风险 | 严重性 | 原因 | 缓解 |
|---|---|---|---|
| origin 配置错误导致 JPpro 入口不可用 | 高 | JPpro 切到 origin 后依赖新链路 | 先验证 origin再切 JPpro保留回滚 |
| IP 白名单误配 | 高 | 节点 IP 写错或 VPS 换 IP | 操作前核对公网 IP变更留痕 |
| token 泄露 | 中 | nginx 远程配置含明文 token | 权限 `600`;仓库只保存脱敏副本 |
| 真实客户端 IP 丢失 | 中 | 为防伪造而覆盖 `X-Forwarded-For` | 明确第一阶段优先级;后续再做可信 IP 链路 |
| 限流误伤正常请求 | 中 | API 客户端并发高、流式请求长 | 先保守配置并观察日志 |
| 大流量 DDoS 打满 proxy-ng 带宽 | 高 | 不使用 Cloudflare LB/清洗时,攻击流量直达 VPS | 接受该边界;多节点分散;必要时换高防/CDN |
| `catproxy` 被公网发现并直接访问 | 高 | 3c4g 直连入口暴露会绕过 proxy-ng | 默认 deny all仅管理 IP/Tailscale/临时回滚允许 |
| 多 A 记录随机命中坏节点 | 中 | 普通 DNS 无健康检查 | TTL 60-300 秒;监控告警后手工摘除坏 A 记录 |
| 日志占满磁盘 | 低 | access log 增多 | 配置 logrotate 或采样 |
## 9. 待确认项
- [x] 公开服务入口采用 `proxy.api.lilifamily.com`,但只解析到 proxy-ng 节点。
- [x] `catproxy.lilifamily.com` 作为 3c4g 受限直连、管理和紧急回滚入口。
- [x] origin 回源入口采用 `origin.proxy.api.lilifamily.com`
- [x] proxy-ng 节点统一使用 `<node>.proxy.api.lilifamily.com` 命名。
- [x] 不依赖 Cloudflare Load Balancing`proxy.api.lilifamily.com` 使用普通 A 记录指向 proxy-ng 节点。
- [ ] `catproxy.lilifamily.com` 的长期访问策略:仅 Tailscale/管理 IP还是完全不开放公网。
- [ ] JPpro 到 origin 是否继续使用 443还是改用 origin 专用端口。
- [ ] 第一阶段是否优先保证 `X-Forwarded-For` 不可伪造,接受真实客户端 IP 链路暂时简化。
- [ ] token 采用单 token 还是一开始就做双 token 轮换。
- [ ] 是否立即启用限流、fail2ban、扫描路径 444还是先只增强 origin 安全边界。
- [ ] 监控使用 Uptime Kuma、cron + webhook还是暂时手工巡检。
- [ ] 下一台 proxy-ng 节点是否已经确定。
## 10. 下一步
建议先审阅并确认以下决策:
1. origin 域名和是否使用 443。
2. JPpro 回源切换窗口和回滚策略。
3. `X-Forwarded-For` 第一阶段处理策略。
4. token 保存位置和轮换方式。
确认后再输出执行版文档,执行版应包含:
- 远程配置文件路径。
- 备份命令。
- 变更步骤。
- 验证命令。
- 回滚命令。
- 本地 `ops/remote/` 留痕更新清单。