我的移动办公 vibe coding
现在大部分编码任务我都是丢给 Claude Code 或者 Codex 去做。一句话把需求说清楚,它自己读文件、改代码、跑测试、修报错,中间会停下来问几次,剩下的时间我基本只是等结果。人干的活变成了按几个确认键,加最后看一眼它到底改成了什么样。
这件事改变的不只是效率。以前要干活必须坐在那台机器前面,现在只要能看到那个终端、能按那个 y/n 就行。位置没那么重要了,重要的是那个会话还活着。

手机上都在干什么
出门前把任务挂上,通常是一句「把 user 模块的参数校验抽出来,测试跑绿了再告诉我」。然后关掉终端,人走开。地铁里掏出手机看一眼,它正停在一个 diff 确认上,点一下回车,继续往下跑。到站的时候事情已经做完了。
晚上躺床上是另一种。睡前让它跑一遍全量测试,或者把一批 lint 报错清掉,手机放枕头边上,困了就不看了。第二天早上翻一下它昨晚做了什么,哪一步没跑通,补一句话让它重来。
出差只带一台平板也是这套。机器留在家里开着,连回去,里面该跑的还在跑,接着刚才那条命令往下说就行。
这三个场景对带宽的要求都不高,但有一条是共同的,人不在机器前面,而那个进程得一直活着。普通 SSH 恰恰做不到这一点,手机锁屏、切一次网、进一次隧道,连接断了,终端里的进程跟着收到 SIGHUP,之前跑的那半小时一起没。
移动办公方案
这套方案不用自己写代码,也不用买什么设备,装几个现成的软件就能跑起来。电脑上四样,tmux、mosh、openssh-server、tailscale。手机上装 Tailscale 的 App,再装一个能连 SSH 的终端 App。
openssh-server 让这台电脑可以被远程登录。SSH 是最老资格的远程终端协议,你能在一个终端里操作另一台机器,靠的都是它,mosh 的第一次认证也得走它,所以这个必须装着。
tmux 是个终端复用器,说白了就是让程序跑在后台,你把窗口关了它也不死。它把 shell 塞进一个服务端进程,你连上去的只是一个客户端,客户端掉了服务端照跑。手机上看到的画面和电脑上那条终端是同一条,不是另开一个。它只管进程存活,网络通不通跟它没关系。
mosh 是 mobile shell 的缩写,定位是 SSH 的移动网络版本。起手还是 SSH,认证完切到 UDP,之后自己维护状态和屏幕内容。断网再连上不是重新协商一整个会话,而是把中间缺的那几帧补回来。手机在 4G 和 WiFi 之间来回切,普通 SSH 基本每次都要重新握手,mosh 通常只是卡一下。代价是服务端要占住 UDP 60000 到 61000,这个后面防火墙得放行,很多人栽在这里。
Tailscale 是一个不需要公网 IP 的虚拟内网,底层跑的是 WireGuard。登录同一个账号的设备之间直接能通,每台机器拿一个 100.64/10 段的地址,手机打开 App 就等于接进了同一个局域网。SSH 只监听在这张虚拟网卡上,公网扫不到 22 端口。以前那套 frp 加端口映射的方案可以收起来了。
用户名、账号和休眠
- 电脑的登录用户名,以及密码或者一把 SSH 公钥
- 同一个 Tailscale 账号,手机和电脑必须是一个,个人版免费额度够用到没感觉
- 关掉自动休眠。这一条比装什么都重要,电脑一睡,前面的配置全白费
Ubuntu 和 Debian
桌面版 Ubuntu 默认不带 SSH 服务,openssh-server 要自己装。
| |
Tailscale 用官方脚本装最省事,它会自己认发行版。
| |
tailscale up 会打出一个登录链接,复制到浏览器里登录,这台机器就进网了。然后看它的内网地址。
| |
出来的 100.x.x.x 记下来,手机连的就是它。开了 ufw 的话把这张虚拟网卡放行,不用去碰公网规则。
| |
CentOS 和 Rocky Linux
CentOS 7 和 8 都已经 EOL,仓库还挂着但不再更新,新机器建议直接上 Rocky Linux 9 或者 AlmaLinux 9。下面的命令在 CentOS 7、CentOS Stream、Rocky、Alma 上都能跑,区别只在 Tailscale 的仓库路径要按系统大版本换。
mosh 不在标准源里,得先开 EPEL。
| |
CentOS 7 上把 dnf 换成 yum,其余一样。最小化安装一般没带 curl,所以上面顺手一起装了。
Tailscale 走官方 yum 源,URL 里的路径按大版本选。
| |
CentOS 7 用 https://pkgs.tailscale.com/stable/centos/7/tailscale.repo,CentOS 8 用 centos/8,只换路径。装完同样是 tailscale ip -4 拿地址。
真正跟 Ubuntu 不一样的是防火墙。firewalld 默认拦进来的包,mosh 的 UDP 段过不去,最省事的做法是把 tailscale0 整张网卡丢进 trusted 区域,从这张网卡进来的流量不再过滤。
| |
不想动 trusted 区域,就至少把 UDP 60000 到 61000 单独放行,具体到 --add-port=60000-61000/udp。漏了这一步的表现很好认,客户端会打出 Nothing received from server on UDP port 60000,然后悄悄退回普通 SSH,看着像连上了其实没用上 mosh。SELinux 一般不用动,别顺手把它关了。
macOS
Homebrew 装两个包,openssh 不用装,系统自带。
| |
SSH 服务默认是关的。系统设置 → 通用 → 共享 → 远程登录,打开开关,右边把允许访问的用户限定成你自己那个账号,别留「所有用户」。macOS 12 及以前这一步在系统偏好设置 → 共享 → 远程登录。
Tailscale 在 macOS 上有两个完全不同的装法,别搞混。
图形版走官网 dmg 或者 brew install --cask tailscale,装完是菜单栏图标,登录后点菜单就能看到本机 100.x 地址。它自带的命令行不在 PATH 里,要用绝对路径调用 /Applications/Tailscale.app/Contents/MacOS/Tailscale status。我图省事建了个软链过去。
| |
命令行版是 brew install tailscale,装的是 tailscaled,按官方的说法用 sudo brew services start tailscale 起服务,没有菜单栏图标。不想要菜单栏多一个东西就走这个,代价是偶尔要自己看一眼服务状态。
macOS 上最容易卡住的不是防火墙,是 PATH。Homebrew 在 Apple Silicon 上装到 /opt/homebrew,sshd 给非登录 shell 的 PATH 里没有这个目录,认证能过,mosh-server 却起不来。
手机上点 mosh 连接,终端报
mosh-server: not found,就是这个问题。软链到/usr/local/bin就行,那个目录在 sshd 默认PATH里。
| |
Intel 的 Mac 上 brew 装在 /usr/local,一般不会碰上这一条。
还有休眠。笔记本合盖就睡,软件层拦不住,caffeinate 只能管住「别自动睡」,管不了合盖那一下。
| |
真要长时间挂着任务,要么接一台外接显示器让机器进入合盖不睡的状态,要么就把盖子开着。这个没有更干净的办法。
Windows
Windows 上没有原生的 tmux,msys2 那套移植版常年有怪毛病,所以这条路是把 WSL2 开起来,tmux、mosh 和 Claude Code 全塞进那个 Ubuntu 里,Windows 只负责跑 Tailscale 和当宿主机。
装 WSL2 和 Ubuntu
Windows 11 或者 Windows 10 的 2004 以后版本,一条命令就够,它会自己去打开虚拟化和需要的组件,装完重启。
| |
第一次启动要设 Linux 用户名和密码,这个用户名后面手机登录要用,别顺手打个 root。
在 WSL 里装那三样
进 Ubuntu 之后,跟前面 Ubuntu 那节一模一样。
| |
systemctl 报 System has not been booted with systemd 的话,是这套 WSL 没开 systemd。在 Windows 用户目录建 C:\Users\你的名字\.wslconfig,写上
| |
然后 wsl --shutdown 再进去。新装的环境一般已经默认开了,只有从旧系统迁过来的才会碰到。
Claude Code 和 Codex 也装在这个 Ubuntu 里,别装在 Windows 那边。任务跑在 tmux 里,agent 的工作目录、依赖、Node 版本全在同一个环境,省得两边对不上账。
Tailscale 和 WSL 的网
Windows 版 Tailscale 从官网下 msi,或者
| |
装完登录同一个账号,托盘菜单里能看到本机的 100.x 地址。麻烦的地方在后面,WSL2 默认躲在一层 NAT 后面,Windows 自己能访问它,从外面进来的包到不了。
Windows 11 22H2 以后有个干净的解法,在 .wslconfig 里打开镜像网络,WSL 直接共用 Windows 的网卡,Tailscale 那个 100.x 地址在 WSL 里也能用。
| |
wsl --shutdown 重进,在 WSL 里 ip addr 看有没有 tailscale0。看得到就齐了,手机连 100.x 的 22 端口,mosh 的 UDP 段也跟着通。防火墙这一侧补一条规则,省得包被静默丢弃。
| |
Windows 10 没有镜像网络这个选项。常见的土办法是用 netsh interface portproxy 把 22 端口转到 WSL 的内网地址,但 portproxy 只转 TCP,mosh 走的 UDP 转不过去,所以 Windows 10 上只能退一步用普通 SSH 加 tmux,会话照样不断,代价是切网要重连。在 WSL 里单独再装一份 Tailscale 也许能绕过去,这条路我没跑通,先不下结论。
防睡眠
Windows 默认也会睡,笔记本合盖更是直接睡。设置 → 系统 → 电源和电池,把「使设备进入睡眠状态」在插电时改成「从不」;合盖的行为在控制面板 → 电源选项 → 选择关闭盖子的功能里,改成「不采取任何操作」。
手机端
Tailscale app 装好,登录同一个账号,开着就行,直连还是走中继它自己判断。
终端 App 挑一个。Android 上用 Termius 或者 JuiceSSH,Termius 的界面好看一些。iOS 上装 Blink Shell,它对 mosh 的支持比 Termius 完整,移动网络下的表现也稳。
新建连接的时候填四个东西,Host 是刚才那个 100.x.x.x,端口 22,用户名是电脑上的账号,认证先拿密码跑通,通了再换密钥。协议选 mosh,别用默认的 SSH,不然前面装的服务端白装。
Claude Code 那个界面在手机上的主要问题是列宽。默认字号下它那几栏信息会折行折得很难看,换成等宽字体,字号压到 10 到 11,横屏使用,看起来就正常了。Termius 里把键盘常驻打开,不然每次点输入框都要弹一遍。
每天的用法
电脑上开会话,命令里的 -A 表示会话已经存在就直接接上,不存在才新建,比每次先 tmux ls 看一眼再决定 attach 要省事。
| |
手机上连上之后,列一下再进去。
| |
手机端脱离一样是 Ctrl+b 再按 d,Blink 和 Termius 都支持把 Ctrl 组合键映射到工具栏上,不用外接键盘也按得出来。
用完不收拾的会话会一直挂着占内存,定期清一下。
| |
容易卡住的地方
tmux attach -s xxx 会报 unknown flag -s。-s 是给 new-session 起名字用的,指定 attach 的目标要用 -t。这条错在中文教程里非常常见,照抄过来在 tmux 3.x 上直接报错。
CentOS 上 mosh 连不通,先看 firewalld,再看 EPEL 装没装。表现是客户端打出 Nothing received from server on UDP port 60000 然后退回 SSH,不报错不提示,很容易误判成连上了。
macOS 上 mosh-server not found,就是上面那条 PATH 的问题,软链一下就好。
Windows 上最迷惑的一种情况是 Windows 自己能连、手机连不上。多半是 WSL 还躲在 NAT 后面,.wslconfig 里没开 networkingMode=mirrored,100.x 那个地址只在 Windows 那一层有效。先在 WSL 里 ip addr 看有没有 tailscale0,没有就是这件事。
过一晚回来看会话没了,九成是电脑睡了或者重启了。tmux 会话不跨重启,这个是设计如此,不是配置错。
手机连不上但两边 tailscale status 都显示在线,去看电脑上的监听地址,ss -lntp | grep :22。只监听 127.0.0.1 的话手机永远连不上,得让它监听 0.0.0.0 或者那个 100.x 地址。
安全
SSH 只走 tailnet,22 端口不做任何公网映射,这一条守住就避掉了绝大部分爆破。
tailnet 内部用密码登录问题不大,但手机丢了等于全家丢了,所以还是建议换成密钥,然后关掉密码认证。Tailscale 后台的 ACL 能限定哪个账号连哪台机器,多人共用一个 tailnet 的时候值得配一下,这块我没有细调过,先记在这儿。
最后说几句
会写代码的人用这套,省掉的是「必须守在电脑前」那段时间。任务丢给它,出门,路上批两次确认,回来收结果。写卡住了下楼转一圈,回来它已经把测试跑完,红的地方还列了原因。
不写代码的人其实更能用上。Claude Code、Codex 这类东西不要求你会语法,把要做的事说清楚就行,改一批文案、把几百个文件按规则改名、从几个表格里拼一份汇总,它自己动手,你只在它问「这样改行不行」的时候回一句。配上这套远程连接,手边那台平板就是工作台,不必是那台装着环境的电脑。少了「你得先学会装环境」这道门槛,移动办公才轮到那些本来不写代码的人。
