SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-13

如何透過 Tor onion service 使用 SSH 且不開放連接埠

了解如何將 sshd 放在 Tor onion service 後方,讓 VPS 不接受任何輸入連線,涵蓋 v3 用戶端授權與避免鎖死的正確設定順序。

透過 Tor onion service 使用 SSH 的變更

透過 Tor onion service 使用 SSH,您可以管理不接受任何連接埠輸入連線的 VPS。伺服器會向外連線至 Tor network,並維持該連線。您的 SSH 工作階段會沿著這條連線返回,因此不需要在公開 IP 位址上監聽任何連接埠。

日誌中的變化會立即出現。具有公開 SSH 連接埠的主機每天會從掃描器收到數千次失敗的密碼嘗試。將 sshd 移至 onion service 後,並在防火牆丟棄輸入流量,/var/log/auth.log 之後只會記錄您啟動的工作階段。

代價是,tor 會位於每次管理工作階段的路徑上。這是必須在每次重新開機後啟動並完成 bootstrap 的 userspace daemon,您必須等它完成後才能登入。關閉連接埠前,請先規劃這項需求,因為此處的故障情境是失去對無法實體接觸之機器的存取權。

先建立不依賴 SSH 的復原途徑

在建立復原途徑前,不要開始進行任何變更。

立即開啟服務供應商的主控台,也就是控制面板中的 VNC 或序列主控台,並使用它登入。如果不知道 root 密碼,請先從控制面板重設 root 密碼,再確認密碼可正常使用。從未測試過的主控台不算復原途徑。

以下順序很重要。每個步驟都必須確認成功後,才能執行下一步。在 onion route 可正常運作前,請保持 22 埠開放。

  1. 安裝 tor,並確認它已完成 bootstrap。
  2. 定義 onion service,並讀取其位址。
  3. 在 22 埠仍開放時,透過 onion 連線。
  4. 加入用戶端授權,然後再次連線。
  5. sshd 綁定至 loopback,並關閉 22 埠。
  6. 重新開機,然後再次透過 onion 連線。

全程保持目前的 SSH 工作階段開啟。已建立的工作階段可以在防火牆變更導致新連線遭到封鎖時繼續使用,因此它是第一道救援手段。

在伺服器上安裝 tor

Ubuntu 在自己的套件庫中提供 tor,但其中的版本通常較舊。Tor Project 的套件庫提供其文件所述的版本。請依照其 apt 套件庫指南 中的指令加入該套件庫。

sudo apt update
sudo apt install -y apt-transport-https wget gpg
wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | sudo tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/null

輸入 /etc/apt/sources.list.d/tor.sourcesSuites 會取得您的發行版代號,而 lsb_release -cs 會輸出該代號(Ubuntu 24.04 為 noble)。

Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: noble
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpg
sudo apt update
sudo apt install -y tor deb.torproject.org-keyring
sudo journalctl -u tor@default -n 20 --no-pager

日誌最後應顯示 Bootstrapped 100% (done)。若停留在這之前,表示 tor 無法連線到網路。幾乎都是因為對外連線的防火牆規則,或系統時間嚴重錯誤。

服務單元名稱容易造成誤判。 即使一切正常,systemctl status tor 仍會回報 Active: active (exited),因為 Debian 和 Ubuntu 將 tor 套件設計為多執行個體的主服務單元,其唯一工作是載入真正的執行個體。daemon 實際上以 tor@default.service 執行。請在 statusjournalctl 中使用該名稱。對 tor 執行啟動、停止及重新載入仍會套用到該執行個體,因此 sudo systemctl reload tor 仍會如預期運作。

設定 onion service 的 port 22

/etc/tor/torrc 中加入以下兩行。

HiddenServiceDir /var/lib/tor/ssh/
HiddenServicePort 22 127.0.0.1:22

第二行指示 tor 在 onion 位址上接受虛擬 port 22,並連線到這台主機上的 127.0.0.1:22。Tor 會透過 loopback 連線到 sshd,因此之後 sshd 可以停止監聽公開位址。

sudo systemctl reload tor
sudo cat /var/lib/tor/ssh/hostname

這會輸出 56 個 base32 字元,後面接著 .onion。這些字元是該服務以編碼格式表示的公開金鑰。這裡不涉及憑證授權單位,也不需要在任何地方註冊名稱。

讓 tor 自行建立 /var/lib/tor/ssh/。如果手動建立時設定了錯誤的擁有者,或權限比 0700 寬鬆,tor 會拒絕使用它,journal 也會回報該目錄的權限過於寬鬆。目錄內的檔案就是服務身分:hs_ed25519_secret_key 就是該位址。請以 mode 600 備份這個目錄,並將副本保存在這台主機之外,因為遺失它會導致位址變更,且每個 client 都必須修改設定。

