回線が変わっても届く自宅サーバ — Tailscaleで作る「常時SSH」メッシュ

回線が変わっても届く自宅サーバ — Tailscaleで作る「常時SSH」メッシュ

この記事について

回線を渡り歩く自宅サーバに、どこからでも同じ名前でSSHするために、Tailscaleでメッシュを組んだ記録だ。

骨子は一行で済む。各マシンに回線非依存の固定アドレスを配って、自宅光でもモバイルhotspotでも外出先でも、同じホスト名でSSHが通るようにした。ポート開放はゼロ。 住宅回線やテザリングでサーバを常駐させている個人開発者・小規模運用向けに、なぜこの構成にしたのかと、一つだけ引っかかる落とし穴を書く。具体的なIPやホスト名は運用上伏せて、構成の考え方だけ書く。

試した構成: Tailscale(WireGuardベースのメッシュVPN)+ 収集用の常駐サーバ(住宅回線/モバイルテザリングを行き来する)+ 手元の作業マシン。

何が問題だったか — テザリング常駐にした瞬間、SSHが届かなくなる

このサーバは、収集作業のために意図的にモバイル回線で常駐させることがある。回線をテザリングに切り替えた瞬間に困るのがこれだ。

  • モバイル回線は使い捨てのグローバルIPで、しかもキャリアのNATの奥にいる。外から到達する固定の宛先がない
  • 自宅LANを離れるので、.local のようなmDNS名も、LAN内の固定IPも当然効かない
  • 結果、サーバがhotspotに移った途端にSSHできなくなる。障害対応やデプロイのたびに、いちいちサーバを自宅LANに戻す「回線トグルのダンス」が要る

収集を止めずに、外からログ確認・設定変更・デプロイをやりたい。だが「常駐させる回線」と「SSHが届く条件」が両立しない。ここが構造的な詰みだった。

発想の転換 — 「到達可能なIP」を待つのをやめて、オーバーレイ網を自分で張る

そもそも、キャリアが割り当てるIPをあてにしている時点で無理筋だった。狙うべきは逆で、下の回線が何であっても関係ない、自前の宛名を各マシンに持たせることだ。

物理回線のIPは、キャリアの都合で変わるし、NATの奥に隠れる。ならその上に、回線から独立した論理ネットワーク(オーバーレイ)を一枚かぶせて、各マシンにそこでだけ通じる固定アドレスを持たせればいい。これがTailscale(WireGuardメッシュVPN)でやっていることだ。

論点旧構成(物理IP頼み)新構成(Tailscaleメッシュ)
宛先アドレス回線ごとに変わる/NATの奥回線非依存の固定アドレス
到達方法ポート開放+グローバルIP必須NAT越えのP2P、届かなければ自動リレー
ポート開放必要(穴を開ける)不要
hotspot移行時SSH不能になる同じ名前で届いたまま

各マシンは同じアカウントのメッシュ(tailnet)に参加し、それぞれ固定の内部アドレスを受け取る。マシン同士はできる限りP2Pで直結し、NATで直結できないときは中継サーバ経由に自動フォールバックする。下でつながっている回線が光だろうがモバイルだろうが、上のアドレスは変わらない。だから作業マシン側のSSH設定にホスト別名を一つ登録しておけば、ssh そのマシン名 で常に届く。

落とし穴 — 「認証URLが出た=回線が切れた」ではない

構成自体はきれいに動いたが、一つだけ勘違いしやすい挙動がある。Tailscaleの内蔵SSH(Tailscale SSH)を有効にしていると、しばらく使ったあとの接続時に、こういう表示が出ることがある。

# Tailscale SSH requires an additional check.
# To authenticate, visit: https://login.tailscale.com/a/...

初見だと「あ、回線が切れたか、鍵が壊れたか」と焦る。だが**これは回線障害ではなく、Tailscale SSHの定期的なブラウザ再承認(check)**だ。表示されるURLを、同じアカウントでログイン済みのブラウザで開けば解消する。鍵認証を明示指定しても、メッシュ側のSSHを通す限りこのチェックは踏むので、鍵の指定では回避できない。

運用上の使い分けはこうした。

  • 自宅LANにいるときは、メッシュ経由ではなく標準の sshd(通常のSSH)で入る。こちらは再承認チェックを完全に迂回でき、ノンストップで入れる
  • 外(hotspot)にいるときだけ、メッシュ経由+必要なら一度のブラウザ再承認で入る

「どこからでも同じ名前で届く」利便と「LAN内はゼロ手間」を両取りするため、宛先を一本化せず二経路を用意したわけだ。

導入の骨子 — 画面が使えないheadlessサーバはCLIで通す

サーバ側が画面の使えないheadless機だったので、導入は全部CLIで通した。考え方だけ書くとこうなる。

  1. パッケージマネージャでTailscaleを入れる
  2. システム常駐デーモンをインストールする(仮想ネットワークインターフェースを作るのに管理者権限が要る)
  3. tailscale up 系のコマンドでメッシュに参加し、内蔵SSHを有効化する。表示される認証URLをブラウザで開いてアカウントに紐付ける
  4. 認証URLがうまく出力に出ないときは、ステータスをJSONで吐かせて、その中の認証URLフィールドから拾う

注意点として、システム常駐デーモンは管理者権限で動くので、非管理者ユーザーからCLIを叩くにはオペレータ設定を入れるか、その都度権限昇格が要る。ここは自分の運用ポリシーに合わせて決めればいい。

やってみてわかったこと

回線を渡り歩くサーバを扱うなら、「どの回線にいるか」ではなく「回線に依存しない宛名を持っているか」で設計を見たほうがいい。物理IPは環境の都合で動くが、オーバーレイ網の固定アドレスは動かない。宛名を回線から切り離した瞬間、「hotspot常駐だとSSHできない」という制約そのものが消えた。

効果は地味だが大きい。収集をモバイル回線で回し続けたまま、ログ確認・設定変更・コードデプロイ・障害対応が全部SSHで完結する。以前は障害のたびに回線を戻していたのが、いまはどこにいても同じ一行で入れる。面倒の正体が「宛先が動くこと」だと分かれば、直すのは回線ではなくアドレスの持たせ方だった、という回だった。

更新履歴

  • 2026-07-08: 初稿