用 FRP 打通云服务器与本地 Ubuntu,让 Codex 远程调试本地硬件
- Codex 可以方便地访问云服务器上的项目代码;
- Petoi 机器狗和 STM32H747I-DISCO 却通过 USB 连接在本地 Ubuntu 上;
- 本地 Ubuntu 没有公网 IP,云服务器无法直接 SSH 到它。
如果不解决这个问题,调试流程就会变成下面这样:
Codex 给出命令
我复制命令
粘贴到本地 Ubuntu 执行
复制命令输出
粘贴回 Codex 分析
Codex 给出下一步
这个流程非常痛苦。
对于普通软件项目,这样手动来回复制几次也许还能忍。但对于硬件调试来说,情况完全不同。硬件调试往往需要频繁执行命令、观察输出、调整脚本、重新烧录、读取串口或 OpenOCD 状态。如果每一步都要手动复制粘贴,效率会非常低,也很容易出错。
后来我通过 FRP 打通了云服务器与本地 Ubuntu 之间的反向 SSH 通道,使 Codex 可以通过云服务器直接登录到本地 Ubuntu,从而直接调试连接在本地 Ubuntu 上的硬件设备。
这篇文章记录一下这个过程。
问题背景
我的实际开发环境大致如下:
- Windows PC 可以通过 Codex / SSH 访问云服务器;
- 云服务器有公网 IP;
- 本地 Ubuntu 在局域网内,没有公网 IP;
- Petoi 机器狗和 STM32H747I-DISCO 通过 USB 连接在本地 Ubuntu 上。
其中,Windows PC 可以访问云服务器,云服务器也有公网 IP。
但是本地 Ubuntu 位于局域网中,没有公网 IP。云服务器不能直接 SSH 到本地 Ubuntu。
这就导致 Codex 虽然可以在云服务器上帮我分析代码、构建固件、生成命令,但无法直接操作连接在本地 Ubuntu 上的硬件。
而硬件调试又恰恰需要直接访问本地 Ubuntu,例如:
lsusb
ls /dev/ttyACM*
openocd ...
arduino-cli ...
python scripts/xxx.py
如果 Codex 无法直接执行这些命令,整个调试体验就会退化成“人工搬运命令和输出”。
为什么选择 FRP
为了解决这个问题,我需要一种方式,让云服务器能够访问本地 Ubuntu。
常见方案有几种:
- 给本地 Ubuntu 配置公网 IP;
- 在路由器上做端口映射;
- 使用 Tailscale / ZeroTier 这类组网工具;
- 使用 FRP 做反向隧道。
我的场景下,FRP 是一个很合适的选择。
原因是:
- 云服务器有公网 IP,可以作为 FRP server;
- 本地 Ubuntu 虽然没有公网 IP,但可以主动连接云服务器;
- 一旦本地 Ubuntu 主动连上云服务器,就可以把本地 SSH 端口反向暴露到云服务器;
- Codex 已经可以访问云服务器,因此也就间接获得了访问本地 Ubuntu 的能力。
最终效果是:Codex 仍然只操作云服务器,但云服务器上的 127.0.0.1:REMOTE_SSH_PORT 会通过 FRP 转发到本地 Ubuntu 的 SSH 服务。
从 Codex 的角度看,它只需要在云服务器上执行:
ssh -p REMOTE_SSH_PORT ubuntu@127.0.0.1
就能登录到本地 Ubuntu。
整体架构
整个链路可以画成这样:
SSH
访问 127.0.0.1:REMOTE_SSH_PORT
主动连接云服务器
转发到 127.0.0.1:LOCAL_SSH_PORT
USB / 串口 / OpenOCD
Windows / Codex
云服务器
frps
frpc
本地 Ubuntu SSH
Petoi 机器狗 / STM32H747I-DISCO
其中:
frps运行在云服务器;frpc运行在本地 Ubuntu;- 本地 Ubuntu 主动连接云服务器;
- 云服务器监听一个本地端口,例如
REMOTE_SSH_PORT; - 访问云服务器的
127.0.0.1:REMOTE_SSH_PORT,实际会被转发到本地 Ubuntu 的 SSH 服务。
这里有一点很重要:云服务器上的反向 SSH 入口只绑定到 127.0.0.1,而不是 0.0.0.0。
这样外部网络无法直接访问这个 SSH 隧道,只有云服务器本机上的进程可以访问它,安全性更好。
云服务器上的 frps 配置
云服务器上运行 frps,配置大致如下:
bindAddr = "0.0.0.0"
bindPort = FRP_SERVER_PORT
proxyBindAddr = "127.0.0.1"
auth.method = "token"
auth.token = "REPLACE_WITH_YOUR_TOKEN"
说明:
bindPort = FRP_SERVER_PORT:本地 Ubuntu 的frpc会连接云服务器的这个端口;proxyBindAddr = "127.0.0.1":反向暴露出来的 SSH 端口只监听云服务器本机;auth.token:认证 token,不能提交到 Git,也不要写进公开博客。
启动 frps:
./frps -c frps.toml
启动成功后,云服务器会等待本地 Ubuntu 上的 frpc 连接。
本地 Ubuntu 上的 frpc 配置
本地 Ubuntu 上运行 frpc,配置大致如下:
serverAddr = "YOUR_CLOUD_PUBLIC_IP"
serverPort = FRP_SERVER_PORT
auth.method = "token"
auth.token = "REPLACE_WITH_YOUR_TOKEN"
[[proxies]]
name = "local-ubuntu-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = LOCAL_SSH_PORT
remotePort = REMOTE_SSH_PORT
说明:
serverAddr是云服务器公网 IP;serverPort对应云服务器上的frps监听端口;localPort = LOCAL_SSH_PORT是本地 Ubuntu 的 SSH 端口;remotePort = REMOTE_SSH_PORT是云服务器上暴露出来的反向 SSH 端口;- 由于云服务器上配置了
proxyBindAddr = "127.0.0.1",所以REMOTE_SSH_PORT只会绑定在云服务器本机。
启动 frpc:
./frpc -c frpc.toml
连接成功后,云服务器上的 frps 日志里会出现类似信息:
client login info ...
new proxy [local-ubuntu-ssh] type [tcp] success
tcp proxy listen port [REMOTE_SSH_PORT]
验证 SSH 隧道
在云服务器上执行:
ssh -p REMOTE_SSH_PORT ubuntu@127.0.0.1
如果能登录到本地 Ubuntu,就说明链路已经打通。
也可以执行一个简单命令验证:
ssh -p REMOTE_SSH_PORT ubuntu@127.0.0.1 "ho
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)