我的远程开发组合技:Ghostty + SSH + tmux

发表信息: by

最近一直在折腾远程开发机、SSH、Codex、code-server,还有手机上怎么接回开发现场。折腾了一圈之后,我发现真正稳定好用的方案不是某一个工具,而是一套组合技:

Ghostty 负责本地终端体验
SSH 负责连到远程开发机
tmux 负责会话保活和分屏
Codex / code-server / vim / 脚本 跑在 tmux 里面

这套组合的核心目标很简单:网络断了没事,电脑休眠没事,手机切后台也没事,任务继续在服务器上跑,回来还能接着干。


先说结论

如果你只想直接抄作业,我建议这样用:

# 1. 本地 Ghostty 里 SSH 到远程开发机
ssh n37

# 2. 在远程机器上创建一个 tmux 会话
tmux new -s codex

# 3. 在 tmux 里面跑长期任务
codex

临时退出但不结束任务:

Ctrl+b,然后按 d

下次回来:

ssh n37
tmux a -t codex

这就是 80% 的用法。


这几个工具分别解决什么问题

很多人会把终端、Shell、SSH、tmux 混在一起理解,其实它们不是一类东西。

工具 负责什么 一句话理解
Ghostty 本地终端 App 替代 Terminal / iTerm2,负责显示终端窗口
SSH 远程连接协议 从本地连到远程开发机
Shell 命令解释器 bash / zsh / fish,负责执行命令
tmux 终端会话管理器 让远程任务断线不丢,还能分屏和多窗口
Codex / code-server 具体工作负载 真正干活的 AI 编程工具或 Web IDE

所以它们的关系是:

你的电脑
  └── Ghostty
        └── ssh n37
              └── tmux session
                    ├── pane 1: codex
                    ├── pane 2: git / vim
                    └── pane 3: server / logs

Ghostty 让本地体验舒服,tmux 让远程现场不丢。


为什么不能只靠 SSH

普通 SSH 有一个问题:它和当前网络连接强绑定。

你直接这样跑:

ssh n37
codex

如果本地网络断了、电脑睡眠了、手机切后台了,这个 SSH 连接就可能断掉。连接一断,里面前台跑的任务也可能一起没了。

这对 AI 编程尤其难受:

  • Codex 正在分析代码,突然断了;
  • 一个长脚本刚跑到一半,断了;
  • 服务日志正在排查,断了;
  • 手机上刚连回去,App 被系统杀后台,断了。

所以只靠 SSH 不够。SSH 负责「连上去」,但不负责「现场保活」。

这个活要交给 tmux。


tmux 的核心价值:会话和连接解耦

tmux 最关键的能力是:把终端会话放在服务器上,而不是放在你的 SSH 连接里。

也就是说:

没有 tmux:
本地终端断了 = 远程任务也可能断

有 tmux:
本地终端断了 = 只是你暂时看不见,任务还在远程继续跑

这就是为什么远程开发机上一定要用 tmux。


我的推荐会话规划

我不建议所有东西都塞进一个 tmux session。最好按用途拆开。

tmux new -s codex     # AI 编程主会话
tmux new -s dev       # 普通开发会话
tmux new -s server    # 服务运行和日志
tmux new -s blog      # 博客写作/预览

查看当前有哪些会话:

tmux ls

进入某个会话:

tmux a -t codex

杀掉一个会话:

tmux kill-session -t codex

如果只记一条,我建议记这个命名习惯:

tmux new -s <项目名或任务名>

比如:

tmux new -s money-eval
tmux new -s cody
tmux new -s blog

tmux 里面怎么分屏

tmux 的默认前缀键是:

Ctrl+b

先按 Ctrl+b,松开,再按后面的键。

操作 快捷键
退出但保留会话 Ctrl+b 然后 d
新建窗口 Ctrl+b 然后 c
下一个窗口 Ctrl+b 然后 n
上一个窗口 Ctrl+b 然后 p
左右分屏 Ctrl+b 然后 %
上下分屏 Ctrl+b 然后 "
切换 pane Ctrl+b 然后方向键
关闭当前 pane 输入 exit

我比较常用的布局是:

window: codex
  左边:codex 主对话
  右上:git diff / git status
  右下:测试命令 / 日志

这样 AI 改代码、我看 diff、跑测试,三个动作在一个窗口里完成。


推荐组合一:Ghostty + SSH + tmux + Codex

这是我现在最推荐的 AI 编程组合。

ssh n37
tmux new -s codex
codex

如果已经有会话:

tmux a -t codex

退出时不要直接关窗口,先 detach:

Ctrl+b,然后 d

这样 Codex 还在远程机器里。

