如何设置后台 ssh 隧道的自动(重新)启动

问题描述 投票:0回答:3

我是 Linux 的初学者,而且对 ssh 和隧道也很新手。

无论如何,我的目标是在后台保持 ssh 隧道打开。

为了做到这一点,我编写了以下批处理,然后将其添加到 crontab 中(该批处理在工作日从上午 8 点到晚上 9 点每 5 分钟自动处理一次)。 我在 stackoverflow 中的其他一些线程中读到,应该使用 autossh,这将确保 ssh 通过定期检查始终正常。我也是....

#!/bin/bash
LOGFILE="/root/Tunnel/logBatchRestart.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date & time of log

if ! ps ax | grep ssh | grep tunnelToto &> /dev/null
then
    echo "[$NOW] ssh tunnel not running : restarting it" >> $LOGFILE
    autossh -f -N -L pppp:tunnelToto:nnnnn [email protected] -p qqqq
    if ! ps ax | grep ssh | grep toto &> /dev/null
    then
            echo "[$NOW] failed starting tunnel" >> $LOGFILE
    else
            echo "[$NOW] restart successfull" >> $LOGFILE
    fi
fi

我的问题是,有时隧道会停止工作,尽管一切看起来都正常(ps ax | grep ssh > 结果显示两个预期任务:autossh 主任务和 ssh 隧道本身)。我实际上知道这个问题,因为隧道由第三方软件使用,一旦隧道不再响应,就会触发错误。

所以我想知道我应该如何改进我的批次,以便它能够检查隧道并在它碰巧死掉时重新启动它。我在there中看到了一些想法,但它是由我已经使用的“autossh”提示得出的结论。因此,我没有主意了......如果你们中有人有的话,我很乐意看看它们!

感谢您对我的问题感兴趣,以及您(也许)的建议!

linux bash ssh
3个回答
12
投票

您可以执行以下技巧,而不是使用

ssh
检查
ps
进程

创建脚本,执行以下操作并通过

crontab -e

将其添加到您的 crontab
#!/bin/sh

REMOTEUSER=username
REMOTEHOST=remotehost 

SSH_REMOTEPORT=22
SSH_LOCALPORT=10022

TUNNEL_REMOTEPORT=8080
TUNNEL_LOCALPORT=8080

createTunnel() {
    /usr/bin/ssh -f -N  -L$SSH_LOCALPORT:$REMOTEHOST:SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:TUNNEL_REMOTEPORT $REMOTEUSER@$REMOTEHOST
    if [[ $? -eq 0 ]]; then
        echo Tunnel to $REMOTEHOST created successfully
    else
        echo An error occurred creating a tunnel to $REMOTEHOST RC was $?
    fi
}

## Run the 'ls' command remotely.  If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER@localhost ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
    echo Creating new tunnel connection
    createTunnel
fi

事实上,这个脚本会打开两个端口

  • 端口 22 将用于检查隧道是否仍然存在
  • 端口 8080,这是您可能想要使用的端口

请检查并通过评论向我发送更多问题


5
投票

您不需要为此手工制作 bash 脚本!

现在大多数 Linux 机器都配备了

systemd
,它为启动/停止/重新启动服务提供了坚实的支持,并具有可配置的条件和超时。

  1. 作为 root 创建一个
    systemd
    服务单元:
sudo vim /etc/systemd/system/ssh-tunnel.service
  1. 将以下配置粘贴到新文件中:
[Unit]
Description=ssh
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=5
StartLimitBurst=1

[Service]
# NOTE: you MUST start ssh *without!* the -f (forking) switch, 
# so that systemd can monitor it and detect when the tunnel goes down
Type=simple
# forward *local* port 80 to port 8088 on the remote host
ExecStart=ssh [email protected] -N -R 8088:localhost:80
# send an exit signal to the SSH master process that controls the tunnel
ExecStop=ssh arh -O exit -R 8088:localhost:80
# see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#TimeoutStartSec=
TimeoutStartSec=10
TimeoutStopSec=10
Restart=always
RestartSec=10

# TODO: set the user name here; root will be used if unset
# make sure the user has the correct ssh key or otherwise 
# explicitly pass the key with `ssh -i /path/to/key/id_rsa   
User=my-user-name

# TODO: for debugging only; remove once you get the service working
StandardOutput=console

[Install]
WantedBy=multi-user.target
  1. 启用并启动服务单元:
# make service start on every boot (after network is up)
sudo systemctl enable ssh-tunnel

sudo systemctl start ssh-tunnel
  1. (可选)检查您的服务状态:
systemctl status ssh-tunnel

这是如何运作的?

StartLimitIntervalSec
配置统计服务启动的时间间隔。如果某个服务在此时间间隔内启动超过
StartLimitBurst
,则不允许再启动。
TimeoutStartSec
配置
systemd
在认为服务处于失败状态之前等待服务启动的最长时间。

使用上述配置,如果 SSH 隧道出现故障,例如由于临时网络故障,

systemd
将等待 10 秒,然后重新启动隧道。

这种方法可靠、可配置,并实现与其他答案或实用程序(如 autossh)中给出的脚本相同的结果,但采用可与任何其他工具一起使用的通用方式。

这里的关键是在 foreground 模式下启动 SSH(即不要使用

-fn
开关将其发送到后台),以便
systemd
可以监控服务是否仍然存在并在失败时重新启动它。

另请参阅:


1
投票

(我将其添加为答案,因为评论中没有足够的空间)

好吧,我设法运行批处理来启动 ssh 隧道(我必须指定我的主机名而不是 localhost 才能触发它):

#!/bin/bash

LOGFILE="/root/Tunnel/logBatchRedemarrage.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date et heure du log


REMOTEUSER=username
REMOTEHOST=remoteHost

SSH_REMOTEPORT=22
SSH_LOCALPORT=10022

TUNNEL_REMOTEPORT=12081
TUNNEL_SPECIFIC_REMOTE_PORT=22223
TUNNEL_LOCALPORT=8082

createTunnel() {
    /usr/bin/ssh -f -N  -L$SSH_LOCALPORT:$REMOTEHOST:$SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:$TUNNEL_REMOTEPORT [email protected] -p $TUNNEL_SPECIFIC_REMOTE_PORT
    if [[ $? -eq 0 ]]; then
        echo [$NOW] Tunnel to $REMOTEHOST created successfully >> $LOGFILE
    else
        echo [$NOW] An error occurred creating a tunnel to $REMOTEHOST RC was $? >> $LOGFILE
    fi
    }

## Run the 'ls' command remotely.  If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT [email protected] ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
    echo [$NOW] Creating new tunnel connection >> $LOGFILE
    createTunnel
fi

但是,当隧道运行时以及当 cron 尝试再次启动批处理时,我立即收到一些消息(如下)......听起来它无法收听它。另外,由于我需要一些时间来获得证明,所以我还不能说如果隧道消失它会成功重新启动。

这是对第二批启动的响应。

bind:地址已在使用中channel_setup_fwd_listener:无法监听 到端口:10022 绑定:地址已在使用中 Channel_setup_fwd_listener:无法侦听端口:8082 无法 请求本地转发。

© www.soinside.com 2019 - 2024. All rights reserved.