Cursor SSH 远程连接编辑中途掉线:6 种修复

Cursor 的 SSH Remote 会话在编辑过程中突然断开,丢失 agent 上下文与未保存缓冲区。用对保活参数,并排查 v1.0.51 重连 bug。

你正在远端开发机上用 SSH Remote 和 Composer 重构代码。重构进行到一半,右下角状态栏突然变红:Disconnected from <host>。agent 对话记录消失,一个未保存的缓冲区变灰,重新连接后会拉起一个全新的远程扩展宿主,看不到之前的聊天。这几乎不是 Cursor 本身崩溃,而是底层 SSH 链路死掉了。修复要分三层来做:客户端保活、网络路径稳定性、远端扩展宿主自己的生命周期。

TL;DR——能解决大多数情况的最快修复。 在本地 ~/.ssh/config 对应的 Host 块里加上 ServerAliveInterval 30ServerAliveCountMax 6,然后关掉远程窗口再重开。光这一步就能止住空闲超时导致的掉线——截至 2026 年 6 月,这是最常见的原因。如果是重连后几秒内就断(不是空闲后),并且看到 ssh: Could not resolve hostname 7b22...,那是另一个问题——anysphere.remote-ssh 扩展在 v1.0.51 引入的 bug。这种情况直接看下面的「第 0 步」。

你属于哪一类?

动手之前,先把症状对上原因。不同原因的修复方法差别很大。

症状特征最可能的原因跳到
安静一段后掉线;一直敲键盘从不掉客户端保活太长 / 没设第 1 步
重连瞬间失败;Could not resolve hostname 7b22...remote.ssh v1.0.51+ 十六进制 authority bug第 0 步
掉线和走动、休眠/唤醒、VPN 重连吻合Wi-Fi 漫游 / IP 变化第 5 步
非常规律地掉(约每 90-120 秒空闲一次)服务端 ClientAliveInterval 不匹配第 4 步
dmesg 出现 Killed process ... cursor-server远端扩展宿主 OOM第 3 步
远端 df -h ~ 显示 100%远端 $HOME 磁盘写满第 2 步
uptime 显示机器刚重启机器睡眠 / spot 实例被抢占第 6 步

常见原因

按 SSH Remote 掉线的发生频率排序。

0. anysphere.remote-ssh v1.0.51+ 重连 bug(新增,2026 年 5 月)

这一类根本不是传输层问题。anysphere.remote-ssh 扩展在 v1.0.51(2026 年 5 月 22 日) 加了更严格的 authority 校验,结果在把保存下来的远程 authority 交给 OpenSSH 之前没有做十六进制解码。当你重开一个最近/已保存的远程工作区时,它会拿原始的十六进制字符串去连,而不是 user@host

如何判断:失败发生在重连的一瞬间,而非空闲之后,报错原文就是 ssh: Could not resolve hostname 7b22686f73744e616d65...: nodename nor servname provided。新建的 Connect to Host... 条目能连上;只有恢复已保存工作区时才会坏。截至 2026 年 6 月,Cursor 官方(论坛上的 Colin)已确认是这次校验改动所致,并表示不会恢复对已保存工作区的向后兼容,所以实际可行的办法是降级扩展,或者重新把主机加一遍。

1. SSH 保活间隔太长(或未设置)

NAT 设备、企业代理、云负载均衡器会在一段固定的空闲时间后悄悄回收 TCP 流。企业防火墙最狠,常常 60-300 秒就回收空闲流;托管云 NAT 宽松一些(截至 2026 年 6 月,AWS NAT Gateway 的空闲超时是 350 秒,Azure NAT Gateway 是 4 分钟,Google Cloud NAT 对已建立 TCP 是 20 分钟)。如果你的 ServerAliveInterval 没设、或者大于路径上最短的那个中间盒超时,连接看起来就是死的,会被清掉。

如何判断:掉线总在安静的空闲段之后(你离开座位、agent 在思考)。一直敲键盘就不会断。~/.ssh/config 中没有 ServerAliveInterval

