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

VPSでTailscaleサブネットルーターを構築する方法

VPSからプライベートネットワークをtailnetへ広告する手順です。ルート承認、再起動後も有効なIP転送、Linuxで必要な--accept-routesフラグを確認できます。

Tailscale subnet router の役割

Tailscale subnet router は、プライベート IP アドレスの範囲全体を tailnet に広告するマシンです。その範囲内のデバイスで Tailscale が動作していなくても、tailnet 上のすべてのデバイスからそのアドレスへアクセスできます。tailnet は、1 つのアカウントまたは組織にサインインしているデバイスで構成される、プライベートな Tailscale ネットワークです。これと混同されやすいのが exit node で、役割は逆です。exit node は、デバイスのすべてのトラフィックを VPS 経由で外部へ送信し、そのデバイスのパブリックインターネットへの経路を VPS にします。

要点を 1 文で説明すると、subnet router は 1 つのプライベートネットワークを tailnet から到達可能にします。exit node は、パブリックトラフィックが外部へ出る場所を変更します。後者が必要な場合は、VPS で Tailscale exit node を実行する方法を参照してください。これらは別々のフラグであり、1 台の VPS で同時に両方を実行できますが、解決する問題は異なり、失敗する原因も異なります。

VPS でサブネットルーターが必要になる場合

一般的なのは、プロバイダーからすでにプライベートネットワークが提供されているケースです。VPS にはパブリックアドレスと、プライベートセグメント上の 2 つ目のインターフェースがあります。そのセグメント上の他のサーバーには、パブリックアドレスがありません。たとえばデータベースは 10.0.0.20、バックアップ先は 10.0.0.30 です。1 台の VPS に Tailscale をインストールして 10.0.0.0/24 を広告すると、ノートパソコンからそれらのプライベートアドレスへ直接アクセスできます。セグメント上の他の設定を変更する必要はなく、データベースにも引き続きパブリックアドレスはありません。そのセグメントから必要なのが 1 つのポートで動作する 1 つの Web アプリだけなら、範囲全体を広告するのは過剰です。その場合は、Tailscale serve でその単一ポートに HTTPS を設定できます。同じ考え方は、意図的に localhost のみで待ち受けるデーモンにも当てはまります。たとえば systemd の下でヘッドレスに動作する dsh では、その VPS の tailnet アドレスを使うことで、UI にアクセスするために別途維持していた SSH トンネルを置き換えられます。

もう 1 つは、VPS の反対側にあるネットワークです。独自のルーター配下にある自宅やオフィスの LAN(ローカルエリアネットワーク)、または、managed switch や、ファームウェアが固定されていて Tailscale を実行できない古い NAS など、Tailscale をまったく実行できない機器が集まるラックが該当します。そのネットワーク上の Linux マシン 1 台を、同じネットワーク内の他の機器すべてに対する subnet router として動作させます。この構成では、その手前にある自宅ルーターでポート転送を設定する必要はありません。Tailscale がルーターのポートを開かずに NAT を通過する仕組みでは、その理由と、relay にフォールバックする条件を説明しています。自宅では、このマシンとして、すでに運用している hypervisor 上の小さな VM を使うことがよくあります。どちら側にサービスを配置するかを決める前に、自宅の Proxmox ホストとレンタル VPS のコスト比較を確認しておく必要があります。

どちらのケースにも共通する要件が 1 つあります。サブネットルーターは、広告する範囲へ、自身のルーティングテーブルとファイアウォールを使って、すでに到達できなければなりません。Tailscale がこの接続を構築するわけではありません。Tailscale はルーターまでトラフィックを運び、転送処理をカーネルに渡します。

Tailscale をインストールし、最初にローカルルートを確認する

curl -fsSL https://tailscale.com/install.sh | sh

このスクリプトはディストリビューションを検出し、Tailscale のパッケージリポジトリを追加し、tailscale コマンドと tailscaled デーモンをインストールしてから、サービスを有効化します。systemctl is-active tailscaled で確認すると、active と表示されるはずです。

何よりも先に、VPS から広告する予定のネットワークへ到達できることを確認します。

ip route show
ping -c3 10.0.0.20

ip route show には、10.0.0.0/24 dev enp7s0 proto kernel scope link src 10.0.0.5 のように、実際のインターフェース上のプライベート範囲が表示されている必要があります。ここで、つまりルーター自体への ping が失敗する場合、Tailscale のどのフラグを指定しても解決できません。原因は VPS のネットワーク設定か、対象ホストのファイアウォールです。後続のテストはすべてこの接続に依存するため、まず問題を解決してください。

