# 国际互联网络优化 — 执行版 日期: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 配置变化 ```yaml # 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. 实施步骤 ### 第一阶段:后端配置(零中断) 1. 登录高性能服务器 2. 确认 `config.yaml` 路径,备份后编辑: ```yaml server: trusted_proxies: - "<轻量VPS公网IP>" ``` 3. 生成自签证书: ```bash 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>" ``` 4. 在 `docker-compose.yml` 中添加 nginx sidecar 做 TLS 终止(监听 8443 → 转发 8080),或直接用 sub2api 的 HTTPS 配置 5. 重启 sub2api / Docker Compose 6. 验证:`curl --noproxy '*' -k https://<后端公网IP>:8443/health` 返回 200 ### 第二阶段:Cloudflare DNS(可能中断 1-2 分钟) 1. 在 Cloudflare 添加站点 `proxyapi.cyan2000.uk` 2. 将域名 NS 改为 Cloudflare 分配的 NS 3. 等 NS 生效后,添加 DNS 记录:A `@` → 轻量 VPS 公网 IP,橙色云朵开启 4. SSL/TLS 模式设为 Full (strict) 5. WAF 规则:`(ip.geoip.country eq "CN")` → Allow,新建规则 6. 验证:`curl -H "Host: proxyapi.cyan2000.uk" https://<轻量VPS_IP>/health --resolve proxyapi.cyan2000.uk:443:<轻量VPS_IP>` — 此时 nginx 还没配,先确认 CF 能到 VPS ### 第三阶段:轻量 VPS 部署 按顺序执行: ```bash # 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. 测试与验证 ### 自动化测试 ```bash # 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` → 403 - [ ] `CF-IPCountry: CN` → 正常转发 - [ ] sub2api 访问日志 `client_ip` = 真实用户 IP(查看日志验证) - [ ] auth 限流:同 IP 超频返回 429,不同 IP 独立计数 - [ ] 流式 API SSE 逐块到达 - [ ] 源站 IP 直连超时 - [ ] `ab` 压测限流生效 - [ ] `slowhttptest` 连接不耗尽 - [ ] `fail2ban-client status` 正常 - [ ] `systemctl show nginx | grep Restart` → `Restart=always` - [ ] `systemctl show nginx | grep MemoryMax` → `MemoryMax=838860800` - [ ] nginx error_log 无异常 ## 9. 回滚 / 降级 ### 快速回滚 DNS 1. Cloudflare DNS 关闭 A 记录橙色云朵(变灰色 = DNS only) 2. 或将 A 记录直接指向后端服务器 IP(绕过轻量 VPS) ### 回滚 sub2api 配置 ```bash # 注释掉 trusted_proxies 行,恢复原状 # 重启 sub2api docker compose restart ``` ### 轻量 VPS 紧急降级 如果 nginx 出现异常但 iptables 正常: ```bash # 紧急放行所有流量 iptables -F CF-WHITELIST iptables -A CF-WHITELIST -j ACCEPT # 重启 nginx systemctl restart nginx ``` --- ## 附录 A:nginx 主配置 见 `NETWORK_OPTIMIZATION.md` 3.2 节完整配置。 ## 附录 B:systemd override ```ini # /etc/systemd/system/nginx.service.d/override.conf [Service] Restart=always RestartSec=5s OOMScoreAdjust=-500 MemoryMax=800M MemoryHigh=700M ``` ## 附录 C:fail2ban 配置 ```ini # /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 ``` ```ini # /etc/fail2ban/filter.d/nginx-404.conf [Definition] failregex = ^ -.*"(GET|POST|HEAD).*" 404 ignoreregex = ``` ## 附录 D:脚本 见 `NETWORK_OPTIMIZATION.md` 3.4 节: - `cf-iptables.sh` — CF IP 白名单(含 IPv6) - `nginx-defense.sh` — 内存压力自动降级 - `rebuild-nginx.sh` — 一键重建