2. Wi-Fi 漫游或 VPN 切换

笔记本在不同 AP 间漫游、VPN 重连、公司网关重新分配 IP——原有的 TCP 连接已经死了,Cursor 的恢复层无法重新绑定。

如何判断:掉线和走动、休眠/唤醒、tailscale status 显示中继切换在时间上吻合。macOS console 日志里掉线时刻能看到 en0: link state change

3. 远端扩展宿主 OOM

远端的 cursor-server 进程撞到 cgroup 或容器内存上限。宿主进程死掉,SSH 连接还短暂存活,随后 Cursor 报告连接丢失。

如何判断:远端 dmesg | tail 看到 Out of memory: Killed process ... cursor-server。或者 ~/.cursor-server/data/logs/<date>/remoteagent.logFATAL 结尾。

4. 远端 $HOME 磁盘写满

Cursor 在 ~/.cursor-server 下写遥测、日志、语言服务器缓存。磁盘满了之后宿主报错退出,看起来就像掉线。

如何判断:远端 df -h ~ 显示 100% 占用。~/.cursor-server/data/logs/ 体积达到几个 GB。

5. 远端机器睡眠 / 自动伸缩把实例回收了

Spot 实例、临时预览环境、合盖的笔记本,都会无预警终止。从内核角度看 SSH 会话是被正常关闭的。

如何判断:重连后 uptime 显示机器刚重启过。云控制台显示实例被替换或抢占了。

6. 服务端 ClientAliveInterval 与客户端不匹配

如果远端 sshd_config 设置了 ClientAliveInterval 30ClientAliveCountMax 3,那么单向沉默 90 秒后服务端就把客户端踢掉——即使客户端自己以为一切正常。

如何判断:掉线非常规律(总是大约 90 秒或 120 秒空闲后)。远端 /var/log/auth.log 里有 Timeout, client not responding

开始之前

  • 留意掉线是时间相关(总在某分钟数)还是随机:规律的指向超时,随机的指向网络或 OOM。
  • 把状态栏报错原文和时间戳记下来。
  • 在终端用最朴素的 ssh <host> 维持同样空闲量,确认是否也会断;如果会,问题完全在 SSH 传输层,与 Cursor 无关。
  • 改任何东西之前,先记下当前 ~/.ssh/config 的保活设置。

需要收集的信息

  • ssh -v <host> 的前 10 行输出(能看出加载的是哪个 config 与身份)。
  • 开发机对应的 ~/.ssh/config Host 块。
  • 掉线后立刻执行的远端 dmesg | tail -50
  • 远端 df -h ~du -sh ~/.cursor-server
  • 远端 ~/.cursor-server/data/logs/<最新>/remoteagent.log 的尾部。
  • 当前是 Wi-Fi 还是有线、路径上是否经过 VPN/零信任代理。

分步修复

按代价从低到高。

第 0 步:排除 v1.0.51 重连 bug

仅当你重连瞬间看到 ssh: Could not resolve hostname 7b22... 时才相关。先确认扩展版本:打开扩展面板(Cmd/Ctrl+Shift+X),搜索 Remote - SSH,看 anysphere.remote-ssh 的版本号。如果是 1.0.51 或更高,你有两个选择。

快速做法——不要恢复已保存的工作区,而是重新加一遍主机。Cmd+Shift+P -> Remote-SSH: Connect to Host... -> + Add New SSH Host...,重新输入 ssh user@host 再连。新建的条目能正确解码;只有存下来的 authority 是坏的。代价是丢掉那个工作区已保存的远程聊天记录。

长久做法——降级到 1.0.50 并阻止它自动更新。在扩展面板点 Remote - SSH 上的齿轮 -> Install Specific Version...,选 1.0.50。然后关掉自动更新,免得它又悄悄升回去:打开设置(Cmd/Ctrl+,),搜索 extensions.autoUpdate,把 Extensions: Auto Update 设为 None(或者右键这个扩展 -> Auto Update,只对它单独关闭)。重载窗口。截至 2026 年 6 月,这是唯一能让已保存工作区继续正常重连的修复。

