SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-27

VPSで.onionサイトを構築する方法

Ubuntuでtorとnginxを使い、loopbackに限定したv3 onion serviceを構築します。公開IPへの漏えいを防ぐ設定と、56文字のアドレスの注意点も解説します。

構築するもの

onion site は、Tor ネットワーク経由でのみ応答する通常の Web サーバーです。tor をインストールし、/etc/tor/torrc に 2 行を追加して、tor が出力したアドレスを確認します。その後、nginx を 127.0.0.1 にバインドし、パブリック IP では何も応答しないようにします。インストールには 10 分かかりません。残りの作業では、情報漏えいにつながる設定を確認します。onion site が機能しなくなる主な原因は、サイト自身の設定が運用者の環境へ直接戻るように指定されていることです。

Tor は当初「the onion router」として始まり、onion service は Tor 経由でのみアクセスできるサービスです。Version 3 のアドレスは 56 文字に続いて .onion が付きます。これらの文字列は、サービスの ed25519 公開鍵、チェックサム、バージョンバイトを base32 でエンコードしたものです。Version 2 のアドレス(16 文字)は 2021 年にネットワークから削除されたため、現在生成されるものはすべて v3 です。アドレス自体が鍵であるため、2 つの点が重要です。証明書認証局を介さず、接続はエンドツーエンドで暗号化および認証されます。また、鍵ファイルを失うと、そのアドレスを完全に失います。

サーバーは受信接続を一切受け付けません。Tor は複数のリレーを導入ポイントとして選び、署名付きの descriptor をディレクトリサーバーへアップロードします。その後、訪問者が選んだランデブーリレーで各訪問者と接続します。これらの接続はすべて、サーバーから外向きに開始されます。開放するポートはなく、公開する DNS レコードもありません。同じ VPS からネットワークへ別のサービスを提供したい場合は、形態が逆になる別の作業です。obfs4 ブリッジは検閲下のクライアントから受信接続を受けるため、到達可能なポートが必要です。

Tor Project のリポジトリから tor をインストールする

Ubuntu には universe に tor パッケージがありますが、リリース凍結時点のバージョンに近いままです。Tor Project の公式リポジトリは現行の安定版を追跡しています。アドレスを自分の管理下に維持できるかどうかを決めるソフトウェアには、こちらが適しています。ディストリビューションにパッケージが存在しても、現在も開発が続いているとは限りません。自分でホストするものでは、この点を確認する価値があります。実際、Searx では 2023 年以降コードコミットがなく、SearXNG がそのプロジェクトを引き継いでいます。

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

リポジトリのエントリには deb822 形式を使用します。Suites には Ubuntu のコードネームを指定する必要があります。入力せず、/etc/os-release から読み取ってください。コードネームを間違えると、リポジトリ自体は正常に解決されても、使用中のリリース向けのパッケージが存在しなくなります。

. /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 パッケージは署名キーを最新の状態に保ちます。そのため、キーがローテーションされても、1 年後に apt update が動作しなくなることはありません。tor が起動し、ネットワークに接続できたことを確認します。

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

journal の末尾は Bootstrapped 100% (done): Done になっているはずです。tor が Bootstrapped 10% で停止している場合、外向きの経路がありません。プロバイダー側のネットワークファイアウォールと、自分の egress ルールを確認してください。デフォルトの設定は sudo ufw status verbose により、allow (outgoing) と表示されるはずです。

ここからは、2 つの名前が重要になります。パッケージは debian-tor ユーザーとして tor を実行します。実行中の unit は tor@default.service です。Debian と Ubuntu の tor.service はインスタンスをラップする仕組みだからです。インスタンス名を指定してステータスとログを確認すれば、常に実際のプロセスを取得できます。

torrc で onion service を設定する

/etc/tor/torrc に次の 2 行を追加します。

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

HiddenServiceDir には、このサービスの鍵とアドレスが保存されます。自分で作成しないでください。Tor は起動時に、必要な所有者と mode でこのディレクトリを作成します。root で作成したディレクトリを使うと、下記の失敗一覧にある最初のエラーが発生します。