從工作站連線

工作站需要 Tor client,完全不需要設定。在 Debian 或 Ubuntu 上,套件是 sudo apt install -y tor netcat-openbsd。接著 Tor 會在 127.0.0.1:9050 監聽,作為 SOCKS5 proxy。SOCKS 是通用的 proxy protocol,而第 5 版可以傳送 hostname,不必使用 IP address。這正是此處需要的功能。

OpenSSH 本身沒有 SOCKS client,因此需要透過輔助程式建立連線。將以下內容加入 ~/.ssh/config

Host myvps
  HostName xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion
  User admin
  ProxyCommand /usr/bin/nc -X 5 -x 127.0.0.1:9050 %h %p
  ServerAliveInterval 30

-X 5 會選擇 SOCKS5,-x 127.0.0.1:9050 會指向本機的 Tor。%h 會將 onion name 以名稱形式交給 Tor,讓 Tor 在網路內解析。這裡必須使用 OpenBSD netcat。GNU netcat 沒有 -X 選項,並會以 nc: invalid option -- 'X' 結束。

ssh myvps

第一次連線會比較慢,因為 Tor 必須先建立 circuit。請像處理其他連線一樣接受 host key fingerprint。從這裡開始,一般的 SSH key 處理方式不變。變更的是傳輸方式,驗證方式沒有變更。

如果只需使用一次,可以略過設定項目:torsocks ssh admin@xxxxx.onion 可執行相同功能。

新增 v3 用戶端授權

目前只要知道該位址,任何人都能連到您的 SSH banner 並開始猜測。Onion 位址無法從目錄系統列舉,因此看似秘密,但仍可能透過一般方式外洩,例如 shell 歷程記錄,或提交至 git repository 的設定檔。用戶端授權可堵住這個漏洞。服務會將 descriptor 加密後發布給用戶端金鑰,因此只有位址而沒有金鑰的人,甚至無法找到該服務。

在用戶端產生 x25519 金鑰組。以下是 Tor Project 用戶端授權指南中的 pipeline,但有一項變更。

openssl genpkey -algorithm x25519 -out /tmp/k1.prv.pem
grep -v " PRIVATE KEY" /tmp/k1.prv.pem | base64 -d | tail --bytes=32 | base32 | sed 's/=//g' > /tmp/k1.prv.key
openssl pkey -in /tmp/k1.prv.pem -pubout | grep -v " PUBLIC KEY" | base64 -d | tail --bytes=32 | base32 | sed 's/=//g' > /tmp/k1.pub.key

指南所發布的版本使用 base64pem -d,但標準 Ubuntu 安裝不包含此工具。該命令接著會因 base64pem: command not found 而停止。GNU base64 -d 能解碼相同的 PEM 內容,因此請改用它。

在伺服器上安裝公開金鑰。

sudo install -d -m 700 -o debian-tor -g debian-tor /var/lib/tor/ssh/authorized_clients
echo "descriptor:x25519:PASTE_PUBLIC_KEY_HERE" | sudo tee /var/lib/tor/ssh/authorized_clients/laptop.auth >/dev/null
sudo chown debian-tor:debian-tor /var/lib/tor/ssh/authorized_clients/laptop.auth
sudo systemctl reload tor

只有以 .auth 結尾的檔案才會讀取。請將檔案儲存為 laptop.auth.txt;如果檔名不符合條件,tor 會忽略該檔案且不輸出錯誤,服務也會繼續對任何知道位址的人開放。

在用戶端上安裝私密金鑰。在 Ubuntu 上,tor daemon 以 debian-tor 使用者身分執行,無法讀取 home directory 中的檔案,因此請將該目錄放在此使用者可存取的位置。

sudo install -d -m 700 -o debian-tor -g debian-tor /var/lib/tor/onion_auth
echo "ADDRESS_WITHOUT_DOT_ONION:descriptor:x25519:PASTE_PRIVATE_KEY_HERE" | sudo tee /var/lib/tor/onion_auth/myvps.auth_private >/dev/null
sudo chown debian-tor:debian-tor /var/lib/tor/onion_auth/myvps.auth_private
sudo chmod 600 /var/lib/tor/onion_auth/myvps.auth_private