IP forwarding を有効にし、再起動後も維持する

Linux マシンは、forwarding が有効でない限り、自分宛てではないパケットを破棄します。他のマシンのパケットを転送することがサブネットルーターの役割なので、この手順は省略できません。

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf

sysctl net.ipv4.ip_forward で確認します。net.ipv4.ip_forward = 1 と表示されるはずです。

この手順を中途半端に実施するケースは少なくありません。sudo sysctl -w net.ipv4.ip_forward=1 はすぐに有効になりますが、次回の boot で無効に戻ります。そのため、サブネットルーターが数週間稼働した後、kernel upgrade に伴う再起動の翌朝に停止することがあります。分かりにくいのは、問題が起きているように見えない点です。tailscale status ではノードが online のままで、管理コンソールでも route は承認済みと表示され、クライアントにも route が設定されたままです。パケットは VPS に到達しますが、kernel がログを出さずに破棄します。値を /etc/sysctl.d/99-tailscale.conf に書き込むことで、再起動後も有効な状態に戻せます。

forwarding が無効なまま route を通知すると、tailscale up がその時点で警告します。Linux では、その行は Warning: IP forwarding is disabled, subnet routing/exit nodes will not work. に近い内容です。そのコマンドの出力を読み、スクロールして見落とさないでください。

ルートを広告する

sudo tailscale up --advertise-routes=10.0.0.0/24

すでに tailnet にサインインしている VPS では、代わりに設定をその場で変更します。

sudo tailscale set --advertise-routes=10.0.0.0/24

以降の変更では tailscale set を使用します。単一のフラグを指定して tailscale up を再実行すると、再指定しなかったフラグがリセットされます。また CLI は、設定をこの方法で変更するには、デフォルト以外のすべてのフラグを指定する必要があるというエラーを表示して処理を停止します。tailscale set は 1 つの設定だけを変更し、その他の設定はそのまま保持します。

複数の範囲は、スペースを入れずにカンマ区切りの 1 つのリストに指定します: --advertise-routes=10.0.0.0/24,192.168.50.0/24。各エントリは、CIDR 表記(classless inter-domain routing、10.0.0.0/24 形式)のネットワークアドレスである必要があります。誤って自分のホストアドレス(10.0.0.5/24)を指定すると、プレフィックスの後ろのビットが 0 ではないため拒否されます。エラーには、おそらく意図していたプレフィックスも示されます。広告を停止するには、sudo tailscale set --advertise-routes= で空のリストを設定します。

管理コンソールで経路を承認する

経路の広告はリクエストであり、変更ではありません。管理者が承認するまで、クライアントはその経路を受信せず、レンジ内のどの宛先にも到達できません。これは意図的な仕様です。自分自身を全員のルーティングテーブルに追加できるマシンがあると、任意のレンジのトラフィックを傍受できるためです。

管理コンソールの Machines ページで承認します。VPS にはサブネットバッジが表示されます。その行を開き、サブネットセクションで経路設定を編集し、経路にチェックを入れて保存します。

承認はプレフィックス単位で行われます。今日 10.0.0.0/24 を広告し、来月 192.168.50.0/24 を広告すると、新しいプレフィックスは未承認の状態で追加され、古いプレフィックスは引き続き機能します。承認済みの経路と無視された経路は VPS からは同じように見えるため、ほかの調査を始める前にコンソールを確認してください。

tailnet ポリシーファイルに autoApprovers ブロックを追加すると、手動の手順を省略できます。

{
  "autoApprovers": {
    "routes": {
      "10.0.0.0/24": ["tag:subnet-router"]
    }
  }
}

次に、そのタグ(sudo tailscale up --advertise-routes=10.0.0.0/24 --advertise-tags=tag:subnet-router)を付けてノードを起動すると、経路が広告された時点で承認されます。タグは、同じポリシーファイルの tagOwners セクションにあらかじめ存在している必要があります。スクリプトで VPS を再構築する場合は、この設定を行う価値があります。再構築されたノードは新しいノードとして扱われ、その経路は再び未承認の状態で始まるためです。

--accept-routes を指定しないと Linux クライアントがルートを無視する理由

ルートは広告され、承認されています。スマートフォンと Mac からは 10.0.0.20 に接続できます。しかし Linux ラップトップからは接続できず、管理コンソールにも問題は表示されません。