HiddenServicePort には 2 つの部分があり、これを取り違えるのが最初によくあるミスです。最初の番号は、訪問者がトンネル内で接続するポートです。そのため、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/

一覧には hostname、hs_ed25519_public_key、hs_ed25519_secret_key と、空の authorized_clients ディレクトリが含まれているはずです。

.onion アドレスを確認する

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

1 行が返ります。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

次に、サーバー上で2点を確認します。1点目は、nginx が onion 名に応答することです。これは、tor が送信する正確な Host ヘッダーです。

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

2点目は、そのアドレスでのみ応答することです。

sudo ss -tlnp | grep 8080

アドレス列は 127.0.0.1:8080 になっている必要があります。0.0.0.0:8080 または *:8080 と表示される場合、onion サイトもパブリックインターネット上で公開されています。これは漏えい一覧の最初の項目です。アドレスのない listen 8080; 行は、すべてのインターフェースにバインドします。これがデフォルトです。

Tor Browser でそのアドレスを開きます。クライアントが descriptor を取得し、rendezvous circuit を構築するため、最初の読み込みには数秒かかります。

Tor Project の公式ドキュメントでは、loopback port より unix socket が推奨されています。HiddenServicePort 80 unix:/var/run/tor/onion_site.sock を使用し、nginx はそのパスで待ち受けます。socket は、後からサーバーに2つ目のインターフェースを追加しても、別のホストから到達できません。代わりに、ファイル権限の管理が必要です。nginx が socket を作成し、tor は debian-tor として接続するため、2つのユーザーでディレクトリの設定を一致させる必要があります。検証済みの ss 出力を使う loopback のほうが設定しやすく、このガイドの後半でもその構成を前提にします。

サイトを loopback で提供する場合、そのサイト用の inbound rule は不要です。自分用に 22 のみを開け、残りは拒否します(VPS で設定しておくべき ufw のデフォルト設定)。ファイアウォールは 0.0.0.0 にバインドしたサービスを無効化するものではなく、ファイアウォールに到達したパケットをフィルタリングするだけです。コンテナではこの点がより重要です。Docker port の公開は ufw より先に iptables ルールを書き込むため、-p 8080:80 によって onion backend が public IP 上に公開され、ufw ではその port が拒否されているように表示されます。コンテナの port は -p 127.0.0.1:8080:80 として公開します。

オニオンサイトを匿名化解除する情報漏えい

Tor はサーバーの場所を隠します。Tor はサーバーが発信する内容を隠しません。以下に挙げるものは、いずれも自分のスタックが公開する情報です。プライバシーツールを評判ではなく実際の保護範囲で評価する習慣は、自己ホスト型 SearXNG が隠すものを確認する際にも同じです。SearXNG が検索エンジンから隠せるのは IP だけで、それ以上ではありません。

公開 IP でも同じサイトが応答する

これは多くの人が見落とす点です。スキャナーは、ルーティング可能なすべてのアドレスの HTTP 応答を継続的にインデックス化しており、その結果は公開され、検索できます。公開 IP と onion アドレスの両方で同じページを配信すると、同一タイトル、同一 favicon ハッシュ、同一 ETag、同一ヘッダー順序によって、1 回の検索で両者を結び付けられます。上の listen 127.0.0.1:8080; 行が対策です。サーバー上ではなく、別のマシンから確認してください。

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

Connection refused またはタイムアウトになれば正しい結果です。HTML が返れば、そのサイトは公開されています。サーバーで clearnet サイトも運用している場合は、その vhost に専用の root を割り当て、公開リスナーに明示的な default_server ブロックを置いてください。これにより、一致しない Host ヘッダーが onion vhost にフォールスルーすることを防げます。

バージョンバナー

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

