Contents

sshuttle 一個免架設 VPN 的跳板代理工具

平常如果只是臨時要連內網服務,我大多會先想到 SSH Tunnel,通常用 -L-R-D 幾招就很夠用了。不過最近看到 sshuttle 這個工具,研究之後發現它滿有意思的。

它也是建構在 SSH 之上,但用起來比自己手動設定 Dynamic Port Forwarding 再加 SOCKS Proxy 更直接。某些情境下,你甚至可以把它當成「不用另外架 VPN Server,也能快速把指定網段流量送進遠端主機」的跳板工具。

先講結論
如果你只是臨時想進公司內網、測試某段私有網路、或想把 DNS 一起走遠端,sshuttle 會比傳統 SSH Tunnel 的設定更省事。它不是完整意義上的 VPN,但實際使用感受已經很接近。

文章重點心智圖

mindmap root((sshuttle)) 定位 建立在 SSH 之上 不用額外架 VPN Server 適合臨時跳板代理 優點 可代理整段網路 可搭配 DNS 遠端查詢 不必另外設定 SOCKS Proxy Client 需求 Root 權限 Python iptables Server 需求 SSH 服務 Python 不一定需要 Root 常用指令 全流量代理 指定內網網段 DNS 代理 排除特定子網 適用情境 臨時進內網 替代部分 VPN 場景 維運排錯與測試

什麼是 sshuttle

sshuttle 可以把本機要送往特定網段的流量,透過 SSH 轉到遠端主機,再由遠端主機幫你送出去。這種做法很像 VPN,但它並不是傳統的 TUN/TAP 型 VPN。

你可以把它理解成:

  1. 本機先攔截要送往指定網段的流量。
  2. 這些流量經由 SSH 傳到遠端主機。
  3. 遠端主機再代替你去連真正的目的地。

下圖就是我整理後比較直覺的概念圖:

architecture.avif

跟 SSH Tunnel 最大差異在哪裡

我自己覺得 sshuttle 最特別的地方有三個:

  1. 它可以直接針對 IP 範圍決定哪些流量要代理,不是只代理單一 Port。
  2. 它不需要像 Dynamic Port Forwarding 一樣,再額外去設定瀏覽器或系統的 SOCKS Proxy。
  3. 它支援把 DNS 查詢一起送到遠端處理,這點就很接近 VPN 的使用體驗。

如果用一句話比較:

  • SSH Tunnel 的 -D 比較像是「先開一個 SOCKS Proxy,再叫應用程式自己走代理」。
  • sshuttle 比較像是「直接在本機把指定網段的流量攔下來,交給 SSH 幫你送出去」。
適合什麼情境
如果你的目標只是臨時進某段內網、排查服務、存取資料庫、或驗證某個 DNS/網路問題,sshuttle 常常就夠用了。

Client / Server 主機需求

我一開始查資料時,發現網路上對安裝需求寫得不太一致。後來整理下來,比較接近實際狀況的是這樣:

角色 需求
Client Root 權限、Python、可操作 iptables
Server SSH Port、Python,通常不需要 Root

requirements.avif

原因其實不難理解:

  1. Client 端需要 Root,主要是因為 sshuttle 會動到本機的 iptables 規則,把指定流量重新導向。
  2. Server 端需要 Python,是因為 Client 會透過 SSH 把一段 Python 程式送過去執行,協助處理轉發。
  3. Server 端只要 SSH 能連、Python 能跑,通常就能工作,不一定要額外裝很重的 VPN 環境。
官方支援範圍
sshuttle 官方文件主要提到 Client 端支援 Linux、FreeBSD、macOS 這類 *nix 環境。Windows 目前不是它最自然的使用場景,如果真的要在 Windows 上用,建議先看官方文件中的 Windows 章節限制。

工作原理,我目前的理解

這部分我一開始也看了好幾篇資料,才稍微比較有感覺。簡單講,sshuttle 並不是把每個原始 TCP 封包原封不動塞進另一個 TCP 連線裡,而是:

  1. 在本機追蹤連線。
  2. 把資料流透過 SSH 這條可靠通道傳送。
  3. 到遠端再重新拆回對應的 TCP 連線。

所以它不像傳統 VPN 那樣以封包層為主,而是比較偏向「在使用者空間裡處理連線與資料流」。

