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 整体拓扑

flowchart LR W[Windows 笔记本<br/>Codex 桌面客户端] U[家中或实验室 Ubuntu<br/>项目与 Codex 远端环境] C[公网云服务器<br/>SSH 跳板机 + frps] W -->|在家:局域网 SSH| U W -->|外出:SSH ProxyJump| C C -->|访问云服务器本机回环端口| F[127.0.0.1:FRP_REMOTE_PORT] F -->|FRP 隧道| U

三台机器分别承担以下职责:

机器 职责
Windows 笔记本 运行 Codex 桌面客户端,通过 SSH 进入远端环境
家中 Ubuntu 运行 frpc,保存项目、开发工具和 Codex 远端数据
公网云服务器 运行 frps,同时作为 SSH 跳板机

3.2 外出时的数据路径

sequenceDiagram participant W as Windows / Codex participant C as 公网云服务器 participant U as 家中 Ubuntu U->>C: frpc 主动连接 frps,建立长期隧道 W->>C: SSH 登录跳板机 W->>C: 请求连接 127.0.0.1:FRP_REMOTE_PORT C->>U: frps 通过已有隧道转发到 Ubuntu SSH W->>U: 完成最终 SSH 认证

关键点在于: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 服务访问其本机回环端口。

最终形成两层控制:

  1. 先通过云服务器 SSH 身份认证;
  2. 再通过家中 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>
  • 云服务器系统防火墙是否允许该端口;
  • serverAddrserverPort 和令牌是否一致;
  • frpsfrpc 版本是否兼容;
  • 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 配置块同时启用,结果不一定是后一个覆盖前一个,而可能出现配置混合,例如:

  • HostNamePort 来自第一个配置块;
  • 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 推荐的切换流程

从在家切换到外出,或者反向切换时:

  1. 在 Codex 中关闭 HomeUbuntu 连接;
  2. 在 Windows SSH 配置中完整切换 Host HomeUbuntu 配置块;
  3. 执行 ssh -G HomeUbuntu 检查最终参数;
  4. 执行 ssh HomeUbuntu 验证连接;
  5. 在 Codex 中重新启用 HomeUbuntu
  6. 打开原来的远程任务,而不是创建新任务;
  7. 继续原有对话和项目工作。

如果忘记在出门前切换,也不影响。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.tomlfrpc.toml 中,并限制配置文件的读取权限。

12.3 云服务器只开放必要端口

公网安全组通常只需允许:

  • <CLOUD_SSH_PORT>
  • <FRPS_BIND_PORT>

<FRP_REMOTE_PORT> 只监听 127.0.0.1,不应额外向公网开放。

12.4 为服务设置自动重启

frpsfrpc 都应由 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

并核对两端的:

  • serverPortbindPort
  • 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 必须开机;
  • 家庭网络必须能够主动访问云服务器;
  • frpcfrps 必须正常运行;
  • 云服务器必须在线;
  • 外出体验受家庭上行带宽、云服务器线路和网络时延影响;
  • 手动切换 SSH 配置时必须确保只启用一个 HomeUbuntu 配置块。

如果团队规模扩大、需要多人访问或希望集中管理身份,可以进一步评估 VPN、组网工具、堡垒机或零信任访问方案。对于个人在家与外出之间切换的场景,FRP 配合 SSH ProxyJump 已经足够直接、透明且容易维护。

15. 总结

这次实践最终解决的并不只是“如何穿透内网”,而是:

在家和外出时,如何通过 Codex 连接同一台没有公网 IP 的 Ubuntu,并在原来的对话中继续工作。

方案的核心可以概括为四点:

  1. 家中 Ubuntu 主动通过 frpc 连接公网云服务器;
  2. 云服务器的 FRP 远程端口只监听 127.0.0.1
  3. Windows 外出时通过 SSH ProxyJump 安全访问该回环端口;
  4. 在家和外出时始终使用同一个 HomeUbuntu 别名,连接同一台电脑、同一用户和同一项目。

网络路径可以改变,远程开发环境和任务身份不必改变。相比追求复杂的自动切换,两个明确、可验证的静态配置块更容易获得稳定且可维护的使用体验。

posted @ 2026-08-27 23:31  icuic  阅读(8)  评论(0)    收藏  举报