适合的场景:

  • 让 Codex 长时间读代码;
  • 让 Codex 改一批文件;
  • 本地网络不稳定;
  • 在手机上临时接回任务;
  • 一边跑测试,一边让 Codex 继续分析。

推荐组合二:tmux + code-server

如果远程机器上跑 code-server,也建议放到 tmux 里:

tmux new -s code-server
code-server --host 0.0.0.0 --port 8080

或者更保守一点,只监听本地地址,然后通过 SSH tunnel 访问:

code-server --host 127.0.0.1 --port 8080

本地开隧道:

ssh -L 8080:127.0.0.1:8080 n37

然后浏览器访问:

http://127.0.0.1:8080

这套方式的好处是:code-server 进程不容易因为 SSH 断开而挂掉。


推荐组合三:手机临时接管远程开发机

手机上操作远程开发机,最怕的不是屏幕小,而是后台被杀、网络切换、连接不稳定。

所以手机端更应该依赖 tmux。

流程是:

手机 SSH App
  -> ssh n37
  -> tmux a -t codex

手机只是一个临时显示器。真正的工作现场在远程 tmux 里。

这样哪怕手机切后台,回来重新 attach 就行。


我会这样配置 alias

每次敲完整命令有点麻烦,可以在远程机器的 ~/.zshrc 里加几个 alias:

alias t='tmux'
alias tls='tmux ls'
alias ta='tmux a -t'
alias tn='tmux new -s'
alias tk='tmux kill-session -t'

之后就可以这样用:

tn codex

ta codex

tls

如果你经常只用一个主会话,也可以加:

alias tcodex='tmux new -A -s codex'

new -A -s 的意思是:

  • 如果 codex 会话不存在,就新建;
  • 如果已经存在,就直接 attach。

以后只要:

tcodex

一个更完整的 tmux 配置

可以在远程机器上创建 ~/.tmux.conf

# 鼠标支持
set -g mouse on

# 历史滚动行数
set -g history-limit 50000

# 从 1 开始编号,更符合直觉
set -g base-index 1
setw -g pane-base-index 1

# 重新加载配置
bind r source-file ~/.tmux.conf \; display-message "tmux config reloaded"

# 更快的快捷键响应
set -sg escape-time 10

改完之后,在 tmux 里按:

Ctrl+b,然后 r

或者执行:

tmux source-file ~/.tmux.conf

什么时候用 systemd,什么时候用 tmux

有些长期服务,比如正式的后台服务,我不建议只放 tmux 里。

可以这样区分:

场景 推荐方式
临时跑 Codex tmux
临时跑测试脚本 tmux
临时看日志 tmux
开发态 code-server tmux 或 systemd user service
长期稳定服务 systemd
机器重启后要自动拉起 systemd

一句话:

tmux 管开发现场,systemd 管正式服务。


常见坑

1. 直接关终端,不知道任务还在不在

如果你在 tmux 里面,直接关本地终端,远程任务通常还在。

重新连上后:

tmux ls
tmux a -t codex

2. 忘了自己在哪个 session

执行:

echo $TMUX

如果有输出,说明你在 tmux 里面。

也可以:

tmux display-message -p '#S'

查看当前 session 名。

3. 嵌套 tmux

有时候你已经在 tmux 里,又 attach 另一个 tmux,会变得很绕。

可以先看:

echo $TMUX

如果已经在 tmux 里,不要再随便 tmux a,可以新建 window 或 pane。

4. 误把 session 退出了

如果你在 tmux 里面一直输入 exit,直到最后一个 shell 也退出,这个 session 就结束了。

如果只是临时离开,要用:

Ctrl+b,然后 d

不是 exit


我的最终工作流

现在我的远程开发基本会收敛成这样:

# 本地 Ghostty
ssh n37

# 远程机器
tmux new -A -s codex

# tmux 里面
codex

旁边再开一个 pane:

git status
git diff

再开一个 pane 跑测试或服务:

make test
# 或者
npm run dev
# 或者
go test ./...

然后离开时:

Ctrl+b,然后 d

回来时:

ssh n37
tmux a -t codex

这套组合的好处不是炫技,而是非常朴素:远程开发现场稳定、可恢复、可接管。

对于 AI 编程尤其重要。因为 AI 工具经常需要长时间读项目、改文件、跑命令,不能因为一次网络抖动就前功尽弃。

所以我的建议是:

本地终端体验交给 Ghostty
远程连接交给 SSH
会话保活交给 tmux
长期服务交给 systemd
AI 编程交给 Codex

把每个工具放在它最擅长的位置,这套远程开发流就会稳定很多。