サブネットルートを受け入れるとは、クライアントのルーティングテーブルにエントリを書き込むことです。Android、iOS、macOS、tvOS、Windows では、Tailscale クライアントがこれを自動的に行います。Linux では行いません。Linux マシンは、意図してルーティングテーブルを設定したサーバーまたはルーターであることが多く、ネットワークから学習した /24 を黙って追加すると、そのマシンがすでに処理しているトラフィックを壊す可能性があるためです。そのため Linux では、各クライアントで明示的に有効化します。

sudo tailscale set --accept-routes

次に、ルートがどこに登録されたかを確認します。

ip route show table 52
ip route get 10.0.0.20

Linux の Tailscale は、受け入れたルートを main ルーティングテーブルには追加しません。ルーティングテーブル 52 に追加し、ポリシールールを設定します。これらのルールは、優先度 5210 から 5270 の範囲で ip rule show に表示され、一致しないパケットをそのテーブルへ送ります。そのため、ip route show だけでは 10.0.0.0/24 は表示されません。このコマンドだけを確認した読者は、--accept-routes が何もしていないと判断します。実際の状態を表示するコマンドは ip route show table 52 であり、tailscale0 に広告された範囲が表示されるはずです。

知っておくべき例外が 1 つあります。この Linux ノード自体が、ローカルネットワーク用の 2 台目のサブネットルーターである場合、--accept-routes によって、自身に直接接続されたサブネット宛てのトラフィックが自身のインターフェースではなく、もう一方のルーターを経由するようになります。高可用性ペアの待機ルーターでは、--accept-routes を無効のままにして、広告だけを行ってください。

障害パターン: 重複する範囲を広告する2台のルーター

2台のサブネットルーターが同一の範囲を広告することがあります。これは高可用性ペアの構成です。各ルーターがまったく同じプレフィックスを広告するため、クライアントは一方から他方へフェイルオーバーできます。プレフィックス長が異なる範囲の重複も許可され、Tailscale は最も具体的な一致を選択します。ルーター A が 10.0.0.0/24、ルーター B が 10.0.0.0/16 を広告している場合、10.0.0.20 宛てのトラフィックは A に送られます。

A がオフラインになった場合の動作は、予想と異なることがあります。オフラインのルーターは自身の広告を取り下げられないため、Tailscale は具体性の低いルートにフォールバックしません。クライアントは引き続き、より具体的なプレフィックスを優先します。10.0.0.20 宛てのトラフィックは停止します。一方、B の /16 だけがカバーする 10.0.1.20 宛てのトラフィックは、B 経由で引き続き動作します。症状としてはプライベートネットワークの一部が停止したように見えます。原因は、1台のオフラインノードがより具体的なプレフィックスを保持していることです。フェイルオーバーが必要な場合は、広い範囲を広告するルーターでも狭いプレフィックスを広告し、両方のルーターが同じアドレスをカバーするようにします。

もう1つの重複は、クライアント側に近い場所で発生します。192.168.1.0/24 のホテルネットワークに接続中に、サブネットルーターが 192.168.1.0/24 を広告すると、両者が同じ宛先を競合します。どちらが選ばれるかはプラットフォームによって異なります。Linux では、Tailscale 独自のルールより前にルールを追加し、ローカルアドレスに main table を使用させます。

sudo ip rule add to 192.168.1.0/24 priority 2500 lookup main

このルールは永続化されないため、次回のブート時に消えます。根本的な対策は、実際のネットワークで遭遇しないプライベート範囲を選ぶことです。192.168.0.0/24 と 192.168.1.0/24 は、多くのホームルーターでデフォルトとして使われています。そのため、意図的に選んだ 10.0.0.0/8 内の範囲を使用してください。同じ衝突は、手動で設定する通常の WireGuard VPNでも発生します。理由は同じです。より具体的なローカルルートが優先されるため、トラフィックがトンネルに入らなくなります。

障害パターン: DNS の解決先をカバーする経路がない

この障害は、エラーを報告する箇所がないため、デバッグが困難です。名前は解決されますが、接続はタイムアウトします。

db.internal.example.com がプライベート nameserver 経由で 10.0.5.20 に解決され、10.0.0.0/24 を広告したとします。DNS(domain name system)による名前解決と IP routing は別の処理であり、互いの状態を確認しないため、名前解決は成功します。その後、10.0.5.20 宛てのパケットに tailnet 上で一致する経路がないため、クライアントのデフォルトゲートウェイから送信され、到達しません。

次の2つのコマンドで、2つの処理を切り分けられます。

nslookup db.internal.example.com
ip route get 10.0.5.20

