Antigravity 的内网 SSH 连接失败,加上手动安装包被误删,两个问题撞一块儿的时候,那感觉就像连续闯了两个红灯还要被贴罚单。我最近在一个隔离项目上就踩了一整套坑:服务器在办公网内部,没有外网出口,Antigravity 远程开发用不了,日志里只有一行 connection failed;想重新装 Remote-SSH 相关组件,却发现本来准备好的离线安装包被系统的临时目录清理程序删掉了。折腾了将近一天,最终把问题完整定位并解决。下面这套方法我已经在真实内网环境里验证过,直接照着操作就行。
1. 先把问题拆清楚:Antigravity 在内网/离线环境下的典型坑
1.1 Antigravity 是什么,为什么会在内网用到
Antigravity 不是杀毒软件,它是面向开发者的智能远程开发环境。你可以在上面打开远程主机上的工程代码,像操作本地项目一样完成编辑、编译、调试,同时它还集成了不少需要在线拉取依赖的功能模块,比如语言服务器、代码补全引擎和插件市场。这种工具在办公内网、生产隔离区、科研机房这些环境里其实非常常见,因为代码和数据不能出内网,但开发者又不想把整个工作流搬回本地终端。
正因为要连远程服务器,SSH 就成了它的生命线。所有远程文件操作、命令执行和调试,本质上都是通过 SSH 通道完成的。我在实际使用中发现,Antigravity 对 SSH 配置的要求比普通终端稍微严格一点:如果你用命令行能连上,但 Antigravity 连不上,问题多半出在 SSH 配置文件、密钥加载方式或者远程插件初始化这几个环节上。定位的时候,不能只看最终报错,要把客户端的连接过程和服务端的日志结合起来看。
1.2 内网/离线环境下的特殊约束
在内网环境里,情况会复杂不少。第一,目标服务器可能没有外网访问能力,Antigravity 首次启动时需要登录激活或拉取远程组件,一旦连不上外网,就会一直卡在初始化阶段。第二,公网 DNS 解析不了内网主机名,SSH 连接可能出现超时或者连接后立刻断开。第三,内网安全策略往往会限制端口扫描和额外端口,某些应用层协议也可能被拦截,如果只开放了 80/443,SSH 默认的 22 端口被禁也相当常见。
还有一个容易被忽略的问题:内网环境里不会有自动化的组件缓存。你在有网环境里正常安装 Antigravity,插件是从远端仓库自动下的;到了内网,这个远端仓库不可达,唯一的办法就是提前把安装包手动拷贝进去。而手动安装包一旦被误删,又没有外网可以重新下载,事情就会迅速升级成“生产事故”。所以每次在内网装新环境,我都会先把所有依赖提前准备好,并把它们像弹药库一样管理起来,避免临时抓瞎。
1.3 为什么“SSH 连接失败”和“安装包被误删”总是一起出现
这两个问题看似独立,实际在排障流程里经常会撞到一起。因为 SSH 连接不上,第一反应往往是重装插件或修复客户端组件;于是你四处找一个能用的离线安装包,把它拷到 /tmp 或用户目录下的临时文件夹里,准备解压或者手动安装。这时候如果系统有定时清理任务,或者你自己顺手清理过临时文件,安装包就没了。接下来你一边怀疑 SSH 配置,一边又找不到安装包,等于卡在两个问题的交叉点上。
所以我的建议是,排障之前先把所有安装包和备份文件放到一个固定目录,比如 /opt/offline_packages,不要随手丢在临时目录里。这样即使 SSH 问题要花很长时间,至少不会因为包丢失再添一道麻烦。下面我先讲 SSH 问题的排查,再讲安装包丢失怎么处理。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SSH 连接失败的内网环境排查路线
2.1 从客户端到服务端,按链路逐段确认
遇到 SSH 连接失败,我习惯按“网络通不通、端口通不通、服务跑没跑、认证过没过、会话能不能建立”的顺序一层层往下查。这一步虽然基础,但能帮你把问题范围缩小一大半。下面是一个我常用的检查清单,你可以直接复制到终端里执行。
| 检查项目 | 命令示例 | 预期结果 | 失败时可能的原因 |
|---|---|---|---|
| 网络连通性 | ping 192.168.10.20 |
有 ICMP 回包 | 网线/网卡/不在同一网段 |
| 端口连通性 | nc -zv 192.168.10.20 22 |
显示 open | 防火墙拦截或 SSH 端口被改 |
| 服务状态 | systemctl status sshd |
显示 active (running) | sshd 未启动或启动失败 |
| 认证结果 | ssh -vvv user@192.168.10.20 |
出现 Authentication succeeded | 密钥权限/公钥未配置/密码错误 |
| 会话建立 | ssh user@192.168.10.20 'hostname' |
输出主机名 | shell 初始化脚本导致断开 |
在实际排查中,我强烈建议先加一个超时参数再测:ssh -o ConnectTimeout=10 -o ServerAliveInterval=5 user@192.168.10.20。内网环境有时会出现很久才超时的情况,看起来像是卡死,其实是网络包被静默丢弃。加了 ConnectTimeout,十秒后就会明确报错,省得一直等。我遇到过同事用默认参数连内网机器,卡了五分钟都没反应,结果加超时参数后五秒就报 Connection timed out,一下子就确认是网络层问题,不用再去翻 SSH 配置。
2.2 配置文件与密钥权限的常见坑
如果端口没问题,服务也正常,那就重点看认证环节。最常见的坑有三个:
第一,客户端私钥权限太宽。SSH 对 ~/.ssh 目录和私钥文件权限有严格要求,私钥权限如果是 644 甚至 777,很多 SSH 客户端会直接拒绝使用。修复办法很简单:chmod 700 ~/.ssh,chmod 600 ~/.ssh/id_rsa。
第二,服务端 authorized_keys 文件权限不对,或者公钥内容没配好。服务端需要把客户端的公钥追加到 /home/<user>/.ssh/authorized_keys,然后执行 chmod 700 ~/.ssh、chmod 600 ~/.ssh/authorized_keys。如果文件属主不是当前用户,SSH 也会不读取它。
第三,sshd_config 里的认证项目禁用了你正在用的方式。比如你只用了公钥登录,但配置里写着 PubkeyAuthentication no,那就是完全不认你的钥匙。建议在服务器上打开 /etc/ssh/sshd_config,重点检查这几项:PubkeyAuthentication yes、PasswordAuthentication(如果你要用密码就设 yes)、PermitRootLogin(内网实验环境可以设 yes,生产环境建议 prohibit-password)、AllowUsers(如果设置了白名单,确认你的账号在名单里)。
每次改完 sshd_config,先执行 sshd -t 检查语法,再重启服务。我踩过几次坑,改完直接 systemctl restart sshd,结果配置文件里一个多余的空格导致服务起不来,反而把自己锁在门外。sshd -t 真的能救命。另外,改配置前一定要备份,哪怕只是 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak,几秒钟时间就能避免后续回滚困难。
2.3 内网环境下的 SSH 超时与 DNS 问题
内网里最诡异的一类问题是“客户端明明能连通端口,但 SSH 连接建立后马上断开,或者要卡很久才提示超时”。我遇到过几个典型原因:
第一是 SSH 服务端默认 UseDNS yes。这时服务端会尝试用客户端的 IP 做反向 DNS 解析,内网没有 DNS,解析就会超时。解决办法是在 sshd_config 里加一行 UseDNS no,重启服务,连接速度会立刻提升。很多时候这个配置加上后,原来要等半分钟的连接变成秒连。
第二是客户端和服务端都在内网,但客户端配置里用的是主机名,而内网 DNS 解析不到。可以在两端 /etc/hosts 文件里手动加上主机名和 IP 映射,或者 SSH 命令直接用 IP。在 Antigravity 的 SSH 配置文件里,也尽量填写内网 IP,减少主机名解析带来的不确定性。
第三是 SSH 长时间不操作后掉线。这类问题通常优化两端保活参数。服务端设置 ClientAliveInterval 60 和 ClientAliveCountMax 3,客户端在 ~/.ssh/config 或命令行加 ServerAliveInterval 60、ServerAliveCountMax 3,基本能解决。我在远程调试时特别依赖这两个参数,不然写一会儿代码切回来看屏幕,SSH 已经断开了。
2.4 Antigravity 侧的特殊设置
如果你用命令行能连上,但 Antigravity 连不上,就要看它的 Remote-SSH 扩展配置了。Antigravity 默认会读取 ~/.ssh/config 里定义的 Host 信息,所以建议在 ~/.ssh/config 里写清楚目标主机配置,而不是直接在连接框里输入 user@ip:port。一个简单的配置示例:
sshconfig复制Host dev-server
HostName 192.168.10.20
User devuser
Port 22
IdentityFile ~/.ssh/id_rsa
ServerAliveInterval 60
ServerAliveCountMax 3
写完 ssh dev-server 确认本地 CLI 能连上,再到 Antigravity 里连接这个 Host。如果还是不行,打开 Antigravity 的“输出”面板,切换到 Remote-SSH 日志,通常会看到具体是在哪一步失败的,比如私钥路径错误、远程主机缺少某个 Python 环境,或者远程端扩展安装被中断。内网环境尤其容易出现远程端组件下载失败,这时候就要用到下面说的离线安装包方案。
3. 手动安装包被误删后的恢复思路
3.1 误删之后不要慌,先确认包是否真的丢失
很多人一发现安装包没了,第一反应就是到处找同事拷。实际上,先花十分钟确认包是不是真丢了,能省很多事。我遇到过一次,同事的安装包其实就在共享目录里,只是他找错了子目录;还有一次是系统清理工具把文件移动到了回收站,从回收站恢复后校验值完全对得上。
我的排查顺序是:先查用户的回收站或影子副本(如果内网 Windows 机器启用了卷影复制),再查系统临时清理工具的日志,最后查下载目录和共享目录的历史版本。如果文件是在 Linux 上被误删,且文件系统还在运行,可以用 lsof | grep <文件名> 看看有没有进程还占着删除文件的句柄,如果能找到进程路径,甚至可以从 /proc/<pid>/fd/ 里把文件内容复制回来。当然,这个方法依赖进程没退出,成功率不一定高,但值得一试。
3.2 安装包从哪来:提前准备离线资源包的正确姿势
如果确认包已经彻底没了,只能重新获取。问题是内网机没有外网,所以核心思路永远是“外网下载,内网拷贝”。我建议在能访问网络的开发机上,提前把下面这些东西全部准备好,做成一个固定结构的离线资源包目录:
- Antigravity 本体安装包,对应操作系统架构(Windows、Linux x64、Arm64 要区分好)
- Remote-SSH 扩展的离线安装文件(通常是一个 .vsix 文件)
- SSH 客户端工具,如果内网机器确实没有 ssh 命令
- 远程端需要的依赖组件,比如特定版本的 Python、tar、wget 等
- 一份校验文件清单,用
sha256sum生成
这样做的好处是:你不需要在故障现场临时找资源,只需要在规定目录里拷文件。目录建议放在 /opt/offline_packages,里面再按项目、日期分子目录。可以顺手写一个简单的生成校验清单的命令:
bash复制cd /opt/offline_packages
find . -type f -exec sha256sum {} \; > SHA256SUMS.txt
之后每次安装前都执行一遍校验。不要小看这一步,内网环境经常有 U 盘拷贝到一半就中断的情况,文件看起来还在,实际字节数都对不上;安装到一半才发现出错,比多敲一条命令浪费时间多了。而且校验文件本身也很容易被忽略,所以我习惯把 SHA256SUMS.txt 和安装包放在同一个目录,并且在 README 里写明“先校验,再安装”这几个字。时间久了,团队其他人也会习惯这套动作。
3.3 已验证的恢复操作流程
我在真实环境里验证过一套恢复流程,基本步骤是这样,你可以根据自己情况调整:
- 从离线包仓库中找到对应的包,确认版本和当前系统匹配。可以检查 Antigravity 日志里的版本号,或者网上安装记录来确认。
- 将包复制到工作目录,比如
/home/<user>/Downloads,然后执行校验:sha256sum -c SHA256SUMS.txt或者单独对文件做哈希比对。 - 如果之前装了一半,先卸载不完整的版本,清理残留目录,再重新安装。这一步容易被忽略,残留的组件可能导致新包装不上。
- 安装本体:执行安装向导,或者解压二进制包到
/opt等固定目录,并配置好环境变量。 - 在 Antigravity 里手动安装扩展文件。以离线安装 Remote-SSH 扩展为例,打开扩展面板,选择“从 VSIX 安装”,选中对应的
.vsix文件,等待提示安装完成。 - 重启 Antigravity,重新尝试 SSH 连接。此时如果 SSH 配置还是不对,先回到第 2 节继续排查。
这套流程看起来不复杂,但每一步都容易踩坑。比如我自己就遇到过扩展版本和 Antigravity 主版本不兼容,安装后一直提示加载失败;后来回到离线包仓库找到匹配版本才解决。所以离线包一定要记录版本信息,不要只写“antigravity-remotessh.vsix”这样没有版本号的文件名。
4. 一套可直接照抄的离线环境避坑方案
4.1 搭建本地软件源或离线包仓库
既然内网环境这么容易卡在依赖下载上,不如一次到位,专门用一台内网 Linux 机器做离线包仓库。最简单的做法是开一个 Nginx 静态文件服务,把离线包目录暴露在局域网内,配合 autoindex on; 就能看到文件列表。这样其他机器只需要从仓库下载,不用再靠 U 盘一个一个拷。
仓库目录结构我会这样组织:
text复制/opt/offline_repo
├── antigravity
│ ├── 2025.06/
│ ├── 2025.07/
│ └── README.md
├── vscode-extension
│ ├── remote-ssh/
│ └── remote-ssh-editor/
└── tools
├── openssh-client/
├── sha256sum/
└── SHA256SUMS.txt
搭建完成后,把所有客户端机器的安装源或下载路径都指向这台仓库。每次新增包,更新 README.md 和校验文件。这件事看似一劳永逸,但很考验纪律性:如果谁拿了一个新包不登记,过几个月就没人知道它是什么版本了。我会在包里加一个 origin.txt,写上来源链接、拷贝日期、校验值、拷贝人,几行字能省下大量后续沟通。
4.2 给 SSH 服务做一次“体检”
SSH 连接失败问题在我这边很少是单一原因,更多是配置和环境的组合问题。所以我给自己定了个流程:在新的内网服务器上正式投入使用前,先给 SSH 服务做一次“体检”,把常见问题一次性排除掉。命令行版本可以直接跑:
bash复制systemctl status sshd
ss -lnt | grep :22
sshd -t
grep -E "UseDNS|PermitRootLogin|PubkeyAuthentication|AllowUsers" /etc/ssh/sshd_config
如果想做成定时巡检,可以把这些命令写成脚本,输出到一个报告文件里。检查项至少包括:服务运行状态、22 端口监听、配置文件语法、认证选项、最近的登录失败记录。我习惯再查看一下认证日志:
bash复制journalctl -u sshd --since today
tail -n 50 /var/log/auth.log
日志里会出现 Failed password、Connection closed、Received disconnect 这类信息,基本能定位到认证失败和网络断开原因。内网环境如果经常有人登录失败,也要注意是不是有人在做批量尝试,及时通过 DenyUsers 或 Fail2ban 这类工具收口。这些操作不会改变正常使用方式,但能让排障简单很多。
4.3 日常维护与备份小技巧
内网环境里,备份比外网更重要,因为外网可以随时拉新包,内网丢了就等于真没了。我总结了几条比较实用的维护习惯:
- 安装包永远不放在
/tmp和C:\Users\<用户名>\AppData\Local\Temp,这些目录随时可能被系统清理。 - 固定使用
/opt/offline_packages或D:\offline_packages作为唯一存放目录,并且让团队所有成员都知道这个约定。 - 每天做一次关键目录备份,至少包含:
~/.ssh、/etc/ssh/sshd_config、/etc/hosts、离线包仓库里的SHA256SUMS.txt。 - 如果团队有 Git 内网仓库,可以用 Git 管理配置文件和安装清单,但不要把私钥文件提交进去,哪怕是内网仓库也容易失控。
- 每次修复完 SSH 问题,在笔记里记录“症状、原因、解决方案、时间”四个字段,下次所有人都不需要重新踩坑。
这些习惯看起来很基础,但我在实际项目里发现,大部分“手动安装包被误删”事故都源于没有固定存放目录。把目录约定好,至少能避免一半问题。更关键的是,当 SSH 又开始抽风时,你能很快翻出备份对比是哪次变更引入的,而不是靠记忆反复试。记笔记这件事我坚持了两年,帮我在内网环境里省下的排障时间,保守估算也有几十个小时。
5. 常见问题速查表
下面是内网环境里常见的 SSH 连接失败和安装包问题,我整理成一个速查表,按症状查即可。
| 症状 | 可能原因 | 解决方式 |
|---|---|---|
SSH 连接报 Connection refused |
sshd 服务未启动或端口不对 | 启动服务:systemctl start sshd;确认端口:ss -lnt;如果改了端口,客户端也要对应改端口 |
| SSH 连接超时 | 防火墙拦截、网络不可达 | 检查 ping 与端口连通性;确认整体路由和安全域规则;不要盲目重装 SSHD |
出现 Permission denied (publickey,password) |
公钥未导入、密钥权限不对、认证方式被禁用 | 检查 authorized_keys;执行 chmod 700 ~/.ssh、chmod 600;确认 sshd_config |
| 连接建立后立刻无响应或断开 | UseDNS 默认开启、客户端/服务端保活参数不合理 | 设置 UseDNS no,调整 ClientAliveInterval 和 ServerAliveInterval |
| Antigravity 能连接但一直提示加载远程组件失败 | 远程端缺少依赖或无法访问外网 | 准备离线安装包,手动安装 Remote-SSH 依赖和扩展;确认远程端有 tar、bash 等基础组件 |
| 手动安装包被系统清理 | 文件放在临时目录 | 放到 /opt/offline_packages 等固定目录,并加入每日备份 |
| 安装包校验值不一致 | 拷贝过程中损坏 | 重新从离线仓库拷贝,并执行 sha256sum -c 校验 |
| 扩展安装后版本不兼容 | 离线包版本和 Antigravity 版本不匹配 | 在仓库中保留版本对应关系,按版本目录存放;升级前先查兼容性 |
这张表适合直接打印出来贴在工位上。我在实际排障时,会把表格贴在自己终端旁边的墙上,遇到问题先查症状,再对原因,能少走很多弯路。你还可以根据自己团队的实际情况,把日志中常见的错误片段补充进去。比如我后来就把 remote host identification has changed 也加入进去了,这种问题在内网里通常意味着密钥记录和服务器不匹配,清理 known_hosts 中的旧记录就能解决。表格的意义不在于面面俱到,而在于给当时慌乱的自己一个清晰的路径。
最后再说一个经验:内网环境下的排障,很多时候不是技术门槛高,而是信息丢了。我那次完整的坑,最终是靠“把离线包重新放回固定目录 + 给 sshd_config 加 UseDNS no + 重装 Remote-SSH 扩展”三个动作解决的,每一个单独看都很简单,但如果不按顺序检查,还是会反复在同一个地方跌倒。如果你也遇到 Antigravity 在内网连不上 SSH,或者安装包被误删,建议先把安装包和配置备份变成固定动作,再按上面的链路逐层排查。这样即使问题卷土重来,你手里也有完整的弹药。
