Macで動かしているWebページを、スマートフォンでも開きたい。パソコンでは http://localhost:4173 で見られるのに、スマホに同じアドレスを入れると何も表示されない。自宅のWi-Fiでは使えたアドレスが、外出すると使えなくなることもある。ページは同じなのに、接続する端末や場所が変わると、何が違うのだろう。
接続の仕組みを知るには、URLの宛先と、サーバーが接続を受け付ける条件を一緒に見る必要がある。IPアドレスはネットワーク上の宛先を、ポートはその宛先にある通信の窓口を示す。バインドはサーバーが使うローカルアドレスとポートを決めることで、プロセスは実行中のプログラムだ。 宛先までの経路と接続の許可もそろって、ページが開く。
ここでは、MacのNodeサーバーがTCPポート 4173 でWebページを提供し、スマホから接続する場面を見ていく。4173 はこの例で使う番号で、サーバーの設定によって別のポートも使える。

異なる出発点から同じパソコンのサーバーに届く様子を描いたイメージ。実際のネットワーク構成や製品画面を示す資料ではない。
IPアドレスとポートから何が分かる?
http://100.x.y.z:4173 では、http が通信方式、100.x.y.z が宛先のIPアドレス、4173 が宛先のポートだ。x.y.z は説明用の仮表記なので、接続するときはMacに実際に割り当てられた数字を使う。
| 概念 | 何を決めるか | この例では |
|---|---|---|
| IPアドレス | ネットワーク上のどのアドレスへ送るか | MacのLANアドレス、またはTailscaleアドレス |
| ポート | そのアドレスのどの通信窓口へ送るか | TCP 4173 |
| バインド | サーバーがどのローカルアドレスとポートを使うか | 127.0.0.1:4173 または 0.0.0.0:4173 |
| プロセス | 実際にどのプログラムがリクエストを処理するか | 実行中のNodeプログラム |
IPアドレスを端末の名札だと考えると、最初は分かりやすい。ただし、パソコン1台に複数のアドレスが付くこともある。MacのWi-Fiアドレス、Tailscaleアドレス、自分自身を指すループバックアドレスは、それぞれ役割が違う。「MacのIPアドレスは?」と聞かれたら、「どこから、どの経路で接続する?」も確かめたい。
ポートは、OSが通信を区別するために使う番号だ。TCPとUDPはそれぞれポート番号を持ち、同じ番号でも別の通信窓口として扱われる。番号の範囲は 0–65535 で、0 は予約されている。IANAのポート登録簿
ひとつのサービスポートを複数のプロセスで共有する構成もある。たとえばNodeの cluster では、複数のワーカーが同じサーバーポートへの接続を分担して処理する。ポート番号だけを見ても、その裏で処理しているプロセスがいくつあるかは分からない。Node.jsのclusterドキュメント
利用者が複数いても、同じ 4173 ポートに接続できる。TCPは両端のIPアドレスとポートの組み合わせで接続を区別する。スマホ側にも送信元ポートがあるので、同じサーバーポートに向かう接続を別々に管理できる。TCPの仕様 RFC 9293
スマホのlocalhostはスマホ自身を指す
localhost とIPv4のループバックアドレス 127.0.0.1 が指すのは、リクエストを送っている端末自身だ。Macで入力すればMac、スマホで入力すればスマホになる。ループバックアドレスは、通常の外部宛先として転送されない。IANAの特殊用途IPv4アドレス登録簿
スマホからは、Macの実際のLANアドレスかTailscaleアドレスを指定しよう。それでもつながらないなら、次はサーバーがどこで接続を待っているかを調べる。
バインドすると、待ち受けるアドレスが決まる
サーバーが 127.0.0.1:4173 にだけバインドされていれば、Mac自身のループバック経由の接続を受け付ける。スマホがMacの別のIPアドレスに送ったリクエストは、そのリスナーの対象にならない。リスナーとは、新しい接続を待つサーバー側のソケットのことだ。
0.0.0.0:4173 は、ひとつのIPv4アドレスに絞らず、すべてのローカルIPv4アドレスで待ち受ける設定だ。スマホのブラウザーに入力する宛先には、引き続きMacの実際のアドレスを使う。 0.0.0.0 は、誰もが接続できる公開アドレスではない。
Nodeで host を省略すると、IPv6が利用できる場合は ::、それ以外は 0.0.0.0 で待ち受ける。IPv6のリスナーがIPv4も受け付けるかどうかは、OSや設定に左右される。接続の問題を調べるときは、サーバーログのアドレスと実際の待ち受け状態を確認しよう。Node.jsのserver.listenドキュメント
| サーバーの待ち受けアドレス | 意味 | この設定だけでは保証されないこと |
|---|---|---|
127.0.0.1:4173 |
Macのループバックで待ち受ける | スマホからの直接接続 |
192.168.x.x:4173 |
指定したLANアドレスで待ち受ける | 同じWi-Fi上の全端末からの接続 |
100.x.y.z:4173 |
指定したTailscaleアドレスで待ち受ける | Tailnet内の全メンバーへのアクセス許可 |
0.0.0.0:4173 |
すべてのローカルIPv4アドレスで待ち受ける | インターネットへの公開、ファイアウォールの許可、ログイン |
待ち受けアドレスを確認したら、経路、ファイアウォール、アクセスポリシーも調べる。バインドが正しくても、途中で接続を遮断されればリクエストはサーバーまで届かない。
同じWi-Fiなら、インターネットを経由せずに届く
スマホとMacが互いに通信できる同じLANにいるなら、スマホはMacのLANアドレスへ接続できる。Wi-Fiアクセスポイントなどを経てMacに届き、OSが対応するサーバーソケットへ渡す。この通信のために、いったんインターネットへ出て戻ってくる必要はない。
同じWi-Fi名が表示されていても、ゲストネットワークや端末間通信の遮断、Macのファイアウォールによって接続できないことがある。その場合は、バインドに加えてネットワークのアクセス制限を確認する。
外出先で 192.168.x.x を入力するときは、別の問題になる。このようなプライベートアドレスは、公開インターネット上で自宅のMacを一意に指すものではない。他の家でも同じ番号を使えるからだ。モバイル回線から自宅のLANへ入るには、別の経路が必要になる。プライベートアドレスが世界中で共通の宛先を示さない理由は、RFC 1918に記されている。
Tailscaleで外からつながる経路を作る
両方の端末でTailscaleに接続すると、物理的には別のネットワークにいるスマホとMacを、Tailnetというプライベートネットワークで結べる。TailscaleのIPv4アドレスは通常 100.64.0.0/10、つまり 100.64.0.0–100.127.255.255 の範囲を使う。100 で始まるアドレスすべてがTailscale用というわけではない。Tailscaleのアドレスに関するドキュメント
IANAはこの範囲を共有アドレス空間に分類し、公開インターネットからグローバルに到達できるアドレスとしては扱っていない。IANAのIPv4登録簿
両端末は最初にDERPリレーで接続情報を交換し、直接つながる経路を試す。直接接続が難しければ、利用可能なPeer Relayを使うか、DERPリレーを使い続ける。どの方式でもWireGuardでエンドツーエンド暗号化され、一般に直接接続のほうが遅延やスループットの面で有利だ。Tailscaleの接続方式
この構成なら、自宅のルーターでWebサーバーの 4173 を公開するポート転送は必要ない。ただし、ネットワークがTailscale自体の接続を遮断している場合は、その制限から調べる必要がある。
リクエストは次の順序で届く。
- スマホのブラウザーが、MacのTailscaleアドレスのTCP
4173に接続を試みる。 - 両端末のTailscaleが、直接接続またはリレーを通じて通信を運ぶ。
- アクセスポリシーとMacのファイアウォールが許可し、宛先のアドレスとポートにリスナーがいれば、接続が成立する。
- NodeプログラムがHTTPリクエストを処理し、ブラウザーが応答を受け取ってページを表示する。
同じTailnet内でも、TailscaleのgrantsやACLなどのポリシーで、ユーザーや端末ごとにアクセスできる宛先とポートを制限できる。サーバーが接続を受け付けているかと、そのユーザーに接続する権限があるかは、それぞれ確認する必要がある。Tailscaleのgrantsドキュメント
ページが開かないときは、順番に切り分ける
いくつもの設定を一度に変えると、原因が分かりにくくなる。下の順序で確認する範囲を絞ってみよう。同じ症状でも原因はいくつか考えられるので、各項目は調査を始める場所として使ってほしい。
| 状況 | 最初に確認すること |
|---|---|
| Mac自身でもページが開かない | サーバープロセスが動いているか、ポートは本当に 4173 か、サーバーログにエラーがないか |
| Macでは開くがスマホでは開かない | スマホのURLに localhost を使っていないか、サーバーがループバックだけにバインドされていないか |
| 同じWi-FiでもLANアドレスにつながらない | Macの現在のLANアドレス、ファイアウォール、ゲストネットワークや端末間通信の遮断 |
| LANアドレスならつながるがTailscaleアドレスではつながらない | 両端末のTailscale接続、宛先アドレス、アクセスポリシー、そのアドレスのリスナー |
| 接続できるがエラーページになる | HTTPステータスとサーバーログ、リクエストしたパス、アプリケーションの認証条件 |
Tailscaleのトラブルシューティングでも、端末の状態、ポリシー、ファイアウォール、サービスへのアクセス条件を確認するよう案内している。VPNが接続中と表示されても、Webサーバーの動作まで確認できたわけではない。Tailscaleの接続トラブルシューティング
Macの launchd でサーバーの実行を管理しているなら、ジョブの設定も確認しよう。再起動するかどうかは、KeepAlive などの設定で変わる。ソケットを先に開いてプログラムに渡す構成も可能だが、プロセス管理が外部ネットワークへの経路やアプリケーションの認証まで担うわけではない。Appleのlaunchdガイド
http://Macの実際のIP:4173 のIPを変えること、サーバーのバインドを変えること、Tailscaleのポリシーを変えることは、それぞれ違う問題への対処になる。次にページが開かなかったら、「サーバーがおかしい」で止まらず、どのアドレスへ送り、どの経路を通り、到着先では何が待ち受けているのかを確認してみよう。