ClientOnionAuthDir /var/lib/tor/onion_auth 加入用戶端的 /etc/tor/torrc,然後重新載入 tor。如果您以自己的使用者身分執行 tor,例如在 macOS 上使用 Homebrew build,請將 ClientOnionAuthDir 指向 ~/.tor/onion_auth,並將模式設為 0700。

該檔案中的位址是 56 個字元,不含 .onion suffix。完成後刪除 /tmp/k1.prv.pem/tmp/k1.prv.key

現在測試兩個方向。ssh myvps 應仍能連線。從沒有金鑰的機器連線至相同位址時,應會失敗。此失敗即可證明授權已啟用。

關閉連接埠 22,依照以下順序操作

先建立安全機制。如果因操作失誤而失去連線,這個命令會在十五分鐘後復原下方兩項變更。

sudo systemd-run --on-active=15m --unit=ssh-rescue \
  /bin/sh -c 'ufw allow 22/tcp; rm -f /etc/systemd/system/ssh.socket.d/override.conf; systemctl daemon-reload; systemctl restart ssh.socket'

確認 onion 路由仍可運作後,使用 sudo systemctl stop ssh-rescue.timer 取消復原排程。

接著,停止 sshd 在公開位址上監聽。Ubuntu 24.04 會透過 socket unit 啟用 SSH,因此在 sshd_config 中設定 ListenAddress 不會生效:負責監聽 socket 的是 ssh.socket,不是 sshd。請先確認目前屬於哪種情況。

systemctl is-enabled ssh.socket

如果輸出 enabled,請執行 sudo systemctl edit ssh.socket,並加入下列內容。

[Socket]
ListenStream=
ListenStream=127.0.0.1:22

空白的 ListenStream= 會清除從套件提供的 unit 繼承而來的值。若省略該行,系統會新增第二個監聽器,同時保留公開監聽器。這是此步驟最常見、且不會明確顯示錯誤的失敗方式。

sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
ss -tlnp | grep ':22'

ss 應顯示 127.0.0.1:22,且 0.0.0.0:22 不應有任何內容。如果 ssh.socket 已停用,請將 ListenAddress 127.0.0.1 加入 /etc/ssh/sshd_config.d/10-onion.conf,執行 sudo systemctl restart ssh,再使用相同的 ss 行檢查。無論是哪種情況,該輸出都是確認結果的依據。

接著處理防火牆。這是 VPS 上一般的 ufw 規則管理。先執行 sudo ufw status numbered,並刪除其中列出的 SSH 規則。

sudo ufw status numbered
sudo ufw delete allow OpenSSH
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw status verbose

保留傳出流量允許。Tor 會透過 443、9001 等連接埠連線至 relay,因此傳出流量預設拒絕的政策會阻止 tor 完成 bootstrap,並同時移除唯一剩餘的連線方式。大多數供應商也會在控制面板中提供獨立的網路防火牆。請一併在該處關閉 22,否則無論 ufw 顯示什麼結果,該連接埠仍可連線。

如果此主機執行 Docker,完成前請先檢查已發布的連接埠。Docker 會將自己的規則寫入相同的 tables,並將容器連接埠 直接發布而繞過 ufw,因此 ufw 的 deny 政策並不能反映完整狀況。

重新開機後再確認服務

systemctl is-enabled tor@default
sudo reboot

如果第一個命令沒有回報服務已啟用,請在重新開機前執行 sudo systemctl enable tor@default。等待 2 分鐘,然後執行 ssh myvps。Tor 必須在開機後完成 bootstrap,因此 onion 位址會在主機啟動一段時間後才開始回應。

如果服務始終無法恢復,請開啟主控台並讀取 sudo journalctl -u tor@default -b。其中會顯示 torrc 語法錯誤或目錄權限問題。套用 torrc 修改前,也可以先檢查設定。

sudo -u debian-tor tor --verify-config

WireGuard tunnel 相較之下的成本

自行 VPS 上的 WireGuard VPN 相比,onion service 較慢,也較難預測。決定採用前,請先誠實評估這項取捨。

延遲。 用戶端 circuit 會經過 3 個 relay,而服務端還會再增加 3 個,因此您輸入的每個按鍵大約會穿過全球隨機選出的 6 台機器。互動式輸入會有明顯延遲,檔案複製速度也很慢。WireGuard 只增加 1 個 hop。請使用 time ssh myvps 'echo ok' 測量您的實際情況,因為數值取決於 tor 當時建立的 circuit,且 tor 建立另一個 circuit 後,數值就會改變。

位於關鍵路徑上的 userspace daemon。 WireGuard 位於 kernel 中,會隨網路啟動。Tor 則是必須啟動、完成 bootstrap,並連線至 guard relay 後才能運作的程序。它失敗時,您只能使用 provider console。