第 1 步:在 ~/.ssh/config 启用客户端保活

新增或修改 Host 块:

Host devbox
  HostName 10.0.0.42
  User you
  ServerAliveInterval 30
  ServerAliveCountMax 6
  TCPKeepAlive yes

ServerAliveInterval 30 每 30 秒发一次保活,稳稳低于路径上任何一个中间盒的超时——哪怕是 60 秒就回收空闲流的严苛企业 NAT。ServerAliveCountMax 6 表示连续丢失 6 次(共 3 分钟)SSH 才判死,能容忍短暂的 Wi-Fi 抖动。改完后要把 Cursor 的 Remote 窗口关掉重开——SSH 配置是新建连接时读取的,不会热更新。

第 2 步:把远端 server 安装挪到 home 之外的卷上

如果 df -h ~ 显示空间紧张,最干净的办法是把整个远端 server 目录搬到更大的卷上。Cursor 沿用了 VS Code 的 remote.SSH.serverInstallPath 设置:打开设置(Cmd/Ctrl+,),搜索 remote.SSH.serverInstallPath,给主机映射一个空间充足的路径,例如:

"remote.SSH.serverInstallPath": {
  "devbox": "/var/tmp"
}

之后下一次连接时,Cursor 就会把 server 装到那个目录下(例如 /var/tmp/.cursor-server),不再放在 ~。改完后要么删掉旧的 ~/.cursor-server,要么单独清理体积大的日志:

find ~/.cursor-server/data/logs -mtime +7 -delete

这一步直接杜绝原因 #4,通常还能省下好几 GB。注意:remote.SSH.serverInstallPath 只决定 server 装在哪里,不会把已有数据搬过去,所以要先设好再重连。

第 3 步:提高远端扩展宿主的内存上限

如果 dmesg 显示 OOM kill,说明 cursor-server 的 Node 进程需要更大堆。修改远端的 shell rc:

echo 'export NODE_OPTIONS="--max-old-space-size=4096"' >> ~/.bashrc

然后杀掉正在运行的服务,让它带着新环境变量重启:

pkill -f cursor-server

下次连接时 Cursor 会拉起一个新的远端宿主。仓库超过 10 万文件时,8192 更现实。

第 4 步:服务端加一个与客户端对称的保活

在远端编辑 /etc/ssh/sshd_config(如果 sshd 支持用户级配置目录,也可以用 ~/.ssh/sshd_config.d/):

ClientAliveInterval 30
ClientAliveCountMax 6

重载 sshd:

sudo systemctl reload sshd

两边保活间隔对齐,能避免”服务端不耐烦地踢掉了一个自认为健康的客户端”这种情况。

第 5 步:网络很差时换用更稳的传输

对于不稳的 Wi-Fi 或频繁切换的 VPN,moshtailscale ssh 能挺过 IP 变化:

brew install mosh

Cursor 自己不支持 mosh,但底层连接可以套一层稳定隧道:

tailscale up
ssh -o ProxyCommand="tailscale nc %h %p" devbox

或者直接用 Cursor 自带的 Tunnels 替代裸 SSH——它在 IP 变化时会自动重连。

如果是重连本身卡在 Opening Remote...(链路慢),把 remote.SSH.connectTimeout 调大(设置里搜 remote.SSH.connectTimeout,默认 15 秒)到 60,免得 server 安装慢的时候握手被提前中止。如果自带的 anysphere.remote-ssh 实在反复出问题,社区的 open-remote-ssh 是不少人偏好的替代扩展:

cursor --install-extension jeanp413.open-remote-ssh

第 6 步:把远端当作随时可丢的,状态显式持久化

如果开发机是 spot/可抢占实例,重要的东西就别只放在机器上:

