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

如何在 VPS 架設 .onion 網站

在 Ubuntu 使用 tor 與 nginx 建立 v3 onion service,讓 nginx 僅綁定 loopback,並關閉可能將 .onion 位址連回公開 IP 的資訊外洩。

建置內容

Onion site 是只透過 Tor network 回應的標準 web server。安裝 tor,將兩行內容加入 /etc/tor/torrc,讀取 tor 寫入的位址,然後讓 nginx 綁定至 127.0.0.1,如此一來公開 IP 就不會回應任何請求。安裝只需 10 分鐘。其餘內容說明可能造成資訊外洩的項目,因為 onion site 最常見的失效原因,是自身設定直接指向營運者。

Tor 最初稱為「the onion router」,而 onion service 是只能透過 Tor 存取的服務。Version 3 位址包含 56 個字元,後接 .onion;這些字元是服務的 ed25519 public key、checksum 與 version byte,並以 base32 編碼。Version 2 位址包含 16 個字元,已於 2021 年從 network 移除,因此目前產生的位址都是 v3。位址本身就是 key,這會帶來兩項結果。連線會以端對端方式完成加密與驗證,不需要 certificate authority;如果遺失 key file,就會永久失去該位址。

您的 server 不會接受任何 inbound connection。Tor 會選取數個 relay 作為 introduction point,將 signed descriptor 上傳至 directory server,並在訪客選擇的 rendezvous relay 與每位訪客建立連線。這些連線全部由您的主機向外發起。不需要開放任何 port,也不需要發布 DNS record。

從 Tor Project repository 安裝 tor

Ubuntu 在 universe 中提供 tor 套件,但其版本通常接近發行版本凍結時的版本。Tor Project 自有的 repository 會追蹤目前的穩定版本。對於負責決定您的位址是否仍由您使用的軟體而言,這正是所需版本。

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

repository 項目使用 deb822 格式,Suites 必須是您的 Ubuntu 代號。請從 /etc/os-release 讀取,不要手動輸入。代號錯誤時,repository 仍可能正常解析,但不會提供適用於您發行版本的套件。

. /etc/os-release
sudo tee /etc/apt/sources.list.d/tor.sources >/dev/null <<EOF
Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: $VERSION_CODENAME
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpg
EOF
sudo apt update
sudo apt install -y tor deb.torproject.org-keyring

deb.torproject.org-keyring 套件會維持 signing key 最新,因此 key rotation 不會在一年後導致 apt update 失效。確認 tor 已啟動並連上網路:

tor --version
sudo journalctl -u tor@default -n 20

journal 最後應出現 Bootstrapped 100% (done): Done。若 tor 卡在 Bootstrapped 10%,表示沒有對外連線路徑。請檢查服務供應商的網路防火牆與您自己的對外連線規則:sudo ufw status verbose 應顯示 allow (outgoing) 為預設值。

接下來有兩個名稱需要注意。套件會以 debian-tor 使用者身分執行 tor,而執行中的 unit 是 tor@default.service,因為 Debian 與 Ubuntu 上的 tor.service 是包裝 instance 的 wrapper。請使用 instance 名稱查詢狀態與日誌,這樣取得的永遠是真正的程序。

在 torrc 中設定 onion service

/etc/tor/torrc 末尾新增以下兩行:

HiddenServiceDir /var/lib/tor/onion_site/
HiddenServicePort 80 127.0.0.1:8080

HiddenServiceDir 是 tor 保存此服務金鑰與位址的位置。請勿自行建立此目錄。Tor 啟動時會以所需的擁有者與模式建立它;如果您以 root 建立目錄,會導致下方失敗清單中的第一個錯誤。

HiddenServicePort 分為兩個部分,混淆兩者是最常見的第一個錯誤。第一個數字是訪客在 tunnel 內連線的連接埠,因此 80 才是預期值,沒有理由變更。第二個部分是 tor 將該網路流量轉送到的本機位址。單獨指定 HiddenServicePort 80 會轉送到 127.0.0.1:80;明確寫出位址並使用高號連接埠,可讓 onion vhost 避免與已在 80 上監聽的服務衝突。

sudo systemctl restart tor@default
sudo ls -l /var/lib/tor/onion_site/

清單應包含 hostnamehs_ed25519_public_keyhs_ed25519_secret_key,以及空的 authorized_clients 目錄。

讀取您的 .onion 位址

sudo cat /var/lib/tor/onion_site/hostname

輸出會回傳一行內容:56 個 base32 字元與 .onion。這個字串就是網站的完整身分。它不由任何人指派、無法轉移;只要您持有金鑰檔案,任何人都無法將其取走。請現在複製這個字串,因為以下每項設定都需要使用它。本指南其餘內容將其寫為 <your-address>.onion

讓 nginx 綁定在 127.0.0.1 來提供網站

