← 全部文章

手机 SSH 不断线:mosh 与 tmux 配置指南

手机上 SSH 断线,要分两件事解决:tmux 让程序在服务器上继续运行,断线后重新附着就能回到原来的界面;mosh 用 UDP 代替 TCP 传输终端,手机换 IP、锁屏几分钟回来都不用重新登录。只装 tmux,任务不会丢,但每次断线要重新连一次;两个都装,体验最接近“从没断过”。

本文按 mosh 1.4.0、tmux 3.x 核对,命令以 Ubuntu / Debian 为例。

为什么手机上 SSH 总断

  • 换网络:SSH 跑在 TCP 上,一条连接绑定手机当时的 IP。从 Wi-Fi 走到蜂窝网络,IP 一变,连接就失效了。
  • 锁屏和后台:iPhone 会在应用进入后台后很快暂停它的网络;Android 的省电策略也会冻结后台应用。连接空闲太久,中间的 NAT 或防火墙还会悄悄丢掉它。
  • 程序跟着连接一起结束:在普通 SSH 里直接运行的程序,是这条连接的子进程。连接断了,服务器发出 SIGHUP,程序通常随之退出。

前两条是连接的问题,mosh 解决;第三条是进程的问题,tmux 解决。

第一步:用 tmux 保住任务

sudo apt install tmux

每次登录后都进同一个会话,有就附着,没有就新建:

tmux new -A -s main

在里面运行编译、测试或 AI Agent。断线后重新登录,再执行同一条命令,就回到断开前的屏幕。想主动离开、让任务继续跑,按 Ctrl+B 再按 D。

适合手机的 tmux 设置

写入 ~/.tmux.conf,然后运行 tmux source ~/.tmux.conf 生效:

set -g mouse on              # 手指上下滑动滚动 tmux 的历史
set -g history-limit 50000   # 多留一些历史,Agent 的输出很长
set -g status off            # 手机屏幕小,不要状态栏(需要时再打开)
set -s escape-time 10        # 按 Esc 不延迟,Claude Code 等 TUI 更跟手

登录后自动进入 tmux

只想从手机登录时自动进入,可以在手机端的 SSH 客户端里把“登录后执行的命令”设成 tmux new -A -s main。不建议在 ~/.bashrc 里无条件启动 tmux,会影响 scp、rsync 和电脑上的登录。

第二步:用 mosh 跟着手机换网络

mosh 先用一次普通 SSH 登录,在服务器上启动 mosh-server,之后终端改走加密的 UDP。客户端每隔几秒发一次心跳,服务器总是把数据回给最近一次收到合法数据包的地址,所以手机换了 IP 也能继续,不用重新登录。网速慢时,mosh 会先在本地显示你输入的字符(带下划线),不用等服务器回显。mosh 为什么换网络不断线,原理见图解 mosh。

服务器配置

# Ubuntu / Debian
sudo apt install mosh

# macOS(Homebrew)
brew install mosh

还要放行 UDP 端口。mosh 从 60001 开始找空闲端口,同时连接的会话不多时,放行一小段就够了:

# ufw
sudo ufw allow 60000:61000/udp

云服务器还要在安全组里放行同样的 UDP 端口。服务器在家里的路由器后面时,与其在路由器上做端口转发,不如用 Tailscale:手机和服务器在同一个虚拟内网里,UDP 不用暴露到公网。

两者一起用

mosh 只同步“当前这一屏”,不保留终端自己的滚动历史,回看历史要靠 tmux。命令行客户端可以这样连:

mosh user@server -- tmux new -A -s main

这样一来,换网络和锁屏由 mosh 处理;mosh 也断了(比如手机关机一晚),tmux 里的任务还在,重新连上即可。

别让 mosh-server 越积越多

默认情况下,客户端消失后 mosh-server 会永远等下去,手机上每次“断开”都可能在服务器上留下一个。在服务器的 ~/.bashrc 或 /etc/environment 里设置超时:

export MOSH_SERVER_NETWORK_TMOUT=3600   # 一小时收不到客户端就退出

任务在 tmux 里,mosh-server 退出不影响任务。已经堆积的可以用 pkill -u "$USER" mosh-server 清掉(会断开你自己当前所有的 mosh 连接)。

常见报错

