[2017/3/6 如果遇到 「Cannot assign requested address」 的錯誤, 可能需要在 ssh 命令列上加上 -4 的選項。 詳見 這篇]
你在自己的筆電或家裡的電腦上面安裝了一個神奇的服務, 心裡想著: 「不能只有我看到! 一定要展示給朋友、 甚至要展示給世界看!」 但是你沒有固定的 IP, 或是你的機器被防火牆保護住了, 朋友跟世界都看不見你有多帥。 這個時候, 如果你有一個 ssh 帳號, 而且那個帳號至少被允許使用一個空的 port, 那麼就可以透過反向 ssh 隧道 (reverse ssh tunnel) 對外展示你的服務了。
要學反向 ssh tunneling, 不如同時把正向 ssh tunneling 也一併弄懂。 找到 這一篇, 插圖把兩者合併畫在一起, 超讚超清楚。
以下假設你已玩過 坐 ssh 火車過山洞 那篇的 http over ssh 或 vnc over ssh, 對 ssh tunneling 已經略懂略懂。 我用更有 fu 的方式白話重畫如上圖。 圖中我們真正有興趣的是紫色的服務 (例如資料庫、 網頁、 串流音樂、 監視錄影影像、 ...): 客戶向伺服器提出請求 (箭頭方向), 伺服器提供資訊給客戶端 (貨車方向)。 至於綠色的 ssh 服務則是一條 "隧道", 用來幫紫色服務多開一個窗口 -- 把它拉到防火牆外面 -- 讓 "更多人" (小藍箭頭) 可以使用紫色的服務。 (原來的窗口當然還是可以繼續使用。)
如果紫色服務跟著 ssh 服務一起放在一部
具有公開 IP 的公司伺服器上面,
但紫色服務被防火牆保護住,
只允許少數人使用 (例如本公司辦公室內的員工),
而你卻需要從家裡/路上/旅館使用它,
那麼這時你就需要(從筆電上面)建立正向的 ssh 隧道。
語法類似這樣: ssh -4fNL
特權入口:localhost:閒人勿近的管制入口 ckhung@penguin.tw
這彷彿是在 「筆記電腦:特權入口」 多開一個匝道接到原來的
「penguin.tw:閒人勿近的管制入口」。 例如 「坐 ssh 火車過山洞」
那篇裡面的 vnc 所鑽的, 就是正向的 ssh 隧道。
如果紫色服務位於你的筆電或你家電腦上,
而且你想把它展示給世界看,
但是它無法對外提供 ssh 服務
(例如因為它沒有公開的 IP,
或是因為 ISP 好心地用防火牆保護住它),
那麼這時你就需要(從筆電上面)建立反向的 ssh 隧道。
語法類似這樣: ssh -4fNR
向朋友展示的櫥窗:localhost:只有我看到的服務 ckhung@penguin.tw
這彷彿是在 「penguin.tw:向朋友展示的櫥窗」 多開一個匝道接到原來的
「筆記電腦:只有我看到的服務」。
不僅如此, 還必須在 penguin.tw 幫朋友開一個 ssh 帳號,
這樣他才可以 (還有在 penguin.tw 上面有 ssh 帳號的任何人也都可以)
登入 penguin.tw, 下 (紫色服務的) 指令觀看
「localhost:向朋友展示的櫥窗」。
[推薦: 2023/8 autossh: 建立具有韌性的反向 ssh 隧道]
或者, 如果這個服務沒有隱私或機密的顧慮,
也可以不必幫朋友開帳號, 而是在 penguin.tw
的 /etc/ssh/sshd_config 裡面設定
GatewayPorts clientspecified
並且重新啟動 ssh 服務、
(在筆電,也就是 client 上面)改用這個指令鑿隧道: ssh -4fNR
'*:向朋友展示的櫥窗:localhost:只有我看到的服務' ckhung@penguin.tw
(前面加 *: 並且外面加單引號或雙引號)。
如此一來, 全世界都能透過 penguin.tw 伺服器
「penguin.tw:向朋友展示的櫥窗」 觀看你的筆電表演。 詳見
這個問答。
用一個具體的例子來練習反向 ssh tunneling。
- 在筆電上安裝 apache2 網頁伺服器。
- 在 /var/www/html/index.html 裡面打一些字。
- 用
lynx http://localhost/
指令確認伺服器架設成功。 - 在自己的伺服器 penuin.tw (如果沒有的話, 就拿桌機當伺服器)
的 /etc/ssh/sshd_config 裡面加上
GatewayPorts clientspecified
、 用service ssh restart
重新啟動 ssh 服務。 - 在伺服器上執行
lynx http://localhost:4380/
當然會連線失敗。 - 在筆電上鑿反向 ssh 隧道:
ssh -4fNR 4380:localhost:80 ckhung@penguin.tw
- 在伺服器上再次執行
lynx http://localhost:4380/
看見筆電的網頁! - 從筆電或手機看這個網址: http://penguin.im:4380/ 連線失敗。
- 在筆電上用
ps ax | grep 'ssh.*:.*:'
以及工人智慧 (肉眼) 找出先前鑿通的隧道並且用 kill 把它砍掉, 或是用這個指令直接砍掉 「本機上目前已鑿通的所有隧道」:kill $(ps ax | perl -ne 'print "$1\n" if (/(\d+).*\d\s+ssh.*:.*:/)')
- 重鑿一個 「對全世界開放」 的隧道:
ssh -4fNR *:4380:localhost:80 ckhung@penguin.tw
- 從筆電或手機再次看這個網址: http://penguin.im:4380/ 成功!
補充說明:
- 重要安全提醒: 實驗結束之後, 記得要砍掉所有的 ssh 隧道程序!
- 如果是真實世界的應用, 強力建議 把 ssh 設定密不透水。
- 不論是正向或反向 ssh 隧道, 鑿隧道時,
當然要用 ssh 伺服器那頭的帳號密碼, 而不是本機 ssh
帳號密碼或紫色服務的帳號密碼。
兩者都用到的
-fN
選項意思是說 「我們只要鑿隧道, 不需要命令列; 請丟到背景執行」。 - 至於一般的翻牆上網 (例如 「坐 ssh 火車過山洞」
那篇當中, 透過 ssh 隧道上網 (http over ssh)
採用的是正向, 但更靈活彈性的 SOCKS proxy
(
ssh -fND ...
)。 詳見 這個問答。 - 不論是哪一種 ssh tunnel 都同時兼具翻牆及保護隱私的效果。 隧道全程加密, 所以隧道途中經過的地方, 就算有 NSA 或其他潰客在監聽, 也只會看到亂碼。 你只需要顧慮 「進隧道之前」 及 「出隧道之後」 的隱私威脅。 這也是為什麼有些時候明明 vnc 已經通了, 卻還要再包一層 ssh。 (vnc over ssh) 詳見 隱私攻防觀念。
- 像我這種要看到命令列才有安全感的人, 出國玩的時候可能會想要用 ssh 連回家裡的電腦。 可是家裡的電腦沒有公開的 IP, 所以需要用反向 ssh 隧道把它拉到某部 (我所管轄的) 具有公開 IP 的伺服器上。 此時紫色的服務正好就是 ssh 本身, 所以只要鑿好反向 ssh 隧道, 一切就完工了。 詳見簡單明瞭的這一篇: 「Reverse SSH Tunnel 反向打洞實錄」。
- 幫朋友或客戶鑿反向 ssh 隧道時, 請務必要負責任地向他解釋必要性跟風險, 也要請他在完工後記得提醒你要關閉隧道, 這樣才不會被誤會/被指責是暗中開後門。
這篇的解釋, 觀念上適用於資料庫、 網頁、 串流音樂、 監視錄影影像、 ... 等等任何網路服務, 甚至是 windows 的 RDP 也可以。 至於實作上會遇到什麼問題? 請留言分享囉。
ngrok 有著異曲同工之妙
回覆刪除「在 /etc/ssh/sshd_config 裡面加上 GatewayPorts clientspecified」的設定教學,很少有中文教學提到。
回覆刪除感謝,很受用!
把一個簡單的觀念講的這麼複雜,看了非常累,不如參考這一編
回覆刪除http://fred-zone.blogspot.tw/2010/08/reverse-ssh-tunnel.html