dryrun 的 ssh 探测适配强制命令,并分清指纹与认证两种失败

采集机那侧的 authorized_keys 用了强制命令,把这把 key 锁成只能跑 tail,
拿不到 shell。副作用是任何请求都变成 tail -F 而它永不返回,原先
`ssh <host> 'echo ok'` 的探测会永久挂住——ConnectTimeout 只管建连,不管
命令时长。改成照 ship_signals 的真实用法读流:tail -c +0 先吐出整个文件,
数行数就等于对端总线条数,之后由 timeout 收掉。

失败诊断原先一律说"装 key",但 Host key verification failed 是 known_hosts
空的,装 key 修不了,会把人引到错方向。现在分三类:指纹未确认、认证被拒、
其他,各给对应做法。指纹那条明确不建议 StrictHostKeyChecking=no——这条链路
上跑的是下单信号。

install.sh 的第 2 步补上 known_hosts:原先只说装 key,而服务跑起来会撞同一
个墙(BatchMode=yes 不允许交互确认)。

实测:强制命令下故意请求错路径,仍拿到真总线内容且 stderr 干净。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jack
2026-08-28 18:01:01 +08:00
co-authored by Cursor
parent b6ed5c8b50
commit d884de2c36
2 changed files with 42 additions and 12 deletions
+32 -10
View File
@@ -46,18 +46,40 @@ myip="$(curl -s --max-time 10 https://api.ipify.org || true)"
echo " 对照 Bitget 后台该 key 的 IP 白名单,不一致下面会报 40018 之类"
echo "── 4. 能否 ssh 到采集机 ──"
if sudo -u "$USER_NAME" ssh -o BatchMode=yes -o ConnectTimeout=10 \
"$SHIP_FROM" 'echo ok' >/dev/null 2>&1; then
ok "ssh $SHIP_FROM"
rb="${SHIP_REMOTE_BUS:-~/chan-live/state/signals_live.jsonl}"
n="$(sudo -u "$USER_NAME" ssh -o BatchMode=yes "$SHIP_FROM" \
"wc -l < $rb 2>/dev/null || echo 0")"
echo " 对端总线现有 $n 条信号"
[[ "$n" -gt 0 ]] || echo " ⚠ 对端总线是空的。采集机接总线了吗?"
else
die "ssh $SHIP_FROM 不通。装 key
# 不能用 ssh <host> 'echo ok' 来试:采集机那侧的 authorized_keys 用了强制命令
# (把这把 key 锁成只能跑 tail,拿不到 shell),任何请求都会变成 tail -F,
# 而它**永不返回**——ConnectTimeout 只管建连不管命令时长,测试会永久挂住。
# 所以照 ship_signals 的真实用法读流:tail -c +0 会先把整个文件吐出来,
# 数一下就等于对端总线的条数,之后它挂着等新内容,由 timeout 收掉。
rb="${SHIP_REMOTE_BUS:-\$HOME/chan-live/state/signals_live.jsonl}"
err="$(mktemp)"; outf="$(mktemp)"
timeout 12 sudo -u "$USER_NAME" ssh -T -o BatchMode=yes -o ConnectTimeout=10 \
"$SHIP_FROM" "tail -c +0 -F $rb" >"$outf" 2>"$err" || true
n="$(wc -l < "$outf")"
if grep -qi "Host key verification failed" "$err"; then
fp="(在采集机上跑 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub 拿)"
rm -f "$err" "$outf"
die "主机指纹没确认过。这不是 key 的问题,装 key 也修不了。
$USER_NAME 的 known_hosts 是空的,而 BatchMode=yes 不允许交互确认。
**不要**用 StrictHostKeyChecking=no 糊过去,那等于放弃中间人防护。
正确做法:在采集机上读出权威指纹 $fp
再在这台上写入并核对:
sudo -u $USER_NAME ssh-keyscan -t ed25519 <采集机IP> \\
| sudo -u $USER_NAME tee -a $STATE/home/.ssh/known_hosts
ssh-keygen -lf $STATE/home/.ssh/known_hosts # 比对指纹是否一致"
elif grep -qiE "Permission denied|publickey" "$err"; then
rm -f "$err" "$outf"
die "认证被拒。指纹是通的,是 key 没装到采集机上:
sudo -u $USER_NAME ssh-keygen -t ed25519 -N '' -f $STATE/home/.ssh/id_ed25519
再把 $STATE/home/.ssh/id_ed25519.pub 加到采集机的 authorized_keys"
elif [[ -s "$err" ]] && ! grep -q "^" "$outf" 2>/dev/null; then
msg="$(head -3 "$err")"; rm -f "$err" "$outf"
die "ssh $SHIP_FROM 不通:$msg"
else
ok "ssh $SHIP_FROM"
echo " 对端总线现有 $n 条信号"
[[ "$n" -gt 0 ]] || echo " ⚠ 对端总线是空的。信号 6.8 个/天,刚重启过就是空的很正常;但要确认采集机接了总线"
rm -f "$err" "$outf"
fi
echo "── 5. 执行器空跑 ${SECS}s(真连交易所,不下单)──"