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

Tor onion serviceでSSH、外部ポートを開けない設定

VPSの受信ポートを0にしてSSHを管理する方法です。torの導入、v3 client authorisation、port 22を閉じる前に接続確認する手順と、lockoutを防ぐ順序を解説します。

Tor onion service 経由の SSH で変わること

Tor onion service 経由の SSH を使うと、どのポートでも受信接続を受け付けない VPS を管理できます。サーバーは Tor ネットワークへ発信接続し、その接続を維持します。SSH セッションはその接続を通って戻ってくるため、パブリック IP アドレスで待ち受ける必要はありません。

ログへの影響はすぐに現れます。パブリック SSH ポートを持つサーバーでは、スキャナーによるパスワード認証の失敗が 1 日に数千件記録されます。sshd を onion service の背後に置き、ファイアウォールで受信トラフィックを遮断すると、/var/log/auth.log に記録されるのは自分で開始したセッションだけになります。

代わりに、すべての管理セッションの経路上に tor が入ります。これはユーザー空間で動作するデーモンで、ログインする前に再起動のたびに起動してブートストラップを完了する必要があります。ポートを閉じる前に、この点を考慮してください。この構成では、物理的にアクセスできないマシンへの接続を失う可能性があります。

何かを変更する前に復旧経路を確保する

SSH を使わない復旧経路を確保するまで、作業を開始しないでください。

今すぐプロバイダーのコンソールを開きます。コントロールパネルの VNC またはシリアルコンソールからログインしてください。root password が不明な場合は、先に パネルから root password をリセットし、ログインできることを確認します。一度もテストしていないコンソールは、復旧経路として使用できません。

以下の順序が重要です。各手順が正常に完了したことを確認してから、次の手順を実行します。onion route が機能するまで、port 22 は開いたままにします。

  1. tor をインストールし、bootstrap が完了することを確認します。
  2. onion service を定義し、アドレスを読み取ります。
  3. port 22 が開いている間に、onion 経由で接続します。
  4. client authorisation を追加し、再度接続します。
  5. sshd を loopback に bind し、port 22 を閉じます。
  6. reboot し、その後もう一度 onion 経由で接続します。

現在の SSH session は、作業全体を通して開いたままにしてください。確立済みの session は、新しい接続をブロックする firewall 変更後も維持されます。そのため、最初の救助手段になります。

サーバーに tor をインストールする

Ubuntu には tor が独自のリポジトリで収録されていますが、そのビルドは古いことがよくあります。Tor Project のリポジトリには、同プロジェクトのドキュメントで説明されているバージョンが収録されています。apt repository guide に記載されたコマンドで追加します。

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.sources を実行します。Suites はリリースのコードネームを受け取り、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 はネットワークに接続できません。ほとんどの場合、原因は外向き通信を遮断するファイアウォールルールか、時計の大幅なずれです。

unit 名には注意が必要です。 すべて正常でも、systemctl status tor は Active: active (exited) を報告します。Debian と Ubuntu では、tor が複数インスタンスを管理する master unit としてパッケージ化されており、その役割は実際のインスタンスを起動することだけだからです。デーモン自体は tor@default.service として動作します。status と journalctl には、この名前を使用します。tor の起動、停止、reload は引き続きインスタンスに到達するため、sudo systemctl reload tor は期待どおりに動作します。

ポート 22 の onion service を定義する

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

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

2 行目は、onion address 上の仮想ポート 22 を受け入れ、ホスト上の 127.0.0.1:22 に接続するよう tor に指示します。tor は loopback 経由で sshd に接続します。そのため、後で sshd が公開アドレスでの待ち受けを停止できます。2 行目の接続先を 127.0.0.1:80 上の Web サーバーに変更すると、同じ 2 つのディレクティブで onion address 上にサイトを公開できます。tor のインストール後に実行する 2 つ目のサービスとして便利です。

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

これにより、56 文字の base32 文字列に続いて .onion が表示されます。この文字列は、エンコードされたサービスの公開鍵です。ここには認証局も名前の登録もありません。

/var/lib/tor/ssh/ は tor 自身に作成させます。所有者を誤って手動で作成したり、0700 より緩いモードにしたりすると、tor はそれを使用せず、journal にディレクトリの権限が緩すぎると記録します。内部のファイルはサービスの識別情報です。hs_ed25519_secret_key が address です。このディレクトリを mode 600 でバックアップし、コピーはホスト外に保管してください。これを失うと新しい address が発行され、すべてのクライアントで設定変更が必要になります。

ワークステーションから接続する

ワークステーションには Tor クライアントが必要です。設定は不要です。Debian または Ubuntu では sudo apt install -y tor netcat-openbsd です。Tor はその後、127.0.0.1:9050 で SOCKS5 プロキシとして待ち受けます。SOCKS は汎用プロキシプロトコルです。バージョン 5 では IP アドレスの代わりにホスト名を渡せます。ここで重要なのはこの点です。

