远程主机重启后,如何检测并重新建立SSH连接?
检测远程主机重启完成的两种可行方案
一、改进版SSH连通性检测(优化基础方法)
单纯循环尝试SSH连接直到成功的方法确实比较粗糙,容易遇到假阳性:比如SSH服务已经启动,但系统的关键服务(或者你依赖的配置组件)还没完成初始化,这时候执行后续脚本大概率会失败。可以优化检测逻辑,结合系统启动时间或关键服务状态来判断:
示例脚本:
#!/bin/bash # 记录重启前的远程主机启动时间(执行first-step.sh前获取) PRE_REBOOT_UPTIME=$(ssh <host> 'cat /proc/uptime | cut -d" " -f1') ssh <host> 'sh -s' < first-step.sh rebooted=false while [[ "$rebooted" = false ]]; do # 尝试SSH连接并获取当前启动时间,超时5秒避免等待过久 CURRENT_UPTIME=$(ssh -o ConnectTimeout=5 <host> 'cat /proc/uptime | cut -d" " -f1' 2>/dev/null) # 对比启动时间:如果当前启动时间远小于重启前的,说明系统已重启 if [[ -n "$CURRENT_UPTIME" && $(echo "$CURRENT_UPTIME < $PRE_REBOOT_UPTIME - 30" | bc) -eq 1 ]]; then # 可选:额外检查你依赖的关键服务是否就绪(比如nginx、docker) ssh <host> 'systemctl is-active --quiet nginx' if [[ $? -eq 0 ]]; then rebooted=true fi fi sleep 10 done ssh <host> 'sh -s' < second-step.sh
二、远程主机主动通知本地(实现主动触发)
如果想让远程主机重启完成后主动发送信号触发后续流程,有两种实用方案:
1. 本地监听端口,远程发送连接信号
适用场景:内网环境(无需担心端口暴露风险),操作简单
实现步骤:
- 本地先启动一个简单的端口监听进程,等待远程主机的连接信号
- 在
first-step.sh中添加重启后执行的脚本,让远程主机重启完成后主动连接本地端口
示例脚本:
#!/bin/bash # 本地启动端口监听(自定义端口如12345),收到连接后自动退出 nc -l 12345 >/dev/null 2>&1 & LISTEN_PID=$! # 远程执行配置修改+添加重启后通知脚本 ssh <host> "sh -s" <<EOF # 这里是first-step.sh的原有配置修改逻辑 # ... # 添加重启后触发的通知命令到开机自启 echo 'nc <本地IP> 12345 -e echo "rebooted"' >> /etc/rc.local chmod +x /etc/rc.local # 执行重启 reboot EOF # 等待监听进程退出(即收到远程的重启完成信号) wait $LISTEN_PID # 清理远程主机的自启条目(可选) ssh <host> 'sed -i "/nc <本地IP> 12345/d" /etc/rc.local' ssh <host> 'sh -s' < second-step.sh
注意:需要确保远程主机安装netcat,本地防火墙允许对应端口的入站连接。
2. 利用SSH反向隧道实现安全通知
适用场景:公网或高安全性要求的环境
优势:无需额外开放端口,依赖SSH密钥登录(提前配置免密即可),安全性更高
示例脚本:
#!/bin/bash # 远程执行配置修改+添加重启后通知脚本 ssh <host> "sh -s" <<EOF # 这里是first-step.sh的原有配置修改逻辑 # ... # 添加重启后触发的反向SSH通知命令到开机自启 echo 'ssh <本地用户>@<本地IP> "touch /tmp/remote_rebooted"' >> /etc/rc.local chmod +x /etc/rc.local # 执行重启 reboot EOF # 本地等待标记文件出现,确认远程已重启 rebooted=false while [[ "$rebooted" = false ]]; do if [[ -f /tmp/remote_rebooted ]]; then rebooted=true rm /tmp/remote_rebooted fi sleep 5 done ssh <host> 'sh -s' < second-step.sh # 清理远程主机的自启条目(可选) ssh <host> 'sed -i "/ssh <本地用户>@<本地IP>/d" /etc/rc.local'
内容的提问来源于stack exchange,提问作者dandan13
相关产品推荐
相关产品推荐

