
跟進:看起來一系列快速斷開連接與每台伺服器運行幾個月的時間相一致可能是巧合,只是為了揭示實際問題。它無法重新連接的原因幾乎可以肯定是由於 AliveInterval 值(kasperd 的答案)。使用 ExitOnForwardFailure 選項應該允許在重新連接之前正確發生逾時,這應該可以解決大多數情況下的問題。 MadHatter 的建議(終止腳本)可能是確保隧道能夠重新連接的最佳方法,即使其他一切都失敗了。
我在防火牆後面有一台伺服器 (A),它在多個連接埠上啟動到小型 DigitalOcean VPS (B) 的反向隧道,以便我可以透過 B 的 IP 位址連接到 A。該隧道已連續工作約3個月,但在過去24小時內突然發生四次故障。不久前另一家 VPS 提供者也發生了同樣的事情 - 幾個月的完美運行,然後突然出現多次快速故障。
我在機器 A 上有一個腳本,它會自動執行隧道命令(ssh -R *:X:localhost:X address_of_B
對於每個連接埠 X),但是當它執行時,它會顯示Warning: remote port forwarding failed for listen port X
.
進入/var/log/secure
伺服器上的 sshd 顯示下列錯誤:
bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X
解決方法需要重啟VPS。在此之前,所有重新連線的嘗試都會給予「遠端連接埠轉送失敗」訊息,並且不會運作。現在隧道只持續了大約4個小時就停下來了。
VPS 上沒有任何變化,它是一次性、單用戶計算機,僅充當反向隧道端點。它在 CentOS 6.5 上運行 OpenSSH_5.3p1。當連線遺失時,sshd 似乎沒有關閉其一端的連接埠。我無法解釋為什麼,或者為什麼在經過幾個月近乎完美的運作後現在會突然發生這種情況。
為了澄清,我首先需要弄清楚為什麼 sshd 在隧道失敗後拒絕偵聽端口,這似乎是由於 sshd 將端口保持打開狀態而從不關閉它們造成的。這似乎是主要問題。我只是不確定是什麼會導致它在按照我的預期運行數月後出現這種情況(即立即關閉連接埠並允許腳本重新連接)。
答案1
我同意 MadHatter 的觀點,這很可能是來自失效 ssh 連線的連接埠轉送。即使您目前的問題是其他問題,您遲早也會遇到此類失效的 ssh 連線。
此類無效連接可能透過三種方式發生:
- 兩個端點之一重新啟動,而連接的另一端則完全空閒。
- 兩個端點之一關閉了連接,但在關閉連接時,連接出現了暫時中斷。連線關閉後,中斷持續了幾分鐘,因此另一端永遠不會知道連線已關閉。
- ssh 連接的兩個端點上的連接仍然完全正常工作,但有人在它們之間放置了一個有狀態設備,導致連接由於空閒而逾時。這個有狀態的設備可以是 NAT 或防火牆,您已經提到的防火牆是主要嫌疑犯。
要弄清楚發生了上述三種情況中的哪一種並不是很重要,因為有一種方法可以解決這三種情況。這就是keepalive訊息的用途。
您應該查看ClientAliveInterval
關鍵字 forsshd_config
和orServerAliveInterval
的間隔。ssh_config
~/.ssh/config
ssh
循環運行該命令可以正常工作。在循環中插入睡眠也是一個好主意,這樣當連線因某種原因失敗時,您就不會導致伺服器氾濫。
如果用戶端在伺服器上的連線終止之前重新連接,則可能會出現新的 ssh 連線處於活動狀態但沒有連接埠轉送的情況。為了避免這種情況,您需要ExitOnForwardFailure
在客戶端使用關鍵字。
答案2
對我來說,當ssh
隧道斷開連接時,連接需要一段時間才能重置,因此該ssh
過程繼續阻塞,導致我沒有活動隧道,我不知道為什麼。解決方案是將ssh
和 放入背景-f
並產生新連接,而無需等待舊連接重置。可-o ExitOnForwardFailure=yes
用於限制新進程的數量。這-o ServerAliveInterval=60
提高了當前連接的可靠性。
您可以ssh
經常重複該命令,例如cron
在腳本中的 , 或 循環中重複該命令,例如,在下面,我們ssh
每 3 分鐘運行一次該命令:
while (1)
do
ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
sleep 180
done
答案3
您可以找到綁定該伺服器上連接埠的進程
sudo netstat -apn|grep -w X
看起來很可能是半廢止的sshd
,但是當你有數據的時候為什麼還要做假設呢?這也是腳本在嘗試再次啟動隧道之前找到 PID 以發送訊號 9 的好方法。
答案4
根據我的經驗,ssh 有一個有點令人討厭的習慣,如果遠端系統上仍在運行“某些東西”,則它不會完全退出。例如在後台啟動。您可以透過以下方式重現此內容:
ssh <server>
while true; do sleep 60; done&
exit
您的 ssh 將註銷,但實際上不會關閉會話 - 直到遠端進程退出(它不會,因為它是一個“while true”循環)。可能正在發生類似的事情 - 您的會話有一個由 ssh 產生的「卡住」進程。該連接埠仍在使用中,因此您的本機進程無法重新使用它。