OpenSSH には SOCKS クライアントが組み込まれていないため、ヘルパープログラムを使って接続します。~/.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 名を名前として Tor に渡します。これにより、Tor がネットワーク内部で名前を解決します。OpenBSD netcat を使用する必要があります。GNU netcat には -X オプションがないため、nc: invalid option -- 'X' で停止します。

ssh myvps

最初の接続には時間がかかります。Tor が処理を開始する前に回線を構築するためです。ホスト鍵のフィンガープリントは、通常の接続と同じ方法で受け入れます。以降は、通常の SSH 鍵管理をそのまま使用できます。変わったのはトランスポートだけです。認証方法は変わりません。

1 回だけ接続する場合は、設定エントリを省略できます。torsocks ssh admin@xxxxx.onion でも同じ処理を実行できます。

v3 クライアント認証を追加する

現状では、アドレスを知っている人なら誰でも SSH バナーに到達し、推測を開始できます。Onion アドレスはディレクトリシステムから列挙できないため、アドレス自体は秘密情報のように機能します。ただし、shell の履歴や git リポジトリにコミットした設定ファイルなど、通常の経路で漏えいします。クライアント認証により、この問題を解消できます。サービスはクライアント鍵で暗号化した descriptor を公開するため、アドレスだけを持ち、鍵を持たない人はサービスの場所さえ特定できません。

クライアント上で x25519 鍵ペアを生成します。これは Tor Project のクライアント認証ガイドにあるパイプラインに、1 点変更を加えたものです。

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 デーモンが debian-tor ユーザーとして実行され、ホームディレクトリ内のファイルを読み取れません。そのため、このユーザーがアクセスできる場所にディレクトリを置きます。

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

クライアントの /etc/tor/torrc に ClientOnionAuthDir /var/lib/tor/onion_auth を追加し、tor を reload します。macOS の Homebrew ビルドのように tor を自分のユーザーとして実行する場合は、ClientOnionAuthDir を ~/.tor/onion_auth に設定し、モードを 0700 にします。

そのファイル内のアドレスは、.onion サフィックスを除いた 56 文字です。作業が終わったら /tmp/k1.prv.pem と /tmp/k1.prv.key を削除します。

次に、両方向をテストします。ssh myvps からは引き続き接続できるはずです。鍵を持たないマシンから同じアドレスに接続すると、失敗するはずです。この失敗により、認証が有効であることを確認できます。

ポート 22 をこの順序で閉じる

最初に安全策を設定します。次の2つの変更によって接続できなくなった場合、この1つのコマンドで15分後に両方を元に戻せます。

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 route が引き続き機能することを確認したら、sudo systemctl stop ssh-rescue.timer でキャンセルします。

次に、公開アドレスで sshd が待ち受けないようにします。Ubuntu 24.04 では socket unit を介して ssh が有効になるため、sshd_config の ListenAddress は無視されます。待ち受けソケットを所有するのは sshd ではなく ssh.socket です。まず、自分の環境がどちらに該当するか確認します。

systemctl is-enabled ssh.socket

enabled と表示された場合は、sudo systemctl edit ssh.socket を実行して、次の内容を追加します。

[Socket]
ListenStream=
ListenStream=127.0.0.1:22

空の ListenStream= は、パッケージの unit から継承した値を消去します。この行を省くと、公開側の待ち受けを残したまま2つ目の待ち受けが追加されます。この手順がエラーを表示せずに失敗する場合の、最も一般的な原因です。

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 が無効になっていた場合は、/etc/ssh/sshd_config.d/10-onion.conf に ListenAddress 127.0.0.1 を記述し、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 などのポートでリレーへ送信接続するため、送信のデフォルト拒否ポリシーを設定すると、tor のブートストラップが停止し、同時に残された唯一の接続経路も失われます。多くのプロバイダーは、コントロールパネル内で別のネットワークファイアウォールも提供しています。そこで 22 も閉じてください。そうしないと、ufw の報告にかかわらずポートへ到達できます。

このホストで Docker が動作している場合は、作業完了と判断する前に公開ポートを確認します。Docker は同じテーブルに独自のルールを書き込み、コンテナのポートを ufw を経由せず直接公開するため、ufw の拒否ポリシーだけでは全体を把握できません。

信頼する前に再起動する

systemctl is-enabled tor@default
sudo reboot

最初のコマンドでサービスが有効になっていると表示されない場合は、再起動する前に sudo systemctl enable tor@default を実行します。2 分待ってから、ssh myvps を実行します。Tor は起動後にブートストラップするため、マシン自体の起動後、しばらくしてから onion アドレスが応答を開始します。

サービスが復帰しない場合は、コンソールを開いて sudo journalctl -u tor@default -b を読みます。torrc の構文エラーやディレクトリの権限問題は、そこに出力されます。適用する前に torrc の編集内容を確認することもできます。

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