sudo apt install -y nginx
sudo install -d -m 755 /srv/onion

寫入 /etc/nginx/sites-available/onion

server {
    listen 127.0.0.1:8080;
    server_name <your-address>.onion;

    root /srv/onion;
    index index.html;

    server_tokens off;
    etag off;
    access_log off;
    error_log /var/log/nginx/onion.error.log error;
}
echo '<h1>hello from the onion</h1>' | sudo tee /srv/onion/index.html
sudo ln -s /etc/nginx/sites-available/onion /etc/nginx/sites-enabled/onion
sudo nginx -t
sudo systemctl reload nginx

現在從伺服器確認兩件事。第一,nginx 會回應 onion 名稱;這就是 tor 會傳送的確切 Host 標頭:

curl -s -H 'Host: <your-address>.onion' http://127.0.0.1:8080/

第二,確認它只在該位址回應,不會在其他位置回應:

sudo ss -tlnp | grep 8080

位址欄必須顯示 127.0.0.1:8080。如果顯示 0.0.0.0:8080*:8080,表示你的 onion 網站也暴露在公開網際網路上,這是洩漏清單中的第一項。不含位址的 listen 8080; 行會綁定所有介面,這是預設行為。

在 Tor Browser 中開啟該位址。第一次載入需要幾秒,因為用戶端必須取得你的描述元並建立 rendezvous circuit。

Tor Project 自己的文件偏好使用 unix socket,而不是 loopback 埠:HiddenServicePort 80 unix:/var/run/tor/onion_site.sock,並讓 nginx 監聽該路徑。即使主機之後增加第二個介面,socket 也完全無法從其他主機連線。代價是檔案權限管理,因為 nginx 會建立 socket,而 tor 會以 debian-tor 身分連線,因此兩個使用者必須對該目錄的權限設定一致。搭配已驗證的 ss 輸出,使用 loopback 較容易設定正確,本指南其餘內容也採用這種方式。

網站使用 loopback 後,主機完全不需要為它設定入站規則。保留 22 供自己使用,並拒絕其餘連線(VPS 上值得設定的 ufw 預設值)。請注意,防火牆無法消除綁定至 0.0.0.0 的服務,只會過濾抵達防火牆的封包。容器會讓這個問題更明顯,因為 發布 Docker 埠會在 ufw 之前寫入 iptables 規則,因此 -p 8080:80 會讓你的 onion 後端服務暴露在公開 IP 上,即使 ufw 仍回報該埠遭到拒絕。請將容器埠發布為 -p 127.0.0.1:8080:80

會使 onion site 去匿名化的資訊

Tor 會隱藏伺服器的位置,但不會隱藏伺服器提供的內容。以下每一項都是由你自己的堆疊公開的資訊。

同一個 site 也在你的公開 IP 上回應

這是最容易被忽略的一項。掃描器會持續索引每個可路由位址的 HTTP 回應,而這些結果公開且可搜尋。如果你的公開 IP 與 onion 位址提供相同頁面,兩者只需透過一次查詢即可關聯:相同的標題、相同的 favicon 雜湊、相同的 ETag,以及相同的標頭順序。上方的 listen 127.0.0.1:8080; 行就是修正方式。請從其他機器驗證,不要在伺服器本身驗證:

curl -sv --max-time 5 http://<your-public-ip>:8080/

Connection refused 或逾時才是正確結果。任何 HTML 都表示該 site 已公開。如果這台主機也執行 clearnet site,請為該 vhost 設定獨立的 root,並在公開 listener 上保留明確的 default_server 區塊,讓不相符的 Host 標頭永遠不會落入 onion vhost。

版本標頭

curl -sI http://127.0.0.1:8080/ | grep -i '^server'

預設的 nginx 會回應 Server: nginx/1.24.0。這個版本字串與其他標頭的確切順序結合後,會形成可將 onion site 與 clearnet 主機比對的指紋。server_tokens off; 會將其簡化為 Server: nginx。這不會移除標頭,而且 nginx 沒有內建指令可做到這點,因此若要完全移除,通常使用 headers-more 模組。PHP 會加入 X-Powered-By,直到你設定 expose_php = Offetag off; 也應列入相同清單,因為 nginx 會根據檔案的修改時間與大小建立 ETag;因此,相同檔案複製到兩台伺服器後,兩邊提供的 ETag 也會相同。

指向 clearnet 網域的絕對 URL

一個 rel="canonical" 標籤、Open Graph og:url、RSS feed、sitemap、密碼重設 email,或硬編碼的 logo URL,都可能在 onion 提供的頁面中指向 clearnet site。請使用 /static/logo.svg 等以 root 為相對基準的路徑,並讓應用程式從請求的主機讀取 base URL,而不是使用固定值。重新導向也有相同問題,只是發生在另一個位置:catch-all block 中的 return 301 https://example.com$request_uri; 會將 onion 訪客送往你的實際網域,而 Location 標頭會直接提供答案。

