• 用 FRP 打通云服务器与本地 Ubuntu,让 Codex 远程调试本地硬件


    最近在做一个结合强化学习、嵌入式部署和机器人控制的项目,目标是把训练得到的控制策略部署到 STM32H747I-DISCO,并进一步控制 Petoi 机器狗。

    项目开发过程中,我遇到一个很现实的问题:我的 Codex 工作环境主要运行在云服务器上,但硬件设备却连接在我本地的一台 Ubuntu 服务器上。

    也就是说:

    • 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 "hostname && whoami && pwd"
    

    这样 Codex 就可以在云服务器上直接操作本地 Ubuntu 了。

    这对 Codex 调试硬件有什么帮助

    打通这条链路之后,调试体验发生了很大变化。

    之前和现在的差异,可以概括成下面这张图:

    打通之后

    Codex

    SSH 到本地 Ubuntu

    直接执行命令

    直接读取输出

    继续分析并执行下一步

    打通之前

    Codex 生成命令

    我手动复制

    本地 Ubuntu 手动执行

    我复制输出

    粘贴给 Codex 分析

    这对硬件调试尤其重要。

    例如,Codex 可以直接执行:

    lsusb
    

    确认 STM32H747I-DISCO 是否被识别:

    STMicroelectronics STLINK-V3
    

    也可以直接检查串口设备:

    ls -l /dev/ttyACM*
    

    可以直接调用 OpenOCD 烧录 STM32:

    openocd -f interface/stlink.cfg -f target/stm32h7x.cfg ...
    

    这样 Codex 不再只是“给建议”,而是可以真正参与调试闭环。

    一个实际例子:调试 STM32H747I-DISCO

    在这个项目里,我曾经需要把一个 STM32H747I-DISCO 的 demo 烧录到板子上。

    板子连接在本地 Ubuntu 上,但构建和代码分析主要在云服务器上完成。

    通过 FRP 打通之后,Codex 可以直接:

    1. 在云服务器上编译固件;
    2. 把 ELF 或 BIN 传到本地 Ubuntu;
    3. 调用本地 OpenOCD;
    4. 烧录 STM32H747I-DISCO;
    5. 读取 OpenOCD 输出;
    6. 判断烧录是否成功;
    7. 如果程序没跑起来,再读取 PC、寄存器、fault 状态继续分析。

    例如,烧录成功时 OpenOCD 会输出:

    Programming Finished
    Verified OK
    Resetting Target
    

    如果没有这条远程链路,每一次烧录和排错都需要我手动在两个环境之间来回搬运信息。

    一个实际例子:调试 Petoi 机器狗

    Petoi 机器狗也是类似情况。

    它连接在本地 Ubuntu 上,云服务器无法直接访问串口或 USB 设备。

    打通 FRP 后,Codex 可以直接在本地 Ubuntu 上检查设备、执行脚本、读取返回结果。

    这让调试变成了真正的远程协作:观察设备状态、修改或执行脚本、分析输出、决定下一步动作,都可以在同一条 SSH 链路里连续完成。

    对我来说,这比手动复制粘贴命令高效太多。

    安全注意事项

    这种方案虽然方便,但安全问题必须重视。

    我采用了几个基本原则:

    第一,FRP token 不提交到 Git。

    auth.token = "REPLACE_WITH_YOUR_TOKEN"
    

    真实 token 只放在本地配置文件或环境变量中。

    第二,云服务器上的反向 SSH 入口只绑定到本机。

    proxyBindAddr = "127.0.0.1"
    

    这样外部机器不能直接访问云服务器的 REMOTE_SSH_PORT 端口。

    第三,本地 Ubuntu 的 SSH 仍然使用密钥认证。

    不要为了方便而开启弱密码登录。

    这件事给我的启发

    这次经历让我更深刻地意识到,AI 编程助手在硬件项目里的能力,强烈依赖于它能否进入真实调试闭环。

    如果 Codex 只能“看代码”和“给命令”,那它更像一个高级问答工具。

    但如果它可以:

    • 直接运行命令;
    • 直接读取设备状态;
    • 直接烧录固件;
    • 直接分析 OpenOCD 或串口输出;
    • 直接根据结果调整下一步;

    那它就不再只是提供建议,而是在真正参与工程调试。

    对于嵌入式和机器人项目来说,这一点非常关键。

    因为这类项目的问题往往不只在代码里,还在:

    • USB 设备是否识别;
    • 串口权限是否正确;
    • 固件是否成功烧录;
    • MCU 是否 HardFault;
    • 外设初始化是否成功;
    • 机器人是否真实响应命令。

    只有让 AI 进入这些真实反馈环节,它才能发挥出更大的价值。

    总结

    这次用 FRP 打通云服务器和本地 Ubuntu,本质上解决的是一个“远程 AI 协作调试硬件”的问题。

    最终效果是:Windows 上的 Codex 操作云服务器,云服务器再通过 FRP SSH 到本地 Ubuntu,本地 Ubuntu 则直接访问 Petoi 机器狗和 STM32H747I-DISCO。

    这条链路避免了大量手动复制粘贴命令和输出的低效操作,让 Codex 可以直接参与硬件调试。

    对于我这个项目来说,这一步非常关键。它让云服务器上的 AI 编程助手,真正接触到了本地的机器人和开发板,也让整个强化学习、嵌入式部署、真机调试流程变得顺畅很多。

    以后如果还要做类似的嵌入式 AI 项目,我会优先把这种远程调试链路搭起来。因为它看似只是一个基础设施小工具,但实际能极大提升整个项目的开发效率。

  • 相关阅读:
    【XSS跨站脚本】反射型xss(非持久型)
    错误-maven工程,程序包org.apache.commons.xxx不存在,Java:不支持发行版本5
    【Mysql】增删改查(基础版)
    cat()函数和print()函数的区别
    手机实时预览vscode写的html页面
    Gof23设计模式之命令模式
    电路电子技术3 电位的计算&受控源在电路分析中的作用
    Java lambda表达式基本使用
    PLS-00172 string literal too long ORA-06550 字段太长插入不进去数据库
    Apollo简易地图制作
  • 原文地址:https://www.cnblogs.com/outs/p/20156105