WireGuard トンネルと比べた場合のコスト

自分の VPS 上で WireGuard VPN を運用する場合と比べると、onion service は遅く、挙動も予測しにくくなります。導入を決める前に、このトレードオフを正しく把握してください。

遅延。 クライアント側の circuit は 3 つの relay で構成され、service 側にもさらに 3 つ加わります。そのため、入力したキー操作は世界中からランダムに選ばれたおよそ 6 台のマシンを経由します。対話的な入力には明確な遅延が生じ、ファイルコピーも低速です。WireGuard は 1 ホップだけ追加します。実際の環境では time ssh myvps 'echo ok' を使って測定してください。値は tor がその時点で構築した circuit に依存し、tor が別の circuit を構築すると変わります。

重要な処理経路にある userspace daemon。 WireGuard は kernel 内で動作し、ネットワークとともに起動します。Tor は起動して bootstrap を完了し、guard relay に到達する必要があるプロセスです。動作しなくなると、provider のコンソールから対応することになります。

時刻の正確性。 onion service の descriptor は時刻の期間に基づいて公開されるため、システム時刻が大きくずれていると、明確なエラーメッセージが表示されないままアドレス検索に失敗します。timedatectl は System clock synchronized: yes を報告する必要があります。

その代わりに得られるのは、ファイアウォールルールが正しいことに依存しない公開範囲です。スキャンできるポートも取得できるバナーもありません。また、アドレス自体が公開鍵であるため、SSH が開始する前にエンドポイントが自身の正当性を証明します。

実用上は、通常この 2 つを併用します。日常の経路には WireGuard を使い、WireGuard の設定が誤っている場合にも機能する経路として onion service を維持します。これにより、公開 SSH ポートではなく 1 つの UDP ポートだけを開けておけます。いずれも sshd 自体の強化の代わりにはなりません。onion service が保護するのはネットワーク経路だけで、それ以外は保護しないため、鍵のみの認証と root 以外でのログインは引き続き重要です。

障害のパターンと表示されるエラー

Tor が Bootstrapped 0% を通過しない。 外向きのトラフィックがブロックされているか、時刻が大きくずれています。sudo ufw status verbose で送信ポリシーを確認し、次に timedatectl を実行します。

systemctl status tor に active (exited) と表示される。 Debian と Ubuntu では正常です。代わりに tor@default を確認します。

ディスクリプターが見つからない。 Tor は SOCKS 拡張エラー F0「Onion Service Descriptor Can Not be Found」を返します。ディスクリプターがまだ公開されていない可能性があります。reload 後の公開には少し時間がかかります。あるいは、サーバー上の tor が起動していません。

F4「Onion Service Missing Client Authorization」。 クライアントに、tor が使用できる一致する .auth_private がありません。torrc に ClientOnionAuthDir があること、ディレクトリのモードが 0700 であること、ファイル名が .auth_private で終わっていること、debian-tor がそのファイルを読み取れることを確認します。

F5「Onion Service Wrong Client Authorization」。 秘密鍵がサーバー上の .auth ファイルと一致していません。末尾の = や、base32 文字列内の不要な改行が原因になります。

nc: invalid option -- 'X'。 OpenBSD 版ではなく GNU netcat がインストールされています。sudo apt install -y netcat-openbsd を実行します。

Could not resolve hostname。 ssh は通常の DNS を試行しましたが、.onion に対する応答がないため、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 とは別の制御機能であり、こちらも閉じる必要があります。

SSH では、.onion アドレスだけで十分なセキュリティを確保できますか?

いいえ。アドレスは 56 文字で、ディレクトリシステムから推測したり列挙したりできないため、Secret のように機能します。ただし、shell の履歴や設定ファイルから漏えいする可能性があります。v3 client authorization を追加してください。これを有効にすると、service descriptor は client key に対して暗号化されます。そのため、アドレスだけを知っている相手には拡張エラー F4 が返され、sshd には到達できません。

再起動後に tor の起動に失敗した場合、どうなりますか?

SSH 接続を完全に失います。onion address が唯一の接続経路になるためです。そのため、port 22 を閉じる前に、プロバイダーのコンソールをテストしておく必要があります。Tor は起動後の bootstrap にも時間がかかるため、マシンが ping に応答してから、アドレスが応答するまで遅れます。応答しない場合は、コンソールからログインして sudo journalctl -u tor@default -b を確認してください。torrc の構文エラーや /var/lib/tor/ssh の権限問題が出力されています。

SSH over Tor は WireGuard より遅いですか?

はい、大幅に遅くなります。onion service への接続は、ランダムに選ばれた約 6 台の relay を経由します。一方、WireGuard はサーバーへ直接接続する暗号化された 1 ホップの通信です。入力時には遅延を感じ、転送速度も低下します。一般的な構成では、日常の作業には WireGuard を使い、VPN 設定が壊れても利用できる緊急用の経路として onion service を残します。