與 clearnet site 共用的 TLS 憑證

onion 位址會自行驗證,因為該位址就是公開金鑰。因此,onion 連線上的 http:// 本身已是端對端加密,Tor Browser 也會將其視為安全內容環境。在 onion vhost 上安裝現有憑證會公開兩者之間的關聯,因為每張受公開信任的憑證都會記錄在 Certificate Transparency logs 中,而這些 logs 公開、永久保存,且可依名稱搜尋。請將 Let's Encrypt 憑證保留在 clearnet vhost,並讓 onion vhost 使用純 HTTP。

第三方字型與分析工具

來自 CDN(content delivery network)的字型或分析 script 都可能造成問題。訪客的瀏覽器會直接擷取每一項資源,因此第三方通常能知道有人載入了你的頁面,以及載入的是哪個頁面;Tor Browser 更嚴格的安全性層級也會封鎖這類請求,導致版面破損。請自行託管頁面所需的所有資產。

Host header 不相符

如果 server_name 不符合 tor 傳送的 Host 標頭,nginx 會針對該 listen 位址回退到預設伺服器。在只有一個 vhost 的主機上,這個問題不易察覺,因為唯一的 server block 同時也是預設伺服器。之後若新增 clearnet vhost,onion 請求可能開始落到該 vhost,連同其 canonical 標籤與重新導向一起被提供。每次修改 nginx 後都請重新執行 curl -H 'Host: ...' 檢查,並在結果中搜尋你的實際網域:

curl -s -H 'Host: <your-address>.onion' http://127.0.0.1:8080/ | grep -o 'https\?://[^"]*' | sort -u

了解哪個程序擁有哪個 socket,是這項工作的主要部分(Linux 上的連接埠與 listening socket 運作方式)。

Logs 中還會留下什麼

每個請求都來自 127.0.0.1,因此 nginx 沒有訪客位址可記錄,而 access_log off; 不會造成任何問題。其上的應用程式則不同,訂單、email 位址或上傳檔案的中繼資料都需要由你負責處理。你自己的操作習慣也很重要:透過未強化的登入方式管理主機,不在 Tor 的保護範圍內,因此請將 同一台 VPS 上的 SSH 強化 視為此建置的一部分。

備份私密金鑰,因為它就是該位址

/var/lib/tor/onion_site/hs_ed25519_secret_key 是服務本身。這裡沒有註冊商,也沒有復原機制。遺失私密金鑰,位址就會消失。複製私密金鑰後,任何持有副本的人都能在你的位址提供自己的內容,而你無法撤銷任何權限。

sudo systemctl stop tor@default
sudo tar -C /var/lib/tor -czf onion-keys.tgz onion_site
sudo chmod 600 onion-keys.tgz
sudo systemctl start tor@default

將該封存檔加密(gpg -c onion-keys.tgz),並移出伺服器保存。在新的 VPS 上還原時,只需要該封存檔,以及 ownership tor 預期的內容:

sudo systemctl stop tor@default
sudo tar -C /var/lib/tor -xzf onion-keys.tgz
sudo chown -R debian-tor:debian-tor /var/lib/tor/onion_site
sudo chmod 700 /var/lib/tor/onion_site
sudo systemctl start tor@default
sudo cat /var/lib/tor/onion_site/hostname

tor 重新發布 descriptor 後約 1 到 2 分鐘,相同位址就會在新硬體上恢復。整個遷移過程不需要變更 DNS,也不需要重新簽發憑證。

若網站也提供一般網路版本,設定 Onion-Location

如果 onion site 是為了便利而非保密,請從一般網路的 vhost 公開宣告:

add_header Onion-Location http://<your-address>.onion$request_uri;

接著,Tor Browser 會在網址列顯示 .onion available 按鈕,並提供切換選項。只有在一般網路頁面透過 HTTPS 提供,且該值為有效的 onion URL 時,瀏覽器才會接受這個標頭。

這裡有一項 nginx 規則需要注意。只有在 location 區塊未自行宣告任何 add_header 指令時,才會繼承這些指令。因此,具有自身 add_headerlocation 會悄悄捨棄 Onion-Location。請在該區塊重複設定,或將所有回應標頭集中在同一處。刻意發布這個標頭會明確建立兩個網站之間的關聯;這對鏡像網站是正確做法,但對任何必須保持無關聯的網站則不適用。

自訂地址

mkp224o會持續產生金鑰組,直到其中一組產生的地址以您指定的前綴開頭。這是暴力搜尋,因此除了前綴,以及您願意等待多久之外,沒有其他需要設定的項目。

