NFD Proxy — 分布式代理节点系统
将用户设备注册为代理节点,通过 WebSocket 控制面实现 geo 感知分发的 SOCKS5 / HTTP 代理网络。
架构
用户 / Vert.x 后端
│ HTTP CONNECT :8888 (Proxy-Authorization: Basic)
│ SOCKS5 :1080 (用户名/密码子协商)
▼
proxy_server.py GeoIP 解析 → 同城→同省→默认→任意
│ WebSocket :9000/ws/node
▼
dnode_client.py 用户设备(真实出口 IP)
▼
目标服务器
组件
| 文件 | 说明 |
|------|------|
| proxy_server.py | 服务端:SOCKS5 + HTTP CONNECT 代理,WS 节点注册,Admin API,控制面板 |
| dnode_client.py | 节点客户端:全平台,单依赖 websockets,Android Chaquopy 支持 |
| run.py | 通用启动器:自动安装依赖,venv 管理,支持远程拉取执行 |
| dashboard.html | 实时监控大屏:节点地图、KPI、事件流 |
| admin.html | 管理面板:节点列表、踢除、URL 参数自动登录 |
| api-docs.html | API 文档 |
| start.sh | 服务端启动脚本,支持完整参数透传 |
快速启动
服务端
# 基础启动
PROXY_USER=admin PROXY_PASS=secret ADMIN_TOKEN=tok python3 proxy_server.py
# 或使用启动脚本
./start.sh -u admin -p secret -t tok --debug
| 端口 | 协议 | 说明 |
|------|------|------|
| 1080 | SOCKS5 | 代理入口 |
| 8888 | HTTP CONNECT | 代理入口 |
| 9000 | HTTP / WS | 控制面板、API、节点注册 |
节点客户端
# 直接运行
python dnode_client.py wss://dnode.qaiu.top/ws/node
# 通过启动器(自动安装依赖)
python run.py wss://dnode.qaiu.top/ws/node
# 从远程拉取执行(Pydroid 等嵌入式环境)
python run.py --url https://qaiu.top/src/py/dnode_client.py
环境变量
| 变量 | 默认 | 说明 |
|------|------|------|
| PROXY_USER | 空 | 代理用户名,逗号分隔多账号,空则不鉴权 |
| PROXY_PASS | 空 | 代理密码,与 PROXY_USER 一一对应 |
| ADMIN_TOKEN | 空 | Admin API 令牌,空则 Admin 全部拒绝 |
| SOCKS5_PORT | 1080 | SOCKS5 端口 |
| HTTP_PORT | 8888 | HTTP CONNECT 端口 |
| CONTROL_PORT | 9000 | 控制面板端口 |
| LOG_LEVEL | INFO | 日志级别,DEBUG 开启流量详情 |
| SHOW_TARGET | true | 事件流是否显示目标地址 |
代理认证 & 真实 IP
支持在凭证中携带真实 IP,用于 geo 节点选择(优先级:凭证 IP > XFF 头 > TCP peer):
# 格式 A 标准
curl -x http://admin:secret@host:8888 https://ipinfo.io
# 格式 B 携带真实 IP(适用于 Vert.x ProxyOptions 无法加自定义头的场景)
curl -x http://'admin:1.2.3.4':secret@host:8888 https://ipinfo.io
// Vert.x ProxyOptions
new ProxyOptions()
.setType(ProxyType.HTTP)
.setHost("dnode.qaiu.top").setPort(8888)
.setUsername("admin:" + userRealIp) // "admin:1.2.3.4"
.setPassword("secret");
Admin API
所有 Admin 接口需要 Authorization: Bearer <ADMIN_TOKEN> 或 ?token=<ADMIN_TOKEN>。
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/stats | 全局统计 + 最近 100 条事件(无需鉴权) |
| GET | /api/admin/nodes | 列出所有在线节点详情 |
| POST | /api/admin/node/{conn_id}/kick | 踢除单个节点,支持前 8 位前缀 |
| POST | /api/admin/nodes/kick-all | 踢除全部节点 |
节点分发策略
Tier 0 同城 (city 匹配)
Tier 1 同省 (province 匹配)
Tier 2 默认节点 (X-Default-Node: true)
Tier 3 任意节点 (兜底)
同 Tier 内取负载最低节点。节点存活由 WS 断开事件驱动,无时间窗口过滤。
Android 集成
// Chaquopy — 启动
thread {
Python.getInstance()
.getModule("dnode_client")
.callAttr("main_for_android",
"wss://dnode.qaiu.top/ws/node",
filesDir.absolutePath, // 配置目录
"", // node_id,空则自动生成
"", // secret
false, // is_default
false) // debug
}
// 停止(任意线程安全调用)
Python.getInstance()
.getModule("dnode_client")
.callAttr("stop_from_android")
停止机制:stop_from_android() 通过 loop.call_soon_threadsafe 主动关闭 WS 连接,打断 async for 循环,event loop 立即退出,不依赖 flag 轮询。
依赖
服务端 (proxy_server.py)
aiohttp >= 3.9
节点客户端 (dnode_client.py)
websockets >= 10.0
其余均为标准库(asyncio / ssl / struct / json)。


评论区