名前解決がアドレスを返す一方で、ip route get が dev tailscale0 で応答しない場合、名前解決は正常で、このクライアントに経路がありません。Linux クライアントでは、まず --accept-routes が有効か確認してください。これが無効だと、承認済みのプレフィックスがアドレスをすでにカバーしていても、サブネット経路はインストールされません。有効で、アドレスをカバーする承認済みプレフィックスがない場合は、10.0.0.0/16 または2つ目の明示的なプレフィックスとして、そのアドレスをカバーする範囲を広告します。その後、console で新しいプレフィックスを承認します。

nameserver 自体にも、対応する落とし穴があります。admin console で 10.0.0.53 のようなプライベートアドレスをグローバル nameserver に設定する場合、そのアドレスは承認済みの経路に含まれていなければなりません。含まれていないと、そのプライベートネットワーク上にないデバイスは resolver にまったく到達できません。到達できない resolver を指定したまま、ローカル DNS サーバーを上書きするオプションを有効にすると、直前まで動作していたデバイスも含め、tailnet 内のすべてのデバイスで名前解決が一斉に失われます。先に resolver への経路を広告して承認し、その後で DNS 設定を変更してください。トンネル内の DNS 障害の切り分けに苦労している場合は、WireGuard トンネルで DNS が機能しなくなる仕組みで、上位の調整レイヤーを除いた同じ仕組みを確認できます。

Source NAT とサイト間リンク

デフォルトでは、サブネットルーターが転送するすべてのパケットの送信元アドレスを、自身のプライベートアドレスに書き換えます。これが SNAT(source network address translation)です。プライベートネットワーク側を変更しなくても応答できるようにするために使用します。10.0.0.20 のデータベースは、到達方法をすでに認識している VPS に応答します。その代わり、データベースから見ると、tailnet からのすべての接続が VPS から来たように見えます。そのため、送信元ごとのファイアウォールルールやアクセスログからは、実際の接続元を把握できません。

クライアントの実際の tailnet アドレスを保持したい場合は、Linux で SNAT を無効にします。

sudo tailscale set --snat-subnet-routes=false

プライベートネットワーク内のホストには、100.64.0.0/10 への戻りの経路が必要です。100.64.0.0/10 は Tailscale がデバイスに割り当てるアドレス範囲で、サブネットルーターを経由するように指定します。この戻りの経路がないと、応答はデフォルトゲートウェイへ送られて到達しません。そのため、最初のパケットの後で接続が停止します。プライベートネットワークのゲートウェイに静的ルートを追加するか、SNAT を有効なままにします。

サイト間リンクでは、2 台のサブネットルーターが同時にこの処理を行います。それぞれが自身のネットワークを広告し、相手側のネットワークを受け入れます。

sudo tailscale up --advertise-routes=10.0.0.0/24 --snat-subnet-routes=false --accept-routes

もう一方のルーターでは、そのルーター自身のアドレス範囲を指定して対応するコマンドを実行します。2 つのアドレス範囲は異なっていなければなりません。ssh と ping は正常なのに大容量転送が停止する場合、原因は MSS(maximum segment size)です。これは、TCP パケットが運べるデータの最大サイズです。トンネルのオーバーヘッドによって、転送されたパケットが経路上の一部のリンクで大きすぎることがあります。MSS のクランプでこの問題を解決できます。

sudo iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

iptables-persistent でこのルールを保存してください。保存しないと、次回のブート時に消えます。

継続運用のための保守

2026 年 10 月時点では、Node のキーはデフォルトで 180 日後に期限切れになります。サブネットルーターのキーが期限切れになると、その Node はサインアウトし、設定をどこも変更していないのに、広告していた範囲全体へ到達できなくなります。管理コンソールの Machines ページで、このマシンのキーの有効期限を無効にし、実施したことを記録してください。上記の autoApprovers の例のように、タグを付けて起動した Node では、デフォルトでキーの有効期限が無効になっています。

Tailscale はピア間の直接接続を優先し、直接接続できない場合はリレーサーバーに切り替えます。リレーは機能しますが、遅延が増えます。公開アドレスを持つ VPS なら簡単です。受信 UDP 41641 を許可すれば、ほとんどのピアが直接接続します。プライベート範囲への通信が VPS の回線から想定される速度より遅い場合は、クライアントがサブネットルーターへ直接接続しているか、リレー経由かを確認することが最初に切り分けるポイントです。ファイアウォールを ufw で管理している場合は、VPS に実際に必要な ufw ルールで構文を確認できます。

