From d884de2c36a40fdcf27912734a3f9c993171e3cf Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 28 Aug 2026 18:01:01 +0800 Subject: [PATCH] =?UTF-8?q?dryrun=20=E7=9A=84=20ssh=20=E6=8E=A2=E6=B5=8B?= =?UTF-8?q?=E9=80=82=E9=85=8D=E5=BC=BA=E5=88=B6=E5=91=BD=E4=BB=A4=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E5=88=86=E6=B8=85=E6=8C=87=E7=BA=B9=E4=B8=8E=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E4=B8=A4=E7=A7=8D=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 采集机那侧的 authorized_keys 用了强制命令,把这把 key 锁成只能跑 tail, 拿不到 shell。副作用是任何请求都变成 tail -F 而它永不返回,原先 `ssh '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 --- live/deploy/dryrun.sh | 42 ++++++++++++++++++++++++++++++++---------- live/deploy/install.sh | 12 ++++++++++-- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/live/deploy/dryrun.sh b/live/deploy/dryrun.sh index f9f4b8e..6c68ea3 100755 --- a/live/deploy/dryrun.sh +++ b/live/deploy/dryrun.sh @@ -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 '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(真连交易所,不下单)──" diff --git a/live/deploy/install.sh b/live/deploy/install.sh index b127c40..9ef2f38 100755 --- a/live/deploy/install.sh +++ b/live/deploy/install.sh @@ -182,10 +182,18 @@ echo " BITGET_API_KEY / SECRET / PASSPHRASE 用只读+交易权限," echo " **不要开提币权限**。SHIP_FROM 填采集机的 ssh 目标。" echo fi -echo " 2. 装拉总线用的 ssh key,并确认能连上采集机:" +echo " 2. 装拉总线用的 ssh key:" echo " sudo -u $USER_NAME ssh-keygen -t ed25519 -N '' -f $STATE/home/.ssh/id_ed25519" echo " # 把 $STATE/home/.ssh/id_ed25519.pub 加到采集机的 authorized_keys" -echo " sudo -u $USER_NAME ssh -o BatchMode=yes <采集机> 'echo ok'" +echo +echo " 还要写 known_hosts,否则报 Host key verification failed —— 服务跑" +echo " 起来会撞同一个墙,因为 BatchMode=yes 不允许交互确认:" +echo " sudo -u $USER_NAME ssh-keyscan -t ed25519 <采集机IP> \\" +echo " | sudo -u $USER_NAME tee -a $STATE/home/.ssh/known_hosts" +echo " ssh-keygen -lf $STATE/home/.ssh/known_hosts" +echo " # 把指纹跟采集机上 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub" +echo " # 的输出比一遍。**不要**图省事用 StrictHostKeyChecking=no," +echo " # 那等于放弃中间人防护,而这条链路上跑的是下单信号" echo echo " 3. 空跑验全链(不下真单,跑够看到一次心跳再停):" echo " sudo $APP/live/deploy/dryrun.sh"