時鐘準確度。 Onion service descriptor 會依時間週期發布,因此時鐘嚴重錯誤時,address lookup 會失敗,而且任何地方都不一定會顯示清楚的訊息。timedatectl 應回報 System clock synchronized: yes

您換回的是不再取決於防火牆規則是否正確的暴露面防護。沒有可供掃描的 port,也沒有可擷取的 banner;此外,該 address 本身就是 public key,因此 endpoint 在 SSH 啟動前就能證明自己的身分。

實務上通常兩者都使用。日常連線使用 WireGuard,並保留 onion service,作為 WireGuard 設定錯誤時仍可運作的路徑。如此只需開放 1 個 UDP port,而不是公開 SSH port。這些措施都不能取代 強化 sshd 本身:仍應使用僅限 key 的驗證方式,並禁止以 root 登入,因為 onion service 只保護網路路徑,不會保護其後的任何部分。

失效情況與您會看到的錯誤

Tor 永遠無法通過 Bootstrapped 0% 出站網路流量遭到封鎖,或系統時鐘偏差過大。使用 sudo ufw status verbose 檢查輸出政策,然後執行 timedatectl

systemctl status tor 顯示 active (exited) 這在 Debian 和 Ubuntu 上屬於正常情況。請改讀 tor@default

找不到 descriptor。 Tor 傳回 SOCKS 擴充錯誤 F0:「找不到 Onion Service Descriptor」。可能是 descriptor 尚未發布;重新載入後需要短暫時間才能完成。也可能是伺服器上的 tor 未執行。

F4,「缺少 Onion Service 用戶端授權」。 用戶端沒有符合條件的 .auth_private 可供 tor 使用。確認 torrc 中有 ClientOnionAuthDir、目錄模式為 0700、檔名以 .auth_private 結尾,並確認 debian-tor 可以讀取該檔案。

F5,「Onion Service 用戶端授權錯誤」。 私密金鑰與伺服器上的 .auth 檔案不相符。base32 字串末尾多出 = 或字串內含多餘換行,都會造成此問題。

nc: invalid option -- 'X' 安裝的是 GNU netcat,而不是 OpenBSD 版本。請執行 sudo apt install -y netcat-openbsd

Could not resolve hostname ssh 嘗試使用一般 DNS 查詢,但 .onion 沒有 DNS 回應,因此 ProxyCommand 從未執行。~/.ssh/config 中的 Host 模式與您輸入的名稱不相符。

Permission denied (publickey) 通道運作正常,tor 已完成工作。請將此視為一般的 permission denied publickey 問題,不要將問題歸咎於 tor。

FAQ

onion service 是否真的代表 VPS 上沒有開放連接埠?

是,只要 sshd 綁定至 127.0.0.1,且防火牆丟棄入站流量即可。Tor 會向 relay 建立出站 TCP 連線,您的工作階段會經由該連線返回,因此伺服器不會在公開位址上接受連線。可在伺服器上使用 ss -tlnp,再從其他位置執行連接埠掃描來驗證。不要忘記供應商控制面板中的網路防火牆。它與 ufw 分開管理,也必須一併關閉相關連接埠。

.onion 位址本身是否足以保護 SSH?

不夠。該位址長達 56 個字元,無法透過目錄系統猜測或列舉,因此具有 secret 的特性,但仍可能透過 shell history 和設定檔洩漏。請加入 v3 client authorisation。啟用後,service descriptor 會使用您的 client key 加密,因此只有位址的人會收到 extended error F4,根本無法連到 sshd。

重新開機後 tor 無法啟動時會發生什麼事?

您會完全失去 SSH 存取權,因為此時 onion 位址是唯一的登入途徑。因此,關閉 22 埠前,必須先測試供應商提供的主控台。Tor 在開機後也需要時間完成 bootstrap,因此 onion 位址會比伺服器開始回應 ping 更晚可用。若始終沒有回應,請透過主控台登入並查看 sudo journalctl -u tor@default -b。其中會記錄 torrc 語法錯誤,或 /var/lib/tor/ssh 的權限問題。

SSH over Tor 是否比 WireGuard 慢?

是,慢很多。連往 onion service 的連線會通過約 6 個隨機選取的 relay,而 WireGuard 只需經過一個加密 hop,直接連到伺服器。輸入指令時會明顯延遲,檔案傳輸速度也較慢。常見做法是日常工作使用 WireGuard,並保留 onion service 作為緊急路徑,以便在 VPN 設定損壞時仍能存取伺服器。