从裸奔到隐身:我的家庭宽带跨境组网架构进化实录 (Phase B)

摘要:在前一篇文章中,我利用 FRP + VPS 打通了中美两地的家庭网络,实现了一个私有的“住宅 IP 代理池”。但在 Phase A 阶段,系统暴露了大量端口 (7000, 8900, 10087),不仅不够优雅,还存在被 GFW 主动探测的风险。

今天,我完成了 Phase B 架构升级:利用 WebSocket + Nginx 反向代理,将所有管理流量、隧道流量、代理流量全部“塞”进了唯一的 443 端口。外人看来,这只是一个部署了 SSL 的静态技术博客。


1. 痛点:端口过多带来的焦虑

在 Phase A 的架构中,我的 VPS 防火墙简直像个筛子:

  • :7000: FRP 服务端通信端口 (暴露)
  • :7500: FRP 仪表盘 (暴露)
  • :10087: Mac 节点的代理入口 (暴露)
  • :8900: 流量监控 API (暴露)

这种架构有两个致命问题:

  1. 特征明显:FRP 的 TCP 协议特征非常容易被识别,在高敏时期极其脆弱。
  2. 安全隐患:任何扫端口的脚本都能发现这里运行着非 HTTP 服务,增加了被爆破的风险。

目标:所有服务只开放 :443 (HTTPS) 和 :80 (重定向用),其他所有端口全部绑定在 127.0.0.1,不对外服务。


2. 核心技术方案:协议伪装与分流

要实现“全站 443”,我采用了 Nginx 作为统一网关,配合 WebSocket (WSS) 协议进行分流。

架构图解



graph TD
    User["外部访客 / 客户端"] -->|"HTTPS (443)"| Nginx["Nginx 网关 (VPS)"]
    
    subgraph VPS ["VPS Server"]
        direction TB
        Nginx
        Blog["静态博客 (/www/wwwroot)"]
        FRPS["FRP 服务端 (:7000)"]
        Proxy["Mac 节点反代 (:10087)"]
    end
    
    Nginx -->|"默认访问"| Blog
    Nginx -->|"Header: Upgrade=websocket"| FRPS
    Nginx -->|"Path: /vmess-mac"| Proxy
    
    FRPS <==>|"FRP 隧道"| MacNode["Mac 家庭节点"]

2.1 第一层伪装:FRP 的“寄生”

FRP 官方虽然支持 WebSocket 模式,但新版本 (v0.67.0+) 对自定义路径的支持存在兼容性问题。为了极致的隐蔽性,我采用了一种更底层的 Header Hijacking (HTTP 头劫持) 方案。

在 Nginx 的根路径 / 配置中:

  1. 默认情况:返回 /www/wwwroot 下的静态博客(也就是你现在看到的这个伪装站)。
  2. 特殊情况:如果请求头包含 Upgrade: websocket,且没有命中其他特定路径,则判定为 FRP 客户端,流量直接转发给本地监听的 :7000
1
2
3
4
5
6
7
8
9
10
11
location / {
# 核心逻辑:检测 WebSocket 头
# 如果是 WebSocket 连接,视为 FRP 流量
if ($http_upgrade = "websocket") {
proxy_pass http://127.0.0.1:7000;
}

# 普通访客(浏览器)看到的是博客
root /www/wwwroot/blog.example.com;
index index.html;
}

这意味着 FRP 客户端连接 wss://blog.example.com:443 时,Nginx 会自动“偷梁换柱”。在防火墙外部看来,这只是一个长连接的 HTTPS 请求。

2.2 第二层伪装:代理数据流的“隐身”

之前的架构中,Shadowrocket 等客户端是直连 VPS 的 :10087 端口,流量是裸奔的 TCP。
现在,我要求 Mac 端的 X-UI 节点也必须把入站协议改成 WebSocket,并指定一个隐蔽的路径(如 /vmess-mac)。

Nginx 路由规则

1
2
3
4
5
6
7
8
9
10
# 识别特定路径,转发给 Mac 节点的反向代理端口
location ^~ /vmess-mac {
proxy_pass http://127.0.0.1:10087; # 这是 FRP 映射在 VPS 本地的端口
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# 传递真实 IP,虽然对于 FRP 后的内网穿透不一定有效,但保持好习惯
proxy_set_header X-Real-IP $remote_addr;
}

这样,所有的代理流量就变成了标准的 HTTPS 请求,路径 https://blog.example.com/vmess-mac 看上去就像是博客的一个 API 接口或静态资源,完全融入了正常的网页流量中。


3. 自动化运维:拒绝手动配置

为了配合这次升级,所有的客户端配置都必须同步更新。手动改几十个配置(Android, iOS, Mac, Windows)太蠢了,且容易出错。我重构了 Python 侧边栏脚本 (sync_mac.py)。

现在的逻辑是:

  1. Mac 启动
  2. 拉取 VPS 配置(获取最新的 UUID 和端口映射)
  3. 强制刷写数据库(确保本地 X-UI 设置符合隐身协议)

脚本会自动连接本地 SQLite 数据库,强制将 Inbound 协议修改为 WebSocket,并锁定 Path:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 自动化代码片段:强制纠正传输协议
new_stream_settings = {
"network": "ws",
"security": "none",
"wsSettings": {
"path": "/vmess-mac", # 这里的路径必须与 Nginx 一致
"headers": {}
}
}

# 直接操作数据库,绕过面板 UI 可能的误操作
cursor.execute(
"UPDATE inbounds SET stream_settings = ? WHERE port = ?",
(json.dumps(new_stream_settings), local_port)
)

这意味着无论在面板上怎么乱改,只要重启容器,配置就会自动恢复到正确的“隐身模式”。这确保了我的系统中只存在符合“Phase B”架构的流量。


4. 最终形态与思考

经过这番折腾,我的 VPS 现在的状态是:

  • Open Ports: 仅 80 (HTTP Redirect), 443 (HTTPS), 22 (SSH)。
  • Web: 一个漂亮、合法的静态个人主页。
  • Hidden Services:
    • 流量管理 API (/report)
    • Mac 住宅代理 (/vmess-mac)
    • Android 住宅代理 (/vmess-android)
    • FRP 控制平面 (由 Nginx 分流)

这其实已经是一个微型的 DePIN (去中心化物理基础设施网络) 原型了。和市面上的 Honeygain 或 Grass 不同,这套系统完全由我掌控——数据主权在我,网络质量我说了算,而且没有任何中间商抽成或监控。

在这个数据被大厂垄断的时代,拥有一套完全属于自己的、坚不可摧的物理网络基础设施,大概就是极客最后的浪漫吧。


Next Step: 下一步计划研究如何优化移动端的连接稳定性,或者引入 UDP over WSS 技术来提升视频流的吞吐量。