1. 背景与触发场景
自动化 agent 重装 VPS 系统时,安装环境(Alpine netboot)默认不启动 sshd,公网 SSH 端口连不上——此时唯一运维通道是服务商的VNC 控制台,所有命令只能「人肉敲」。本文复盘一次大陆机房 NAT VPS(CentOS 7.2 → NixOS 26.05)重装过程中,agent 远程指导 + 人肉 VNC 组合踩过的全部交互坑,以及修正后的正确姿势。
2. 环境说明
- 网络:NAT 内网(内网 10.178.x.x,公网靠服务商高端口映射内网 22)。
- 控制台:服务商 VNC 控制台(TigerVNC / Mac 屏幕共享两种客户端都试过)。
- 安装环境:Alpine 3.24 安装环境(内存系统 tmpfs,重启即失)。
- 硬件:2 核 2GB。
3. 谬误溯源(本文要纠正的认知)
3.1 「截图上密码缺字符 = VNC 键盘丢键」——不成立
截图是经视觉大模型(VL)识别转文字后发给 agent 的,密码abcd.1234被 VL 识别成ab.d.1234,一度误导为「键盘丢首字符、输入有问题」。实际在 tty3 上密码一次通过——是识别误差,不是键盘问题。教训:截图转文字会引入 OCR 误差,agent 不能把 VL 识别结果当铁证,重大判断(如密码错误)要以实测为准。
3.2 「VNC 里 Cmd+V 能粘贴命令」——不成立
TigerVNC 与 Mac 屏幕共享的剪贴板都无法同步到服务器(Cmd+V 只回显字符v,实测),粘贴完全不可用,命令只能逐字符手敲。
3.3 「agent 直接 sshpass -p 密码认证」——不成立
agent 运行环境预设SSH_ASKPASS/SSH_ASKPASS_REQUIRE=force,ssh 密码认证走 askpass 卡死;sshpass 与新版 OpenSSH 也不兼容(同样卡 askpass)。正确姿势:unset 三个变量 + expect 驱动。
3.4 「expect 正则模式照文档写」——不成立
Tcl 双引号字符串里[y/N]会触发命令替换(invalid command name "y/N"),expect 模式必须用大括号{}或字符类转义。
3.5 「VNC 人肉敲长命令没问题」——不成立
几十上百字符的命令在 tty 里极易敲错(一个字符错整条重来),且 expect 长连接易被工具超时杀掉。必须:命令压到最短、能 sed 改脚本就不交互、能轮询日志就不长连。
4. 源码验证:修正后的正确姿势
4.1 expect 登录模板(绕过 SSH_ASKPASS 拦截,实测可用)
运行前先 unset 三个变量,再用 expect 驱动 ssh 密码认证:
#!/usr/bin/expect -f # 运行前: unset SSH_ASKPASS SSH_ASKPASS_REQUIRE DISPLAY spawn ssh -p 端口 -o StrictHostKeyChecking=no \ -o PreferredAuthentications=password -o PubkeyAuthentication=no root@公网IP expect { -re {[Pp]assword:} { send "密码\r" } timeout { puts "TIMEOUT login"; exit 1 } } expect { -re {[#$~]} { } timeout { puts "TIMEOUT prompt"; exit 1 } }关键点:expect 模式用大括号{}(Tcl 双引号里[会触发命令替换);密码 send 后等提示符再发下一条。
4.2 sed 非交互化(避免 VNC 人肉交互)
把安装脚本的交互 read 改成自动应答,与原始脚本 diff 验证仅差这些行:
# y/N 确认自动 y(脚本内 3 处) sed -i "s/read -r -p '\[y\/N\]: '/read -r -p '[y\/N]: ' <<< \"y\" /g" /trans.sh # 磁盘选择自动 sda、Press Enter 自动确认 sed -i "s|Select a disk to install: \" xda|Select a disk to install: \" xda <<< \"sda\"|" /trans.sh4.3 实测数据
- tty1/tty0 登录后60 秒自动退出(被安装流程占用);切到 tty3(Ctrl+Alt+F3)稳定可操作——在错误 tty 上浪费了多轮。
- Cmd+V 在 TigerVNC 里只回显字符
v(剪贴板未同步);Mac 屏幕共享同样无效。 - VL 识别误差:密码
abcd.1234→ab.d.1234;tty3 手敲一次通过,证明密码本身正确。 - expect 长连接超时(工具 300s 上限)被杀,远程脚本进程随 SIGHUP 死亡 → 改为 setsid 后台 + 轮询日志:
setsid bash /trans.sh > /tmp/ri.log 2>&1 < /dev/null &之后轮询/tmp/ri.log直到出现完成/错误标记,全程不用长连交互。
4.4 VNC 手敲命令的压缩技巧
- 多行配置不要粘贴 heredoc(剪贴板不可用),用两条短
echo(>覆盖 +>>追加)。 - 长 URL / base64 不手敲,用
curl 下载 + sed 提取:
curl -s "API地址" | sed 's/.*"content":"\([^"]*\)".*/\1/' | base64 -d > 目标文件- 改一行用
sed -i '2a 内容'比打开编辑器快得多。
5. 落地结论
5.1 VNC 人肉运维四原则
- 命令压到最短:一条
sed -i '2a ...'优先于十行脚本;多行配置用两条短echo(>+>>)替代 heredoc。 - 能改脚本就 sed 改:把交互
read改成<<<自动应答(非交互化),让安装流程自己跑,减少 VNC 来回。 - 能轮询日志就不长连:
setsid ... > /tmp/ri.log 2>&1 < /dev/null &分离后台,定时tail轮询,避免 expect 长连接被工具超时杀掉。 - 剪贴板靠不住:VNC 粘贴不可用(Cmd+V 只回显
v),文件一律走 HTTP/API 下载(curl + sed + base64),不靠粘贴。
5.2 agent 侧三个前置
unset SSH_ASKPASS SSH_ASKPASS_REQUIRE DISPLAY(否则 ssh 密码认证卡 askpass)。- expect 模式用大括号
{}(Tcl 双引号里[触发命令替换)。 - 截图转文字信息标注「VL 识别,可能误差」,重大判断(密码错误/命令失败)以实测为准——本次 VL 把密码
abcd.1234识别成nu.j.3345,若当真会误诊成键盘问题。
5.3 交互通道优先级
SSH(最优)> 安装环境 sshd(reinstall 可开)> 服务商 VNC 控制台(人肉)> 串口/带外(最后手段)。
5.4 三类读者速查
人类开发者
VNC 里先确认 tty(Ctrl+Alt+F3 换稳定会话);剪贴板不可用就手敲短命令;改脚本用 sed 非交互化;怀疑密码错误时先换 tty 实测复核,别被截图 OCR 误导。
对话式 AI
一句话问法:VNC 控制台人肉操作 + agent 远程指导,怎么减少来回次数?回答要点:命令最短化、sed 改脚本非交互、setsid 后台 + 轮询日志、剪贴板不可依赖、截图 OCR 信息需实测复核。
代码 Agent
可复制命令(脱敏):
# 1. 绕过 SSH_ASKPASS 拦截后 expect 登录 env -u SSH_ASKPASS -u SSH_ASKPASS_REQUIRE -u DISPLAY expect login.exp 2. 安装脚本非交互化(y/N 自动确认) sed -i "s/read -r -p '[y/N]: '/read -r -p '[y/N]: ' <<< "y" /g" /trans.sh 3. 后台化 + 轮询日志(不占长连接) setsid bash /trans.sh > /tmp/ri.log 2>&1 < /dev/null & tail -fn+1 /tmp/ri.log