デフォルトの nginx は Server: nginx/1.24.0 と応答します。このバージョン文字列は、他のヘッダーの正確な順序と組み合わさることで、onion ホストと clearnet ホストを照合できるフィンガープリントになります。server_tokens off; により Server: nginx まで減らせます。ヘッダー自体は削除されません。nginx には削除用の組み込みディレクティブがないため、削除したい場合は通常 headers-more モジュールを使用します。PHP は expose_php = Off を設定するまで X-Powered-By を追加します。etag off; も同じ一覧に含めてください。nginx はファイルの変更時刻とサイズから ETag を生成するため、同じファイルを 2 台のサーバーにコピーすると、両方で同じ ETag が返されます。

clearnet ドメインを指す絶対 URL

rel="canonical" タグ、Open Graph の og:url、RSS フィード、サイトマップ、パスワードリセットメール、ハードコードされたロゴ URL。これらのどれか 1 つでも、onion 経由で配信されたページ内に clearnet サイトの名前を記載します。/static/logo.svg のような root 相対パスを使用し、アプリケーションには定数ではなくリクエストの host からベース URL を読み取らせてください。リダイレクトも別の場所に現れる同じ問題です。キャッチオールブロック内の return 301 https://example.com$request_uri; は onion の訪問者を実ドメインへ送り、Location ヘッダーはその答えを直接知らせます。

clearnet サイトと共有する TLS 証明書

onion アドレスは、そのアドレス自体が公開鍵であるため、自身を認証します。そのため、onion 接続上の http:// はすでにエンドツーエンドで暗号化されており、Tor Browser は安全なコンテキストとして扱います。既存の証明書を onion vhost にインストールすると、両者の関連が公開されます。公開的に信頼されたすべての証明書は Certificate Transparency ログに記録され、そのログは公開され、永続的に保存され、名前で検索できます。Let's Encrypt 証明書は clearnet vhost に置き、onion vhost は通常の HTTP のままにしてください。

サードパーティのフォントと分析ツール

CDN(content delivery network)から読み込むフォントや分析スクリプトも該当します。訪問者のブラウザーはそれぞれを直接取得するため、サードパーティは誰かがページを読み込んだことと、通常はどのページかを把握できます。また、Tor Browser のより厳格なセキュリティレベルではリクエストがブロックされるため、レイアウトが崩れます。ページに必要なすべてのアセットを自己ホストしてください。

Host ヘッダーの不一致

server_name が tor の送信する Host ヘッダーと一致しない場合、nginx はその listen アドレスのデフォルトサーバーへフォールバックします。vhost が 1 つしかないサーバーでは、唯一の server ブロックがデフォルトでもあるため、この問題は見えません。後から clearnet vhost を追加すると、onion のリクエストがその vhost に到達し、canonical タグやリダイレクトまで返されることがあります。nginx を変更するたびに curl -H 'Host: ...' の確認を再実行し、結果に実ドメインが含まれていないか grep してください。

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

どのプロセスがどのソケットを所有しているかを把握することが、この作業の大部分です(Linux でポートとリスニングソケットが動作する仕組み)。

ログに残る情報

すべてのリクエストは 127.0.0.1 から到着するため、nginx に記録できる訪問者アドレスはなく、access_log off; による負担もありません。ただし、その上で動作するアプリケーションは別です。注文、メールアドレス、アップロードされたファイルのメタデータは、自分で適切に扱う必要があります。自分の運用習慣も関係します。強化されていないログイン経由でサーバーを管理することは、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 への復元に必要なのは、アーカイブと 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 サービスが秘密ではなく利便性を目的とする場合は、クリアネットの vhost からその URL を通知します。

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

Tor Browser はアドレスバーに .onion available ボタンを表示し、切り替えを提案します。このヘッダーが有効になるのは、クリアネットのページが HTTPS で配信され、値が有効な onion URL である場合だけです。

ここでは nginx のルールに注意が必要です。add_header ディレクティブは、location ブロックに独自のディレクティブが1つもない場合にだけ継承されます。そのため、独自の add_header を持つ location では Onion-Location が暗黙に失われます。そこで同じ設定を記述するか、すべてのレスポンスヘッダーを1か所で管理します。このヘッダーを公開すると、2つのサイトが意図的に関連付けられます。ミラーサイトでは適切ですが、関連付けを避ける必要があるサイトには適していません。

