很多天來,我一直在想如何自動建立反向隧道。
我有許多在 LAN 內使用 NAT 的遠端 Raspberry,以及一個我用作伺服器的 Raspberry,可透過 Internet 存取。
我在我的網站上實作了一個向遠端樹莓派發送單一命令的系統。
每個遠端 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
via執行命令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
而不僅僅是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 上的反向連接埠應該不同,以避免伺服器上的連接埠之間發生衝突