# 远端 cron,每 5 分钟把未提交的工作推到 wip 分支
*/5 * * * * cd ~/proj && git add -A && git commit -m "wip" --allow-empty && git push origin HEAD:wip-$(hostname)

配合 Cursor 的 Chats: Persist Remote History,agent 对话会同步到本地账户。这样掉线不再损失任何东西。

验证

  • 打开 Cursor 远程窗口,闲置 10 分钟再回来,状态栏依然绿色。
  • 跑一个故意很长的 agent 任务(大型重构),逐轮观察——中间不再断流。
  • 真实的网络抖动后(手动关 Wi-Fi 5 秒),底栏应在 30 秒内重连,打开的编辑器不丢。
  • 如果碰到的是 v1.0.51 bug:确认扩展面板里 anysphere.remote-ssh 显示为 1.0.50,再重开之前打不开的那个已保存工作区——它应该连到 user@host,而不是一串十六进制。

长期预防

  • 团队统一推送一份 ~/.ssh/config 模板,里面预置 ServerAliveInterval 30
  • 开发机至少 8 GB 内存,日志/缓存卷与 $HOME 分开。
  • 每天一个 cron,清理 7 天前的 ~/.cursor-server/data/logs
  • 笔记本到云端的连接优先用 Tailscale 或 Cursor Tunnels,而不是裸 SSH。
  • spot 实例必须有自动 wip 分支推送。
  • 在开发机 bootstrap 脚本里监控 dmesg 与磁盘占用,在机器死掉之前就告警。
  • 一旦确定了一个能用的 anysphere.remote-ssh 版本,就把 extensions.autoUpdate 设为 None,免得以后某个版本又悄悄把重连 bug 带回来。

常见误区

  • 觉得”少说话更省”,把 ServerAliveInterval 调到 300——多数企业 NAT 在 120 秒就回收空闲流,最严苛的 60 秒就回收。
  • Cursor 还开着 Remote 窗口时去改 ~/.ssh/config:要等下一次新建连接才生效。
  • 默认 agent 对话保存在服务端:实际默认是本地,远端崩 + 本地缓存过期就丢了。
  • 一边编辑一边 pkill cursor-server:缓冲区会变灰,未保存的修改全部消失。先保存。
  • 在裸终端 ssh devbox 也按相同周期断开,却继续怪 Cursor。
  • 忽视 ~/.cursor-server/data/logs/ 长到几十 GB。

常见问题

Q:我一重连就看到 ssh: Could not resolve hostname 7b22...,这是什么?

那串十六进制是你编码后的 SSH authority 原封不动漏了出来——这是 anysphere.remote-ssh v1.0.51(2026 年 5 月 22 日)引入的 bug,只在恢复已保存/最近的远程工作区时触发。要么用 Remote-SSH: Connect to Host... 重新加一遍主机,要么把扩展降级到 1.0.50 并把 extensions.autoUpdate 设为 None。详见第 0 步。

Q:Cursor 重连后 agent 把之前的事都忘了,怎么保住聊天?

设置里启用 Chats: Persist Remote History,对话会同步到本地账户,远端宿主重启也能继续。可同时参考Cursor 重启后聊天历史丢失

Q:我改了 SSH 配置但没生效。

Cursor 只在新建远程窗口时读 ~/.ssh/config。“Reload Window”不够,要先”Remote: Close Remote Connection”再重新连接。

Q:在远端开一个常驻 screen/tmux 有用吗?

对 Cursor 本身没用——远端扩展宿主是独立进程,和你的 shell 无关。但远端终端窗口在 tmux 里跑仍然有价值,作为扩展宿主重启时的兜底。

Q:能直接用 mosh 吗?

不能,Cursor 的 Remote-SSH 只走标准 SSH。mosh 用来开一个独立终端;IDE 本身建议走 Tailscale 或 Cursor Tunnels。

相关阅读

标签: #Cursor #排查 #排查 #AI 编程