Vanity アドレス

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/ に hostname と hs_ed25519_secret_key を格納します。インストールするには、tor を停止し、そのディレクトリを HiddenServiceDir にコピーしてから、上記の復元手順と同じ chown および chmod 700 を適用します。

コストはプレフィックスの長さで決まります。アドレスは base32 形式なので、要求する文字が 1 文字増えるごとに、必要な鍵の期待数は 32 倍になります。短いプレフィックスなら laptop でも処理が完了します。長いプレフィックスは、所有しているどのマシンでも処理が完了しません。Vanity プレフィックスを使うと、読者はアドレス全体ではなく先頭数文字だけを確認するようになります。これは、onion サイトのフィッシング用コピーが利用する習慣です。

障害パターンと表示される文字列

再起動後に 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) と表示される。 クライアントが descriptor を取得できていないため、ネットワーク上ではそのアドレスに何も公開されていません。tor が実行中でブートストラップ済みであることを確認し、入力したアドレスを sudo cat /var/lib/tor/onion_site/hostname と 1 文字ずつ比較してから、時刻を確認してください。Tor は descriptor の公開と検証に正確な時刻を必要とします。timedatectl は System clock synchronized: yes を返す必要があります。

アドレスは解決するが、ページが読み込まれない。 Tor はランデブーを完了した後、最後のホップである tor から nginx への接続に失敗しています。このホップはローカルで完結するため、tor のログには何も記録されません。サーバー上で curl -sI http://127.0.0.1:8080/ を実行してください。Connection refused は、nginx が停止しているか、HiddenServicePort が指しているアドレスとは異なるアドレスで待ち受けていることを意味します。

ページは読み込まれるが、すべてのリンクが実際のドメインに移動する。 テンプレート内の絶対 URL が原因です。上記の grep -o 'https\?://[^"]*' チェックを実行し、表示された内容を修正してからアドレスを共有してください。

動作するが、再起動後に停止する。 サイトを利用する前に、意図的に 1 回サーバーを再起動し、その後 sudo systemctl status tor@default と sudo systemctl status nginx を実行してください。手動で起動したサービスは、マシンを再起動するまで、有効化されたサービスと同じように見えます。

FAQ

Tor onion service 用にファイアウォールのポートを開く必要はありますか?

いいえ。tor デーモンは、ディレクトリサーバー、導入ポイント、各ランデブーリレーへの送信接続だけを確立します。そのため受信ルールは不要で、Web サーバー自体は 127.0.0.1 で待ち受けます。SSH のみを許可し、受信トラフィックに対する ufw のデフォルト拒否を維持してください。同じ性質により、onion service はパブリック 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 ファイルを比較してください。1 文字でも違えば、別のサービスになります。Onionsite Not Found (0xF0) は、そのアドレスの descriptor が見つからないことを示します。通常は tor が実行されていないか、システムクロックが間違っています。

onion サイトを新しいサーバーへ移行して、同じアドレスを維持できますか?

はい。アドレスは hs_ed25519_secret_key から導出されます。そのため HiddenServiceDir 全体を新しいサーバーへコピーし、所有者を debian-tor に設定してモード 700 にし、tor を起動します。descriptor が再公開されると、アドレスは再び利用できます。更新する DNS レコードはありません。そのファイルを失うとアドレスは復元できないため、作成した日に暗号化してサーバー外へバックアップしてください。

onion サイトに HTTPS 証明書は必要ですか?

いいえ。56 文字のアドレスはサービスの公開鍵です。そのため接続はエンドツーエンドで暗号化および認証され、Tor Browser は .onion の名前に対する http:// を secure context として扱います。clearnet の証明書を onion vhost で再利用するのは、何もしないより悪い対応です。Certificate Transparency のログは公開され、どの名前が同じ証明書を共有しているかを恒久的に記録するためです。.onion の名前に対して証明書を購入する唯一の理由は、証明書を発行する CA によるブランドの信頼性です。その関連付けは設計上公開されます。