文档

快速开始 + 每部分每设备的功能说明(持续更新中)

端口穿透

本文介绍面板的「端口穿透」——把穿透服务器上的应用端口映射到面板服务器的公网端口。

功能简介

对于通过「穿透运维」接入的无公网 IP 服务器,它上面的应用(如 Navidrome 音乐、Nextcloud 网盘、Memos 笔记)无法被外部访问。端口穿透把这些应用端口映射到面板服务器(有公网 IP)的端口上,让外部用户通过「面板服务器 IP:端口」访问。

适用场景

  • 穿透服务器上跑了 Web 应用,想让外部访问
  • 把内网设备的服务暴露到公网

原理

外部用户 → 面板服务器公网端口 (如 :9117) → 转发通道 → 穿透服务器应用端口 (如 :9117)

统一通道(所有设备,无需手动选择):

设备类型转发通道原因
Linux 服务器(无公网 IP)4433 反向隧道(AES-256-GCM 加密)原生 TCP 字节流,快且稳,支持大量并发
安卓/Termux 设备4433 反向隧道(AES-256-GCM 加密)同上。曾误判「移动运营商重置 4433」改走 SocketIO,实测安卓设备多在 WiFi 环境(无 SIM 卡),4433 隧道同样稳定且更快(无 base64 膨胀)

面板统一走 4433 反向隧道,创建穿透时无需关心底层通道。

使用方法

1. 确保目标设备已通过「穿透运维」接入(Agent 在线)

2. 打开「端口穿透」,点击「添加穿透」

3. 选择穿透服务器(Agent),填写:

  • 监听端口:面板服务器的公网端口(外部访问用)
  • 目标端口:穿透服务器上的应用端口

4. 创建后,外部即可访问 http://面板服务器IP:监听端口

资源上限

限制
每个 Agent 最多转发通道32
全面板最多 Agent64

超出会自动拒绝新连接,不影响已运行的穿透

注意事项

1. 云防火墙:面板服务器的云防火墙/安全组需放行对应的监听端口,否则外部访问不了。

2. Agent 版本:转发非 SSH 端口(非 22)需要穿透服务器已安装新版 Agent(旧版只支持转发 22 端口)。如需转发其他端口,请重新安装 Agent。

3. Agent 在线:穿透依赖 Agent 保持在线。Agent 离线时穿透会中断,重连后自动恢复。

4. 面板服务重启后,穿透会自动恢复(Agent 重连时触发)。

5. 所有设备统一走 4433 反向隧道:端口穿透统一经 4433 反向隧道(AES-256-GCM 加密、原生 TCP 字节流)转发,无 base64 膨胀、无 SocketIO 协议开销,速度快、支持大量并发。安卓/Termux 设备的系统管理(命令执行/终端/文件)仍走 SocketIO 稳定通道(5501),但端口穿透走 4433 隧道——两者互不干扰。历史:曾误判「移动运营商重置 4433」把安卓穿透改走 SocketIO,实测安卓设备多在 WiFi 环境(无 SIM 卡),4433 隧道同样稳定且更快,故统一回归 4433。

6. 安卓目标服务需支持并发:安卓上被穿透的目标服务(如 python3 -m http.server)若为单线程且启用 keep-alive,同一连接未关闭会阻塞后续请求。建议目标服务使用多线程(如 Python 3.7+ 的 http.server 已默认多线程),或确保连接及时关闭。

7. (SocketIO 通道历史坑,现已停用 SocketIO 穿透、统一走 4433,代码保留备用)通道号 ch_id 必须全局唯一(跨穿透):面板端 SocketIO 转发为每个连接分配 ch_id_handle_agent_fwd_datach_id 遍历所有穿透查找 socket。若每个穿透各自从 1 递增,多个穿透同时使用时 ch_id 冲突,会把 A 穿透的响应数据写进 B 穿透的连接(串数据)——症状:openclaw 图标巨型(CSS 串了)、lan-monitor 无数据(数据串走)、登录页加载不出(JS 串了)。修复:用模块级全局 _sio_pf_next_ch 递增,且函数内须加 global 声明(否则 += 会让 Python 当局部变量,抛 UnboundLocalError 致 accept 循环崩溃、连接全部超时)。

8. (SocketIO 通道历史坑)安卓穿透大文件慢(如 echarts 1MB):SocketIO 通道因 base64 膨胀 + 协议开销,大前端资源(echarts.min.js 1MB、Vite 打包 CSS 466KB)下载需 5-30s,浏览器可能超时导致资源加载失败、页面 JS 崩(如 lan-monitor 的 echarts.init 因 echarts 未定义抛 ReferenceError,页面只剩框架无数据)。已改用 4433 隧道(原生字节流)根治;目标应用加 gzip 仍有益(echarts 1MB→326KB)——Flask 用 after_request 中间件,静态文件 direct_passthrough=Trueget_data() 会抛 RuntimeError,需先 b''.join(resp.response) 读入内存再压缩。