现象原因与处理
mosh-server needs a UTF-8 native locale to run服务器缺 UTF-8 语言环境。运行 sudo locale-gen en_US.UTF-8,或在连接时指定 LANG=C.UTF-8
连不上,提示 Please verify that UDP port 60001 is not firewalled and can reach the server.UDP 不通:检查 ufw、云安全组和路由器;手机上开着代理或 VPN App 时,它可能不转发 UDP
mosh-server: command not found非登录 shell 找不到它,macOS 上常见。用 mosh --server=/opt/homebrew/bin/mosh-server user@host 指定路径
macOS 弹窗询问是否允许 mosh-server 接收连接在系统设置的防火墙里允许它,否则 UDP 进不来
手指滑动不能回看历史mosh 没有滚动历史。在 tmux 里开启 set -g mouse on,或用 Ctrl+B [ 进入复制模式翻页
端口转发、X11、ssh-agent 转发不起作用mosh 不支持这些功能,需要时另开一个普通 SSH 连接

Android 和 iPhone 上的 mosh 客户端

mosh 要求客户端自己实现 mosh 协议,只支持 SSH 的 App 用不了。截至 2026 年 10 月的情况:

客户端平台mosh说明
Blink ShelliPhone、iPad支持mosh 官网列出的 iOS 客户端,命令行风格,适合熟悉终端的人
TermiusAndroid、iPhone、桌面支持图形界面,免费版即可用 mosh;跨设备同步主机需要账号
TermuxAndroid支持手机上的 Linux 环境,pkg install mosh 后用命令行连接
JuiceSSHAndroid支持mosh 官网仍列出它,但 Google Play 上已经找不到,多年没有更新
RoamttyAndroid、iPhone支持自动配合 tmux,详见下一节

Roamtty 怎么做

Roamtty 把上面的步骤做成了默认行为,添加主机时会话模式保持 tmux 即可:

  • 一键安装:主机菜单的“安装插件”用服务器的包管理器装 tmux 和 mosh(Linux 用 apt、dnf、pacman 等并需要 sudo,macOS 用 Homebrew,Windows 用 winget 装 psmux),也能找到 Homebrew、MacPorts 和 snap 装在非标准路径的 mosh-server。
  • mosh 里直接是 tmux:每个会话是服务器上独立的 tmux 会话,mosh-server 启动时就附着进去,开启 tmux 鼠标模式,上下滑动回看的是 tmux 的历史。
  • 自动处理语言环境:依次尝试 en_US.UTF-8 和 C.UTF-8,服务器没生成语言包也能用上 mosh。
  • 自动回退:8 秒收不到 UDP 回应就改走 SSH,并提示可能是 UDP 60000–61000 没放行。
  • 不留残余进程:tmux 模式下 mosh-server 15 分钟收不到手机的数据就退出;手机睡得更久,回来时自动重新登录并附着 tmux。
  • 文件仍走 SSH:终端走 mosh 时,SFTP 文件浏览和上传仍用 SSH,断了会在后台重新登录。

Roamtty 即将开源;iPhone 版已在 App Store 上架(中国大陆区暂未提供),Android 版即将上架 Google Play。配置细节见使用文档;在外面连回家里的服务器,见Tailscale 一节和自建 DERP 中继。

常见问题

问题回答
只用 tmux、不装 mosh 可以吗?可以。任务不会丢,只是每次换网络或锁屏回来都要重新登录一次,通常几秒钟。
只用 mosh、不装 tmux 呢?短时间断网没问题,但 mosh-server 一旦退出(超时、服务器重启、手机关机一晚),里面的程序也随之结束,而且没有滚动历史。建议两个都装。
mosh 安全吗?登录仍走 SSH,之后每个 UDP 数据包都用 AES-128 OCB 加密和认证,密钥通过 SSH 交给客户端。
iPhone 锁屏后 mosh 也会断吗?iOS 会暂停后台应用的网络,mosh 期间收不到数据,但 mosh-server 还在等;解锁回到应用后,mosh 接着同步屏幕,不用重新登录。
mosh 能穿过 Tailscale 吗?能。mosh 走的是普通 UDP,连服务器的 100.x.y.z 地址即可,服务器防火墙要允许 tailscale0 网卡上的这些端口。