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.
10 KiB
10 KiB
国际互联网络优化 — 执行版
日期:2026-05-21 | 前置:审阅版已通过
1. 目标与范围
在 1C/1G 轻量 VPS 上部署 nginx 反向代理,通过 Cloudflare CDN 实现中国 IP 白名单访问控制,将流量转发到后端 2C4G 高性能服务器的 sub2api 服务。
2. 前置假设
- 轻量 VPS 已就绪,OS Debian/Ubuntu,有公网 IP,已配置 SSH 密钥登录
- 高性能服务器已部署 sub2api(Docker Compose),监听 8080,
config.yaml可编辑 - 域名
proxyapi.cyan2000.uk的 NS 管理权限在手 - 两台 VPS 之间通过公网 IP 通信(无内网)
- 目标用户全部在中国大陆(+ 酌情香港/澳门)
- Cloudflare 免费计划账户已注册
3. 涉及文件与路径
轻量 VPS(新部署)
| 路径 | 操作 | 说明 |
|---|---|---|
/etc/nginx/nginx.conf |
写入 | 主配置,定义 upstream、限流区域 |
/etc/nginx/ssl/fullchain.pem |
certbot 签发 | Let's Encrypt 证书 |
/etc/nginx/ssl/privkey.pem |
certbot 签发 | 私钥 |
/etc/systemd/system/nginx.service.d/override.conf |
创建 | MemoryMax + Restart |
/etc/fail2ban/jail.local |
写入 | nginx-404 + nginx-limit-req 规则 |
/etc/fail2ban/filter.d/nginx-404.conf |
写入 | 404 扫描过滤 |
/usr/local/bin/nginx-defense.sh |
创建 | 内存压力自动降级 |
/usr/local/bin/cf-iptables.sh |
创建 | CF IP 白名单更新 |
/usr/local/bin/rebuild-nginx.sh |
创建 | 一键重建 |
/etc/cron.d/cf-iptables |
写入 | 每日 3:00 执行 |
/etc/cron.d/nginx-defense |
写入 | 每分钟执行 |
高性能服务器(配置变更)
| 路径 | 操作 | 说明 |
|---|---|---|
config.yaml |
编辑 | server.trusted_proxies 加 nginx IP |
config.yaml |
编辑(条件) | security.trust_forwarded_ip_for_api_key_acl: true |
/etc/ssl/private/sub2api-key.pem |
生成 | 回源自签证书私钥 |
/etc/ssl/certs/sub2api-cert.pem |
生成 | 回源自签证书 |
docker-compose.yml |
编辑(可选) | nginx sidecar 做 TLS 终止 |
4. 数据流与依赖
用户浏览器
│ HTTPS 443 (Let's Encrypt)
▼
Cloudflare CDN
│ 加头: CF-Connecting-IP, CF-IPCountry
│ HTTPS 443 (Let's Encrypt)
▼
轻量VPS nginx (1C/1G)
│ iptables: 仅接受 CF IP 段
│ nginx: CF-IPCountry 非 CN → 403
│ 加头: X-Real-IP, X-Forwarded-For
│ HTTPS 8443 (自签证书)
▼
后端 nginx sidecar (TLS 终止)
│ HTTP :8080
▼
sub2api (Gin)
│ ip.GetClientIP() → CF-Connecting-IP → X-Real-IP → X-Forwarded-For
▼
PostgreSQL / Redis
依赖:
- 轻量 VPS → 后端公网 IP 可达(防火墙允许 8080 或 8443)
- 后端 → Redis / PostgreSQL(已有)
- 轻量 VPS → cloudflare.com(cron 拉取 IP 段)
5. 接口契约与字段变化
sub2api 配置变化
# config.yaml 新增
server:
trusted_proxies:
- "<轻量VPS公网IP>"
- "173.245.48.0/20" # Cloudflare IP 段(如需)
# ... 或信任所有 CF IP 段
# 如果启用了 API Key IP 白名单功能
security:
trust_forwarded_ip_for_api_key_acl: true
nginx 向下游传递的头
| 头名称 | 值来源 | 用途 |
|---|---|---|
X-Real-IP |
$remote_addr(CF 边缘 IP) |
传统兼容 |
X-Forwarded-For |
$proxy_add_x_forwarded_for |
代理链 |
X-Forwarded-Proto |
$scheme(https) |
协议感知 |
CF-Connecting-IP |
$http_cf_connecting_ip(CF 原始头) |
sub2api 优先读取 |
Host |
$host(proxyapi.cyan2000.uk) |
虚拟主机 |
sub2api IP 解析优先级(ip.go 已有,不变)
CF-Connecting-IP → X-Real-IP → X-Forwarded-For(第一个公网IP) → c.ClientIP()
c.ClientIP()(限流器使用)仅在 trusted_proxies 含来源 IP 时才信任转发头。必须配置。
6. 边界情况与失败路径
| 场景 | 预期行为 |
|---|---|
| 用户绕过 CF 直连源站 IP | iptables DROP,连接超时 |
| 用户通过 CF 但伪造 CF-IPCountry 头 | CF 会覆盖此头或剥离,nginx 看到空 → 403 |
| 用户通过 CF 但来自非中国 IP | CF WAF Block(第一层),nginx $http_cf_ipcountry != CN → 403(第二层) |
| CF IP 段更新,iptables 未同步 | 受影响的新 CF IP 回源被 DROP,用户看到 502;每日 cron 最小化窗口 |
| 轻量 VPS OOM | systemd MemoryMax=800M 杀 nginx 而非全机 OOM;Restart=always 5s 恢复 |
| 轻量 VPS 彻底宕机 | 备机 DNS 切换;或一键重建脚本 |
| 后端 502/504 | nginx 返回 502 给用户;proxy_next_upstream error timeout http_502 有限重试 |
sub2api trusted_proxies 未配 |
限流器把所有用户视为同一 IP(nginx IP),共享限流桶 |
| CF-Connecting-IP 传递失败(nginx 没透传) | sub2api 回退到 X-Forwarded-For 解析,仍能拿到真实 IP |
| Let's Encrypt 证书过期 | certbot renew 自动续期;需确保 80 端口可访问用于验证 |
| 前端磁盘满 | access_log 生产环境关掉;error_log logrotate maxsize 50M |
7. 实施步骤
第一阶段:后端配置(零中断)
- 登录高性能服务器
- 确认
config.yaml路径,备份后编辑:server: trusted_proxies: - "<轻量VPS公网IP>" - 生成自签证书:
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout /etc/ssl/private/sub2api-key.pem \ -out /etc/ssl/certs/sub2api-cert.pem \ -subj "/CN=<后端公网IP>" - 在
docker-compose.yml中添加 nginx sidecar 做 TLS 终止(监听 8443 → 转发 8080),或直接用 sub2api 的 HTTPS 配置 - 重启 sub2api / Docker Compose
- 验证:
curl --noproxy '*' -k https://<后端公网IP>:8443/health返回 200
第二阶段:Cloudflare DNS(可能中断 1-2 分钟)
- 在 Cloudflare 添加站点
proxyapi.cyan2000.uk - 将域名 NS 改为 Cloudflare 分配的 NS
- 等 NS 生效后,添加 DNS 记录:A
@→ 轻量 VPS 公网 IP,橙色云朵开启 - SSL/TLS 模式设为 Full (strict)
- WAF 规则:
(ip.geoip.country eq "CN")→ Allow,新建规则 - 验证:
curl -H "Host: proxyapi.cyan2000.uk" https://<轻量VPS_IP>/health --resolve proxyapi.cyan2000.uk:443:<轻量VPS_IP>— 此时 nginx 还没配,先确认 CF 能到 VPS
第三阶段:轻量 VPS 部署
按顺序执行:
# 1. 基础软件
apt update && apt install -y nginx certbot fail2ban iptables-persistent
# 2. 获取证书(先关 nginx 80/443,或 certbot standalone 模式)
certbot certonly --standalone -d proxyapi.cyan2000.uk
# 3. 写入 /etc/nginx/nginx.conf(见附录 A)
# 4. 写入 systemd override(见附录 B)
mkdir -p /etc/systemd/system/nginx.service.d
# 5. 写入 fail2ban 配置(见附录 C)
# 6. 写入脚本(见附录 D)
# - /usr/local/bin/cf-iptables.sh
# - /usr/local/bin/nginx-defense.sh
# - /usr/local/bin/rebuild-nginx.sh
# 7. 执行 iptables 白名单(先 accept 所有,确认 nginx 正常后再启用 DROP)
bash /usr/local/bin/cf-iptables.sh
# 8. cron
echo "0 3 * * * root /usr/local/bin/cf-iptables.sh" > /etc/cron.d/cf-iptables
echo "* * * * * root /usr/local/bin/nginx-defense.sh" > /etc/cron.d/nginx-defense
# 9. 关闭 access_log(生产环境)
# 编辑 nginx.conf: access_log off;
# 或保留但 logrotate: maxsize 50M rotate 3
# 10. 启动
systemctl daemon-reload
systemctl enable --now nginx fail2ban
第四阶段:端到端验证
见第 8 节验证清单。
8. 测试与验证
自动化测试
# 1. 基本连通性
curl -I https://proxyapi.cyan2000.uk/health
# 预期: 200 OK
# 2. 中国 IP 访问控制 (CF-IPCountry 头)
curl -I https://proxyapi.cyan2000.uk/ -H "CF-IPCountry: CN"
# 预期: 正常转发,非 403
curl -I https://proxyapi.cyan2000.uk/ -H "CF-IPCountry: US"
# 预期: 403 Forbidden
curl -I https://proxyapi.cyan2000.uk/
# 预期: 403 (CF-IPCountry 为空 = 直连)
# 3. 压力测试 — 限流
ab -n 200 -c 50 https://proxyapi.cyan2000.uk/health
# 预期: 部分请求返回 429 / 503
# 4. Slowloris 抗性
slowhttptest -c 50 -H -u https://proxyapi.cyan2000.uk/
# 预期: 连接不耗尽,正常请求仍能响应
# 5. 源站 IP 直连
curl -I --connect-timeout 5 https://<轻量VPS_IP>/
# 预期: 超时或被拒绝 (iptables DROP)
# 6. 限流验证 — 真实 IP
for i in $(seq 1 35); do
curl -s -o /dev/null -w "%{http_code}\n" https://proxyapi.cyan2000.uk/auth/login
done
# 预期: 前 20 个 200/401,后续 429
验证清单
curl https://proxyapi.cyan2000.uk/health→ 200- CF 关闭橙色云朵(直连 VPS)→
CF-IPCountry为空 → 403 CF-IPCountry: US→ 403CF-IPCountry: CN→ 正常转发- sub2api 访问日志
client_ip= 真实用户 IP(查看日志验证) - auth 限流:同 IP 超频返回 429,不同 IP 独立计数
- 流式 API SSE 逐块到达
- 源站 IP 直连超时
ab压测限流生效slowhttptest连接不耗尽fail2ban-client status正常systemctl show nginx | grep Restart→Restart=alwayssystemctl show nginx | grep MemoryMax→MemoryMax=838860800- nginx error_log 无异常
9. 回滚 / 降级
快速回滚 DNS
- Cloudflare DNS 关闭 A 记录橙色云朵(变灰色 = DNS only)
- 或将 A 记录直接指向后端服务器 IP(绕过轻量 VPS)
回滚 sub2api 配置
# 注释掉 trusted_proxies 行,恢复原状
# 重启 sub2api
docker compose restart
轻量 VPS 紧急降级
如果 nginx 出现异常但 iptables 正常:
# 紧急放行所有流量
iptables -F CF-WHITELIST
iptables -A CF-WHITELIST -j ACCEPT
# 重启 nginx
systemctl restart nginx
附录 A:nginx 主配置
见 NETWORK_OPTIMIZATION.md 3.2 节完整配置。
附录 B:systemd override
# /etc/systemd/system/nginx.service.d/override.conf
[Service]
Restart=always
RestartSec=5s
OOMScoreAdjust=-500
MemoryMax=800M
MemoryHigh=700M
附录 C:fail2ban 配置
# /etc/fail2ban/jail.local
[nginx-404]
enabled = true
port = http,https
filter = nginx-404
logpath = /var/log/nginx/access.log
maxretry = 30
findtime = 60
bantime = 600
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 60
bantime = 600
# /etc/fail2ban/filter.d/nginx-404.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*" 404
ignoreregex =
附录 D:脚本
见 NETWORK_OPTIMIZATION.md 3.4 节:
cf-iptables.sh— CF IP 白名单(含 IPv6)nginx-defense.sh— 内存压力自动降级rebuild-nginx.sh— 一键重建