アクセスルールも重要です。デフォルトの tailnet では、自分のすべてのデバイスから他のすべてのデバイスへ到達できるため、承認済みのルートはそのまま機能します。ACL ポリシーを作成すると、ルールの宛先側でプライベート範囲を対象にする必要があります。範囲を明示するか、承認済みのサブネットルートを含む * ワイルドカードを使用してください。10.0.0.20 は tailnet アドレスではないため、tailnet IP またはタグを対象にしたルールでは許可されません。

最後に、自分で運用しないコーディネーションサーバーを利用するかどうかを決めます。Tailscale のコントロールプレーンはホスト型サービスです。キーは自分のマシンに残りますが、アカウントとポリシーファイルはサービス側に置かれます。侵害されたコントロールプレーンや盗まれた認証情報を使って実際に何ができるのかは、プライベートネットワークへのルートを任せる前に確認しておくべき点です。Tailscale の信頼モデルでは、その境界が示されています。無料プランでは最大 6 ユーザーが各自無制限のデバイスを利用できるため、費用が理由で Tailscale の利用をやめることはほとんどありません。ただし、タグを付けて起動したサブネットルーターは、自分としてサインインしたサブネットルーターとは別の方法で数えられます。その上限を超えると、料金はマシン数ではなくユーザー数に応じて決まります。そのため、上限を超えるアカウントを追加する前に、無料プラン終了後に家庭や 5 人のチームで実際にかかる費用を確認しておくとよいでしょう。Headscale、セルフホスト型の Tailscale コントロールサーバーを運用すれば、この機能を自分の VPS に置けますが、保守が必要です。同じ懸念への別の対応は、Tailscale のクライアントも使わないことです。NetBird VPN サーバーをセルフホストする方法なら、コーディネーション層と独自のメッシュクライアントを、自分で管理する 1 台のマシンに配置できます。この方式と手動で設定を記述する方式のどちらにするか決めかねている場合は、WireGuard と Tailscale の比較で、コーディネーション層が提供する機能とそのコストを確認できます。

FAQ

サブネットルーターとexit nodeの違いは何ですか?

サブネットルーターはプライベートアドレスの範囲を広告するため、tailnet上のデバイスからTailscaleを実行していないマシンへ到達できます。exit nodeはインターネット全体への経路として自身を広告するため、デバイスのすべてのトラフィックがそのノードのパブリックアドレス経由で送信されます。1台のVPSで両方を兼用できます。これらは別々のフラグ、--advertise-routes と --advertise-exit-node であり、それぞれadmin consoleで個別に承認する必要があります。

Linuxクライアントが広告されたサブネットルートを無視するのはなぜですか?

Linuxクライアントは、明示的に有効化しない限りサブネットルートを受け入れません。クライアントで sudo tailscale set --accept-routes を実行してください。その後、ip route show ではなく ip route show table 52 で確認します。Tailscaleは受け入れたルートをrouting table 52にインストールし、policy rules経由で使用します。そのため、main tableには表示されず、動作しているルートがないように見えます。

再起動後にサブネットが使えなくなりました。何が壊れたのですか?

最も可能性が高いのはIP forwardingです。sysctl -w で設定した値は再起動後も保持されないため、/etc/sysctl.d/99-tailscale.conf に書き込み、sysctl net.ipv4.ip_forward で確認してください。forwardingが有効で、範囲にも引き続き到達できない場合は、admin consoleでそのノードを確認します。node keyはデフォルトで180日後に期限切れになります。期限切れのサブネットルーターは、アカウントの問題ではなくネットワーク障害のように見えます。

2台のサブネットルーターで同じ範囲を広告できますか?

はい。高可用性ペアでは、同一の範囲を使用します。両方のルーターがまったく同じprefixを広告します。異なるprefix長の範囲が重複していても問題ありません。この場合は、最も具体的な経路が優先されます。ただし、フェイルオーバーには注意が必要です。より具体的なprefixを保持するルーターがオフラインになっても、Tailscaleはより広い経路へフォールバックしないため、そのトラフィックは停止します。実際のstandbyペアでは、両方のルーターに同じ具体的なprefixを広告させてください。

ホスト名は解決できますが、接続がタイムアウトします。なぜですか?

DNS解決とルーティングは別の処理です。名前が、承認済みの経路でカバーされていないアドレスに解決されることがあります。その場合、パケットはクライアントのデフォルトゲートウェイ経由で送信されます。クライアントで ip route get <address> を実行してください。Linuxクライアントで結果に dev tailscale0 が含まれていない場合は、まず --accept-routes が有効か確認します。有効であれば、そのアドレスをカバーする範囲を広告し、新しいprefixをadmin consoleで承認してください。