Codex 远程开发实践:在家中与外出时连接同一台内网 Ubuntu,并延续原有Codex对话
1. 引出问题
我家中有一台用于开发的 Ubuntu 电脑。它保存着项目源码、编译环境和硬件调试工具,但没有公网 IP。
平时在家,在家时,我可以让 Windows 笔记本上的 Codex 通过局域网直接连接这台 Ubuntu;外出后,局域网地址自然无法访问。更重要的是,我希望无论身处何处,都能在 Codex 中打开同一个远程任务,在原来的对话上下文中继续工作,而不是重新创建项目、重新解释背景或迁移整段聊天记录。
最终采用的方案是:
- 在家时,Codex 通过局域网 SSH 连接 Ubuntu;
- 外出时,Codex 通过公网云服务器、FRP 和 SSH
ProxyJump连接同一台 Ubuntu; - 两种场景始终使用同一个 SSH 主机别名;
- 网络路径可以变化,但远端电脑、Linux 用户、项目目录和 Codex 数据目录保持不变;
- 在 Codex 中继续打开原来的远程任务,从而延续已有对话上下文。
不想阅读完整配置过程?
可以把本文直接交给 Codex、WorkBuddy 等具备终端操作能力的 AI 工具,并告诉它:“请根据本文方案检查我的实际环境,先备份现有配置,再逐步完成部署和验证。”AI 可以协助安装 FRP、生成配置、创建 systemd 服务、调整 SSH 配置并执行连通性测试。不过,云服务器安全组、
sudo授权、SSH 密钥和其他敏感操作仍应由用户本人确认;不要把私钥、令牌或密码直接粘贴到对话中,也不要在未审查命令和备份配置的情况下允许批量修改。
本文记录这一方案的设计思路、配置方法、验证步骤和实际使用方式。文中的地址、端口、用户名和密钥路径均为脱敏占位符,使用时必须替换成自己的配置。
2. 要解决的问题
2.1 家中 Ubuntu 没有公网 IP
家庭和实验室网络通常位于 NAT 之后。Ubuntu 可以主动访问互联网,但互联网中的 Windows 笔记本无法直接向它发起连接。人在外出时,Windows 笔记本也无法直接访问家庭或实验室局域网中的设备。
如果只配置局域网 SSH,离开家庭或实验室网络后,下列地址就不再可达:
<HOME_LAN_IP>:<HOME_SSH_PORT>
2.2 项目实际运行在位于家庭或实验室局域网中的 Ubuntu 上
这里的 Ubuntu 是一台位于家庭或实验室局域网内的开发电脑,并不只是代码存储位置,还可能承担以下工作:
- 编译 Linux 或嵌入式项目;
- 运行容器、仿真器和训练任务;
- 连接串口、调试器或其他硬件;
- 保存大型数据集和厂商资料;
- 提供适合长期运行的开发环境。
因此,将整个项目复制到 Windows 再开发并不理想。更合理的方式是让 Codex 直接使用局域网中 Ubuntu 上的项目和工具。
2.3 远程连接不能破坏任务连续性
在家和外出时,连接路径虽然不同,但目标都是同一台 Ubuntu。如果因为网络变化而在 Codex 中创建两个不同的远程主机身份,后续容易出现:
- 同一项目出现多个入口;
- 不清楚应该在哪个入口继续任务;
- 新任务缺少原有对话背景;
- 项目路径和执行环境容易混淆。
本方案的核心目标不是“自动找到一台可连接的主机”,而是让同一个固定 SSH 别名在不同场景下指向同一台电脑。
3. 最终网络架构
3.1 整体拓扑
三台机器分别承担以下职责:
| 机器 | 职责 |
|---|---|
| Windows 笔记本 | 运行 Codex 桌面客户端,通过 SSH 进入远端环境 |
| 家中 Ubuntu | 运行 frpc,保存项目、开发工具和 Codex 远端数据 |
| 公网云服务器 | 运行 frps,同时作为 SSH 跳板机 |
3.2 外出时的数据路径
关键点在于:FRP 连接由家中的 Ubuntu 主动发起,因此不要求家庭宽带拥有公网 IP,也不需要在家庭路由器上做端口映射。
4. 为什么让 FRP 转发端口只监听 127.0.0.1
最直接的 FRP 用法,是让云服务器的某个公网端口转发到家中 Ubuntu 的 SSH 端口:
Internet → <CLOUD_PUBLIC_IP>:<FRP_REMOTE_PORT> → Ubuntu SSH
这种方式虽然简单,却会把转发后的 SSH 端口暴露在公网。即使已经禁用密码登录,公网扫描、暴力尝试和日志噪声仍然没有必要。
更稳妥的做法是让 frps 的代理端口只绑定云服务器回环地址:
127.0.0.1:<FRP_REMOTE_PORT>
这样,互联网无法直接访问该端口。Windows 必须先通过正常的 SSH 认证进入云服务器,再使用 ProxyJump 让云服务器上的 SSH 服务访问其本机回环端口。
最终形成两层控制:
- 先通过云服务器 SSH 身份认证;
- 再通过家中 Ubuntu SSH 身份认证。
此时,云服务器安全组只需要放行:
- 云服务器自身的 SSH 端口;
frpc连接frps所需的服务端端口。
不需要向公网放行 <FRP_REMOTE_PORT>,因为它只监听 127.0.0.1。
5. 前置条件
开始配置前,需要准备:
- 一台具有公网 IP 的云服务器;
- 一台位于家中或实验室内的 Ubuntu;
- 一台运行 Codex 桌面客户端和 OpenSSH 的 Windows 笔记本;
- Windows 到云服务器的 SSH 密钥登录;
- Windows 到家中 Ubuntu 的 SSH 密钥登录;
- 云服务器与家中 Ubuntu 使用相同版本的 FRP;
- 家中 Ubuntu 能够主动访问云服务器的
<FRPS_BIND_PORT>。
如果暂时没有公网云服务器,可以通过腾讯云活动页面查看可用机型。本文场景对服务器性能要求不高,选择网络稳定、地域合适的基础配置即可。活动中最便宜的配置一年仅需 99 元,包含 2 核 CPU、2 GB 内存、4 Mbps 带宽、50 GB SSD 云硬盘和每月 300 GB 流量。
本文使用以下占位符:
| 占位符 | 含义 |
|---|---|
<CLOUD_PUBLIC_IP> |
云服务器公网 IP 或域名 |
<CLOUD_SSH_PORT> |
云服务器 SSH 端口 |
<FRPS_BIND_PORT> |
frpc 连接 frps 的端口 |
<FRP_REMOTE_PORT> |
云服务器回环地址上的 SSH 转发端口 |
<HOME_LAN_IP> |
家中 Ubuntu 的局域网 IP |
<HOME_SSH_PORT> |
家中 Ubuntu 的 SSH 端口 |
<REMOTE_USER> |
Ubuntu 登录用户 |
<CLOUD_USER> |
云服务器登录用户 |
<PRIVATE_KEY_PATH> |
Windows 上访问 Ubuntu 的私钥路径 |
<CLOUD_KEY_PATH> |
Windows 上访问云服务器的私钥路径 |
<STRONG_RANDOM_TOKEN> |
FRP 使用的高强度随机令牌 |
不同用途的端口应当使用不同值,避免混淆。
6. 在云服务器上配置 frps
6.1 frps.toml
在云服务器创建 frps.toml:
bindAddr = "0.0.0.0"
bindPort = <FRPS_BIND_PORT>
# 所有 FRP 代理端口只绑定云服务器回环地址。
proxyBindAddr = "127.0.0.1"
auth.method = "token"
auth.token = "<STRONG_RANDOM_TOKEN>"
其中:
bindPort用于接收家中 Ubuntu 上frpc的连接;proxyBindAddr决定 FRP 创建的代理端口监听在哪个地址;127.0.0.1表示代理端口只能从云服务器本机访问;auth.token用于避免未经授权的frpc接入。
6.2 使用 systemd 运行 frps
下面是一个脱敏后的服务示例:
[Unit]
Description=FRP Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=<CLOUD_USER>
ExecStart=/opt/frp/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
启用服务:
sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo systemctl status frps --no-pager
6.3 检查监听状态
sudo ss -lntp
预期看到两类监听:
0.0.0.0:<FRPS_BIND_PORT>
127.0.0.1:<FRP_REMOTE_PORT>
第二个端口只有在家中 Ubuntu 的 frpc 成功连接并注册代理后才会出现。
7. 在家中 Ubuntu 上配置 frpc
7.1 frpc.toml
在家中 Ubuntu 创建 frpc.toml:
serverAddr = "<CLOUD_PUBLIC_IP>"
serverPort = <FRPS_BIND_PORT>
auth.method = "token"
auth.token = "<STRONG_RANDOM_TOKEN>"
[[proxies]]
name = "home-ubuntu-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = <HOME_SSH_PORT>
remotePort = <FRP_REMOTE_PORT>
这里的含义是:
云服务器 127.0.0.1:<FRP_REMOTE_PORT>
→ FRP 隧道
→ 家中 Ubuntu 127.0.0.1:<HOME_SSH_PORT>
7.2 使用 systemd 运行 frpc
[Unit]
Description=FRP Client
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=<REMOTE_USER>
ExecStart=/opt/frp/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
启用并检查:
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
sudo systemctl status frpc --no-pager
如果 frpc 无法连接,应依次检查:
- 云服务器安全组是否放行
<FRPS_BIND_PORT>; - 云服务器系统防火墙是否允许该端口;
serverAddr、serverPort和令牌是否一致;frps与frpc版本是否兼容;- Ubuntu 本机 SSH 是否确实监听
<HOME_SSH_PORT>。
8. Windows SSH 配置
8.1 云服务器跳板机
在 Windows 的 OpenSSH 配置文件中添加云服务器:
Host RelayServer
HostName <CLOUD_PUBLIC_IP>
Port <CLOUD_SSH_PORT>
User <CLOUD_USER>
IdentityFile <CLOUD_KEY_PATH>
IdentitiesOnly yes
通常配置文件位于:
%USERPROFILE%\.ssh\config
8.2 在家时的 HomeUbuntu 配置
在家时,让固定别名 HomeUbuntu 直接指向局域网地址:
Host HomeUbuntu
HostName <HOME_LAN_IP>
Port <HOME_SSH_PORT>
User <REMOTE_USER>
IdentityFile <PRIVATE_KEY_PATH>
IdentitiesOnly yes
HostKeyAlias HomeUbuntu
ConnectTimeout 5
ServerAliveInterval 30
ServerAliveCountMax 3
8.3 外出时的 HomeUbuntu 配置
外出时,仍然使用 HomeUbuntu,但将它改为固定走云服务器:
Host HomeUbuntu
HostName 127.0.0.1
Port <FRP_REMOTE_PORT>
User <REMOTE_USER>
IdentityFile <PRIVATE_KEY_PATH>
IdentitiesOnly yes
HostKeyAlias HomeUbuntu
ProxyJump RelayServer
ConnectTimeout 15
ServerAliveInterval 30
ServerAliveCountMax 3
这段配置并不是让 Windows 连接自身的 127.0.0.1。因为存在:
ProxyJump RelayServer
OpenSSH 会先登录 RelayServer,然后由云服务器访问其本机的:
127.0.0.1:<FRP_REMOTE_PORT>
该端口再通过 FRP 隧道到达家中 Ubuntu。
8.4 为什么两个同名 Host 配置不能同时启用
OpenSSH 读取配置时,通常采用“先获得的值优先”。如果两个 Host HomeUbuntu 配置块同时启用,结果不一定是后一个覆盖前一个,而可能出现配置混合,例如:
HostName和Port来自第一个配置块;ProxyJump来自第二个配置块;- 最终产生一条并非预期的连接路径。
因此,任何时候只能启用一个完整的 Host HomeUbuntu 配置块。
一种简单可靠的管理方式是:
- 在家时,完整启用局域网配置,完整注释外出配置;
- 外出时,完整注释局域网配置,完整启用 FRP 配置;
- 不要只注释其中一两行;
- 不要在配置中留下单独的反斜杠或其他无效字符。
9. 为什么最终采用手动切换静态配置
9.1 曾考虑过自动判断网络
直觉上,可以使用 OpenSSH 的 Match exec:先快速探测局域网地址,如果可达就走局域网,否则走 FRP。
命令行中的 OpenSSH 可以实现类似逻辑。但在实际使用中,Codex 桌面客户端除了建立 SSH 会话,还需要在远端启动服务并建立后续通信。复杂的动态匹配和多层跳转会增加主机配置解析的不确定性。
9.2 稳定性比自动化更重要
最终采用两个静态配置块手动切换,原因是:
- 每个场景的最终 SSH 配置清晰可见;
- 可以使用
ssh -G准确检查; - Codex 始终只看到一个固定主机别名;
- 出现问题时容易判断当前走的是哪条路径;
- 切换操作虽然多一步,但频率很低;
- 避免为了自动化而引入难以排查的边界行为。
这里的经验是:网络自动选择并不是目标,可靠地继续同一个远程任务才是目标。
10. 如何验证两种连接路径
10.1 查看最终生效的 SSH 配置
每次切换后,在 Windows CMD 中执行:
ssh -G HomeUbuntu | findstr /i "hostname port proxyjump hostkeyalias"
在家时,预期结果包含:
hostname <HOME_LAN_IP>
port <HOME_SSH_PORT>
hostkeyalias HomeUbuntu
不应出现 proxyjump。
外出时,预期结果包含:
hostname 127.0.0.1
port <FRP_REMOTE_PORT>
proxyjump RelayServer
hostkeyalias HomeUbuntu
10.2 验证局域网路径
在家时执行:
ssh HomeUbuntu "hostname && whoami"
确认返回的是目标 Ubuntu 的主机名和用户。
10.3 验证 FRP 路径
可以在家中临时启用外出配置进行测试,无需真的离开家。
ssh -v HomeUbuntu "hostname && whoami"
日志应显示先连接 RelayServer,随后认证最终 Ubuntu。
还可以在云服务器检查:
ss -lnt | grep <FRP_REMOTE_PORT>
预期只看到:
127.0.0.1:<FRP_REMOTE_PORT>
如果显示 0.0.0.0:<FRP_REMOTE_PORT>,说明该端口可能暴露在公网,需要检查 frps.toml 中的 proxyBindAddr。
11. 在 Codex 中保持同一任务和对话上下文
11.1 真正需要保持不变的内容
对话连续性的关键并不是网络路径完全相同,而是以下身份和状态保持一致:
| 项目 | 在家 | 外出 |
|---|---|---|
| Codex 中的 SSH 主机名 | HomeUbuntu |
HomeUbuntu |
| 最终电脑 | 同一台 Ubuntu | 同一台 Ubuntu |
| Linux 用户 | <REMOTE_USER> |
<REMOTE_USER> |
| Codex 远端数据目录 | 同一个用户目录下的 .codex |
同一个用户目录下的 .codex |
| 项目目录 | <PROJECT_PATH> |
<PROJECT_PATH> |
| 网络路径 | 局域网直连 | 云服务器与 FRP |
可以把它理解为:只是去同一个办公室时选择了不同路线,办公室、工位和桌上的资料都没有变化。
11.2 推荐的切换流程
从在家切换到外出,或者反向切换时:
- 在 Codex 中关闭
HomeUbuntu连接; - 在 Windows SSH 配置中完整切换
Host HomeUbuntu配置块; - 执行
ssh -G HomeUbuntu检查最终参数; - 执行
ssh HomeUbuntu验证连接; - 在 Codex 中重新启用
HomeUbuntu; - 打开原来的远程任务,而不是创建新任务;
- 继续原有对话和项目工作。
如果忘记在出门前切换,也不影响。SSH 配置保存在随身携带的 Windows 笔记本上,只要家中 Ubuntu、frpc 和云服务器仍在运行,外出后仍可修改配置。
12. 安全建议
12.1 SSH 只使用密钥认证
建议在云服务器和家中 Ubuntu 上:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
修改前应保留一个已经连接的 SSH 会话,并使用:
sudo sshd -t
确认配置语法正确后再重新加载 SSH 服务,避免把自己锁在服务器之外。
12.2 FRP 使用独立随机令牌
不要使用示例令牌或短密码。可以在可信环境中生成随机值,例如:
openssl rand -hex 32
令牌应只保存在 frps.toml 和 frpc.toml 中,并限制配置文件的读取权限。
12.3 云服务器只开放必要端口
公网安全组通常只需允许:
<CLOUD_SSH_PORT>;<FRPS_BIND_PORT>。
<FRP_REMOTE_PORT> 只监听 127.0.0.1,不应额外向公网开放。
12.4 为服务设置自动重启
frps 和 frpc 都应由 systemd 管理,并设置合理的 Restart 策略。这样云服务器或家中 Ubuntu 重启后,远程通道能够自动恢复。
13. 常见问题
13.1 ssh HomeUbuntu 在家可用,外出不可用
首先执行:
ssh -G HomeUbuntu | findstr /i "hostname port proxyjump"
如果仍然显示局域网地址,说明尚未切换到外出配置。
13.2 云服务器没有监听 FRP 远程端口
依次检查:
systemctl status frps --no-pager
systemctl status frpc --no-pager
并核对两端的:
serverPort与bindPort;auth.token;remotePort;- FRP 版本;
- 云服务器安全组。
13.3 云服务器远程端口监听在 0.0.0.0
检查 frps.toml:
proxyBindAddr = "127.0.0.1"
修改后重启 frps,再等待 frpc 重新连接。
13.4 两个 HomeUbuntu 配置块都没有注释
不要假设后一个配置块会完整覆盖前一个。请完整注释其中一个块,再使用 ssh -G 查看最终结果。
13.5 命令行连接正常,但 Codex 没有使用新路径
SSH 配置修改后,已经存在的连接不会自动改变底层路径。应在 Codex 中先关闭 HomeUbuntu,等待数秒,再重新启用。
14. 方案的边界
这套方案解决了网络路径变化与 Codex 远程任务连续性问题,但仍有以下前提:
- 家中 Ubuntu 必须开机;
- 家庭网络必须能够主动访问云服务器;
frpc和frps必须正常运行;- 云服务器必须在线;
- 外出体验受家庭上行带宽、云服务器线路和网络时延影响;
- 手动切换 SSH 配置时必须确保只启用一个
HomeUbuntu配置块。
如果团队规模扩大、需要多人访问或希望集中管理身份,可以进一步评估 VPN、组网工具、堡垒机或零信任访问方案。对于个人在家与外出之间切换的场景,FRP 配合 SSH ProxyJump 已经足够直接、透明且容易维护。
15. 总结
这次实践最终解决的并不只是“如何穿透内网”,而是:
在家和外出时,如何通过 Codex 连接同一台没有公网 IP 的 Ubuntu,并在原来的对话中继续工作。
方案的核心可以概括为四点:
- 家中 Ubuntu 主动通过
frpc连接公网云服务器; - 云服务器的 FRP 远程端口只监听
127.0.0.1; - Windows 外出时通过 SSH
ProxyJump安全访问该回环端口; - 在家和外出时始终使用同一个
HomeUbuntu别名,连接同一台电脑、同一用户和同一项目。
网络路径可以改变,远程开发环境和任务身份不必改变。相比追求复杂的自动切换,两个明确、可验证的静态配置块更容易获得稳定且可维护的使用体验。

浙公网安备 33010602011771号