這也是為什麼它看起來不像標準 VPN,實際用起來卻又很接近 VPN。再加上它能搭配 iptables 攔流量,體感上就會很像你把某些網段直接接到遠端機器後面。

實際驗證:為什麼 Client 要 Root、Server 要 Python

看完原理後,我回頭去驗證,發現這個需求其實可以直接從執行結果看出來。

Client 端會動到 iptables

sshuttle 啟動後,在 Client 端可以看到 NAT 規則被加上:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
ubuntu@primary:~$ sudo iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
sshuttle-12300  all  --  anywhere             anywhere

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
sshuttle-12300  all  --  anywhere             anywhere

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

Chain sshuttle-12300 (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL
RETURN     tcp  --  anywhere             localhost
REDIRECT   tcp  --  anywhere             anywhere             redir ports 12300

這也說明了為什麼 Client 端需要有足夠權限去調整 iptables

一個容易忘的小地方
如果你只下 iptables -L,通常看不到 NAT 規則,要記得加上 -t nat

Server 端會出現 Python 行程

Server 端則可以看到類似這種 Python 行程:

1
2
3
4
# ps aux | grep python

user      29681  0.5  2.1  16832  9572 ?        Ss   Sep04   0:01 python3 -c import sys, os; verbosity=0; sys.stdin = os.fdopen(0, "rb"); exec(compile(sys.stdin.read(1704), "assembler.py", "exec")); sys.exit()
ubuntu@primary:~$ sshuttle -r user@host.com 0.0.0.0/0

這代表 Client 真的會透過 SSH 在遠端拉起 Python 程式來協助處理資料流。

常用指令整理

1. 轉發所有流量

如果你想把所有流量都走遠端主機:

1
sshuttle -r username@sshserver 0.0.0.0/0

也可以縮寫成:

1
sshuttle -r username@sshserver 0/0

這是最像「整台機器直接接上遠端」的做法,但也最容易影響整體網路行為,所以我通常只會拿來短時間測試。

2. 臨時代理公司或內網網段

這個比較像實務上常用的模式,只代理私有網段,並讓 DNS 也一起走遠端:

1
sshuttle --dns -NHr username@sshserver 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16

幾個參數的意思如下:

  • --dns:把 DNS 查詢也交給遠端處理。
  • -N:自動偵測遠端路由表中的網段。
  • -H:把遠端主機名稱加入本機的 hosts 對應。
  • -r:指定要連線的 SSH 主機。

如果你是在 VPN 壞掉、但又臨時需要進公司內網查資料,這種用法我覺得很實用。

3. 代理 DNS 查詢

如果你除了連線,連 DNS 解析也想走遠端:

1
sshuttle --dns -r username@sshserver 0/0

這一招很適合處理「服務明明有通,但本機 DNS 解析不到內部網域」的情境。

4. 排除特定網段

如果你希望大部分流量走 sshuttle,但某一段網路維持本地直連,可以用 -x 排除:

1
sshuttle -r username@sshserver 0.0.0.0/0 -x 1.2.3.0/24

這樣 1.2.3.0/24 這段網路就不會被代理,仍然走你原本的本地網路路徑。

我自己的使用心得

實際看完之後,我會把 sshuttle 定位成下面這種工具:

  1. 它不是拿來完全取代正式 VPN 的。
  2. 但它很適合當成「快速、輕量、免額外架設」的臨時跳板方案。
  3. 如果你原本就有一台可 SSH 的跳板機,那它的導入成本其實非常低。

尤其是當你只是想快速進某段內網、驗證 API、連資料庫、打開內部網站、或排查 DNS 時,它比手動開 Dynamic Port Forwarding 再配應用程式代理方便很多。

使用詳細影片

參考資料

  1. sshuttle 官方文件
  2. sshuttle 說明整理
  3. sshuttle 工具介紹
  4. sshuttle 全域代理原理簡析
  5. Windows 使用方式

總結

如果你已經熟 SSH Tunnel,那 sshuttle 其實不難理解。它的核心價值不在於把 SSH 變得更神奇,而是在「讓指定網段流量經由 SSH 走遠端」這件事上,提供一個比手動 SOCKS Proxy 更接近實戰需求的做法。

對我來說,它很適合放進平常維運與排錯工具清單裡。哪天 VPN 剛好壞掉,但你手上還有一台能 SSH 的跳板主機,這工具就很可能派上用場。