很多天来,我一直在思考如何自动建立反向隧道。
我有许多在其 LAN 内使用 NAT 的远程 Raspberry,还有一个用作服务器的 Raspberry,可通过互联网访问。
我在我的网站上实现了一个系统,用于向远程 Raspberries 发送单个命令。
每个远程 Raspberry 每分钟(crontab)检查可用命令的存在,如果有,则下载命令,创建可执行文件并运行它。以下是 crontab 文件的代码:
#! /bin/bash
sudo wget -c --output-document=ipdiscover.php "www.myserver.com/checkforcommands.php";
comando=$(cat ipdiscover.php);
sudo rm "/esegui.sh";
echo "#! /bin/bash" >> /esegui.sh;
echo "" >> /esegui.sh;
echo -e $comando >> /esegui.sh;
echo "exit 0" >> /esegui.sh;
sudo chmod +x /esegui.sh;
sudo /esegui.sh;
sudo rm "ipdiscover.php";
sudo date >>/tmp/crontest.txt;
这个系统运行得很好,但我无法用它来建立反向隧道。
如果我在远程服务器上运行此代码:
sudo /usr/bin/ssh -gNnT -R 2222:localhost:22 pi@publicserverIP;
然后一切都正常工作,但如果我从 crontab 脚本运行它,它就不起作用。
我创建了没有密码的证书,并将其从远程 Raspberry 发送到服务器以便无法登录访问。
答案1
您不需要通过 运行cron
命令sudo
。
创建一些类似下面的脚本,并将其放在将与您的服务器建立反向 SSH 连接的用户的主目录中:
#!/bin/sh
### reverseSSHscript.sh ###
### (use public key authentication, so you don't need
### to enter password for your server)
PrivateKeyToAccessCentralServer='/path/to/the/private/ssh/ServerKey.pem'
(
/usr/bin/nohup \
/usr/bin/ssh -gNnT \
-i "${PrivateKeyToAccessCentralServer}" \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=1 \
-o TCPKeepAlive=no \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
-R 2222:localhost:22 pi@publicserverIP
) &
然后创建cron任务来运行它:
echo "@reboot User /path2the_script_shown_above/reverseSSHscript.sh" |
sudo tee /etc/cron.d/reverseSSH2home
然后它应该可以工作了。顺便说一句,为了安全起见
,您可能希望在某些限制下User
而不是在 as 下运行此脚本。root
您还需要实现一些逻辑来reverseSSHscript.sh
检查连接是否已建立,以防止创建多个会话。
还要定期从 cron 运行一些额外的检查来测试服务器上的反向连接端口是否仍然有效;如下所示:
chkRemPort() {
# Connect to intermediate host and check if remote forwarded port is alive
echo $(/usr/bin/ssh -4 -f -q \
-o BatchMode=yes \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
-i /path/to/the/private/ssh/ServerKey.pem \
pi@publicserverIP \
/bin/nc -w 3 -zv localhost 2222 2>&1 | /bin/grep succeeded > /dev/null ; \
[ $? -eq 0 ] && { echo 'OK'; } || { echo 'FAILED'; }; exit; )
}
如果检查失败,则尝试与您的服务器建立新的反向会话。
PS
每个 Raspberry Pi 上的反向端口应该不同,以避免服务器上的端口发生冲突