本文討論如何用Tor + Nginx + Docker架設洋蔥網站(Onion Website)。

不是經營Tor realy節點,而是架設.onion網址的網站,專門給Tor網路的用戶訪問。
1. Tor網路連線架構簡介 #
什麼是Tor?The Onion Router,又稱洋蔥網路,是一種匿名上網的開源技術,連上網路的時候會經過多次伺服器跳轉,令人難以追蹤使用者,可以有效隱藏使用者的IP,保護上網隱私。
Tor俗稱暗網,儘管這個名稱並不準確。
在Tor網路裡面,可以架設Onion網站,提供匿名的連線功能。
別人是如何連接到你的Onion網站的?
這是Tor網路的概略連線方式:

Tor提供一個叫做Onion Service(舊稱Hidden Service)的功能,可以將你伺服器上的一個服務通訊埠開放給Tor網路,這樣就能架設Onion網站。讓使用者透過一組超長的.onion網址連線,而不需要知道伺服器的真實IP。
一般網站架設需要購買網域與設定DNS,並將網域指向伺服器IP;但Onion Service的運作方式不同。.onion 網址不是向註冊商購買來的,而是由一組加密金鑰產生。Tor會根據Onion Service的公鑰推導出對應的.onion網址,而私鑰則保存在你的伺服器上。
使用Onion Service架站的好處是,網站伺服器不需要開放公開IP,也不需要開放通訊埠讓外界直接連入。訪客透過Tor瀏覽器連線時,流量會在Tor網路中繞行,最後透過Rendezvous Point與Onion Service會合。這樣一來,訪客不會知道伺服器實際架設在哪裡,伺服器也不會直接得知訪客的真實IP。
換句話說,你的Onion網站究竟是架在公共VPS或者自己家裡的NAS,訪客都難以得知。
Tor Project官方有發表一個專案叫做Onionize,將現有網站轉爲Onion網站,Tor變成反向代理這樣。不過我是直接用Tor的Onion Servcie功能來架站。
2. 預期的連線架構 #
我的「網站」是用靜態HTML建立的網頁。當然你也可以使用動態網站技術。
我預期的連線方式處理:
Client → Tor網路 → Tor Container → Docker 內部網路 → Nginx Container → Hugo網站的HTML檔案

網頁伺服器使用Nginx就可以了,同時作爲HTTP伺服器與反向代理。能夠在需要的時候設定負載平衡。
要公開的HTML網頁用SSG生成,例如Hugo。
Onion網址在Docker服務重啓後通常不會變,因爲所有金鑰保存在你的伺服器目錄。只要這組私鑰沒有遺失,重啟Tor或遷移到其他機器後,仍然可以保留同一個.onion網址。
使用Docker容器方便遷移伺服器與網站。容器也能保護整個伺服器,讓Tor連線只能看到容器內部的網站與檔案。
3. 啓用HTTPS與購買網域的必要性 #
在你建立Onion Service之後就會自動獲得一個網址。所有.onion的網址是隨機根據加密金鑰生成的一長串網址。雖然理論上可以串自訂網域,可是如果你尋求匿名性,買網域是在自殺。
你還是可以自訂.onion的部分內容增加辨識度,例如Duckduckgo的.onion網址就有duckduckgo*的前綴。想要這種專門的網域,就是透過Tor Project官方工具Onionmine多抽幾次。
HTTPS同理,向憑證頒發機構Let’s Encrypt申請會暴露更多資料。在連線資料加密部分,Tor已經幫你做了,非必要。
除非你的網站需要連接到其他非Tor網域的服務,那麼加入HTTPS更保險。
4. 撰寫docker-compose #
-
在Linux伺服器安裝Docker
-
Tor服務,爲了安全性,我使用Tor Project官方發表的Onimages映像檔,不使用野生開發者打包的Tor。可惜這個映像檔沒有做MultiArch,只支援x86_64,ARM64架構的機器得用其他開發者的,例如osminogin/docker-tor-simple,或者自己用Alpine打包。
-
建立資料目錄
mkdir ~/onion-website
cd ~/onion-website- 建立docker-compose
vim docker-compose.yml- 填入內容如下。web網頁伺服器依賴tor這個服務的網路才能上網。不要使用ports暴露通訊埠,全部都在容器內部連線,對外只有Tor的80開放。Tor服務讓它讀取torrc設定檔啓動。
services:
web:
image: nginx:alpine
container_name: onion-nginx
restart: unless-stopped
volumes:
- ./public-onion:/srv:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- onion-net
tor:
image: containers.torproject.org/tpo/onion-services/onimages/tor:alpine
container_name: onion-tor
restart: unless-stopped
depends_on:
- web
command: ["tor", "-f", "/etc/tor/torrc"]
volumes:
- ./torrc:/etc/tor/torrc:ro
- ./tor-data:/var/lib/tor
networks:
- onion-net
networks:
onion-net:
driver: bridge- 預先修改目錄權限
mkdir ./tor-data
sudo chown -R 100:100 tor-data
sudo chmod -R 700 tor-data- 新增torrc設定檔
vim torrc- 填寫torrc,HiddenServicePort填寫Nginx的DNS。
HiddenServicePort是外部連線進來的通訊埠,維持預設的80。後面是要連線的服務,因爲是Docker內部連線所以寫service name加上要用的通訊埠就好。
SocksPort 0
HiddenServiceDir /var/lib/tor/onion/
HiddenServiceVersion 3
HiddenServicePort 80 web:8008
Log notice stdout- 新增nginx.conf
vim nginx.conf- 填寫要使用的伺服器位址和監聽的通訊埠,這只能在容器內由Tor存取
server {
listen 8008;
root /srv;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}- 建立網站目錄,再將要公開的HTML檔案放進去
public-onion,通常首頁應該是一個index.html檔案
mkdir ./public-onion- 啓動容器服務
docker compose up -d5. 存取Onion網站的方式 #
- 透過
docker logs tor,或著讀取檔案,查看你取得的.onion網址:
sudo cat ./tor-data/onion/hostname- 用Tor瀏覽器開啓.onion網址。由於Tor連線會經過多次跳轉,即使你是在區域網路連線過去也不會特別快。