sudo apt install -y git gcc libc6-dev libsodium-dev make autoconf
git clone https://github.com/cathugger/mkp224o
cd mkp224o
./autogen.sh
./configure --enable-amd64-51-30k
make
./mkp224o -d onionkeys blog

每次找到符合項目時,onionkeys/<address>.onion/會將其存放在包含hostnamehs_ed25519_secret_key的目錄中。安裝時先停止 tor,將該目錄複製到您的HiddenServiceDir,然後套用上述還原程序使用的相同chownchmod 700

前綴長度決定全部成本。地址採用 base32,因此每增加1個字元,預期所需的金鑰數量就會乘以32。短前綴可在筆記型電腦上完成。長前綴則無法在您擁有的任何設備上完成。自訂前綴也會讓讀者習慣只辨識地址開頭的幾個字元,而不是完整地址;釣魚網站仿冒 onion site 正是利用這種習慣建立的。

錯誤情況與你會看到的訊息

重新啟動後沒有 hostname 檔案。 Tor 未啟動,或拒絕使用該目錄。sudo journalctl -u tor@default -n 50 會指出原因:

/var/lib/tor/onion_site/ is not owned by this user (debian-tor, 108) but by root (0). Perhaps you are running Tor as the wrong user?

這表示該目錄是手動建立的。修正擁有者與權限模式,或刪除該目錄,讓 tor 自行建立。

Tor Browser 顯示 Onionsite Not Found (0xF0)。 用戶端無法取得描述資訊,因此就網路的角度來看,該位址沒有發布任何內容。確認 tor 正在執行且已完成 bootstrap,逐字比對你輸入的位址與 sudo cat /var/lib/tor/onion_site/hostname,然後檢查系統時間。Tor 需要準確的時間來發布及驗證描述資訊,而 timedatectl 應回報 System clock synchronized: yes

位址解析成功,但頁面始終無法載入。 Tor 已完成 rendezvous,但在最後一跳,也就是從 tor 到 nginx 的連線上失敗。由於這一跳是本機連線,tor log 不會留下相關訊息。在伺服器上執行 curl -sI http://127.0.0.1:8080/Connection refused 表示 nginx 未啟動,或正在監聽的位址與 HiddenServicePort 指向的位址不同。

頁面可以載入,但所有連結都指向你的實際網域。 問題出在範本中的絕對 URL。執行上方的 grep -o 'https\?://[^"]*' 檢查,先修正其輸出的問題,再在任何地方分享該位址。

原本可以運作,但重新啟動後停止。 在依賴網站前,先刻意重新啟動主機一次,然後執行 sudo systemctl status tor@defaultsudo systemctl status nginx。手動啟動的服務在機器重新啟動前,看起來與已啟用的服務完全相同。

FAQ

我需要在防火牆中開放 Tor onion service 的連接埠嗎?

不需要。tor daemon 只會向外建立連線,連往 directory server、introduction point 和各個 rendezvous relay,因此不需要任何入站規則,網頁伺服器本身則監聽 127.0.0.1。請讓 ufw 對入站 traffic 維持預設拒絕,只允許 SSH。相同特性也表示 onion service 可在完全沒有 public IP 的 NAT(network address translation)後方機器上運作。

為什麼我無法在 Tor Browser 中連線到我的 .onion 位址?

請從伺服器開始逐層檢查。sudo journalctl -u tor@default -n 50 應顯示 Bootstrapped 100% (done): Done,接著在伺服器上執行 curl -sI http://127.0.0.1:8080/ 應回傳狀態列,再將你輸入的位址與 hostname 檔案比對,因為只要有一個字元錯誤,就會變成不同的服務。Onionsite Not Found (0xF0) 表示找不到該位址的 descriptor,通常代表 tor 未執行或系統時鐘錯誤。

我可以將 onion site 移至新伺服器並保留相同位址嗎?

可以。該位址衍生自 hs_ed25519_secret_key,因此請將完整的 HiddenServiceDir 複製到新主機,設定其擁有者為 debian-tor,權限設為 700,然後啟動 tor。descriptor 重新發布後,該位址就會恢復運作,且不需要更新 DNS 記錄。若遺失該檔案,位址將無法復原,因此請在建立當天將其加密備份到伺服器之外。

onion site 需要 HTTPS 憑證嗎?

不需要。這個 56 字元的位址就是該服務的 public key,因此連線已在端點之間完成加密與驗證;Tor Browser 也會將 http://.onion 名稱上視為安全內容環境。將 clearnet 憑證重複用於 onion vhost,反而比完全不使用憑證更糟,因為 Certificate Transparency 日誌公開可見,且會永久記錄哪些名稱共用同一張憑證。為 .onion 名稱購買憑證的唯一理由,是向簽發此類憑證的 CA 取得品牌保證,而該關聯本來就會公開。