ノート PC では応答するが他のどこからも応答しない開発サーバーは、通常は誤ったアドレスにバインドされています。接続は受け付けるがページを拒否するサーバーは、通常ホスト名チェックに失敗しています。これらは別の不具合であり別の修正が必要で、正しい設定の選択は、誰がワークスペースに到達する必要があるか、またどのように到達するかによって決まります。

三つの問いが答えを決めます。誰が接続するのか、どのアドレスに到達できるのか、その人にとってライブリロードが動作する必要があるのか、です。

設定ファイルからではなく、ソケットから始める

実行中のプロセスが実際に何にバインドされているかを、それを起動したのと同じネットワークコンテキストの中で読み取ります。コンテナや名前空間は、ホスト側のシェルから見えないソケットを所有することがあるからです。リッスン列が最初の問いに答えます。ローカルパスのみ、特定の一つのインターフェース、またはすべてのインターフェースです。

ss -ltn '( sport = :8080 )'
ss -ltnp | grep node

ループバックアドレスは安全な既定値であり、遠隔のクライアントには役に立ちません。ワイルドカードバインドは便利で、ルートを持つすべてのインターフェースでポートを公開しますが、トンネルも持つマシンでは多くの人が意図するより広くなります。特定のアドレスは中間の選択肢で、ソケットが作られる瞬間にインターフェースがそのアドレスを所有している場合にのみ機能します。この区別が重要なのは、三つのうち二つのバインドはブラウザでは同じに見え、二つ目のインターフェースが存在するとまったく異なる動作をするからです。

ルートやファイアウォールの規則に触れる前に、この観察に合わせてください。プロセスが誤ったアドレスで待ち受けているなら、どんなポリシールーティングでもクライアントをそこへ到達させられません。

誰が到達する必要があるかでバインドアドレスを選ぶ

このマシン上の自分だけがページを必要とするなら、ループバックバインドを維持して終了します。同じトンネル上の同僚一人が必要とするなら、トンネルインターフェースのアドレスにバインドし、ファイアウォールにはその送信元だけを許可させます。開発サーバーを、実際にテストしている人たちの外へ公開することは、やがてワークスペースをインターネットに晒す習慣です。

コンテナ内のブラウザがサーバーに到達する必要があるなら、バインドアドレスはコンテナのネットワークがルーティングできるものでなければならず、それは多くの場合ホストが自分自身に対して解決するアドレスではありません。設定を編集する前にケースを決めてください。三つのケースは三つの異なる値を生み、正しいのは一つだけです。ここで推測すると、セットアップの他のどの部分よりも時間を浪費します。

次に、起動ツールが実際に読む形式でアドレスを設定します。設定ファイルと、サーバーをプログラムで構築するスクリプトは、同じオプションを消費しません。

devServer: {
  host: "10.77.0.20",
  port: 8080,
  allowedHosts: ["dev.corp.example"],
}

その断片のアドレスは例示であり、ホストが所有する VPN アドレスを表します。プロジェクトがサーバーを new WebpackDevServer(options, compiler) で構築する場合は、代わりにコンストラクタの引数でオプションを渡してください。webpack 設定の別個の devServer プロパティはその経路では参照されないからです。設定ファイルと Node API のこの違いは、決して読まれないプロジェクトに断片をコピーする人を捕まえます。dev-server のドキュメントは二つの起動方法を区別しており、使用中のバージョンと照合すべき参照です。

ホスト名チェックを承認する名前に合わせる

ホスト名チェックは、攻撃者が制御する名前から配信されたページが、ブラウザ経由で開発サーバーと通信するのを防ぐために存在します。これを allowedHosts: "all" で無効にするとその保護が失われ、内部サービスに到達できるマシンではその利便性が報われることはほとんどありません。ブラウザが送る名前がわかれば、チェックを正しく満たすのは安価です。

使用する正確な名前を、トンネルアドレスに解決されるプライベート名も含めて列挙します。クライアントが名前を、バインドしたアドレスとは別のアドレスに解決する場合、それはサーバー設定の問題ではなく名前解決の問題であり、許可リストに名前を加えても直りません。解決はサーバーからではなくクライアントから確認してください。

三つの制御を頭の中で分けておいてください。バインドアドレスはどのインターフェースが接続を受け入れるかを決め、許可リストはどの Host ヘッダーを受け入れるかを決め、認証は誰を中に入れるかを決めます。三つ目だけがアクセス制御であり、開発サーバーには通常どれもありません。トンネルアドレスも認証の仕組みではありません。そこへルーティングできる人は、あなたが頼っていた境界の内側にすでにいるからです。

ページとライブリロード用ソケットを一緒に確認する

意図したクライアントから設定済みのスキームで新しいリクエストを読み込み、キャッシュではなく結果を読み取ります。HTTPS では期待するホスト名と証明書の検証を維持してください。ブラウザの警告は成功した受け入れテストではないからです。ライブリロードが静かに失敗しているのにページが表示されるのは、ここで最もよくある部分的な成功であり、素早い確認では見落としやすいものです。

curl -sS -o /dev/null -w "%{http_code} %{remote_ip}\n" http://dev.corp.example:8080/
curl -sS -i http://10.77.0.20:8080/ | head -n 5

次にブラウザのネットワーク診断を開き、WebSocket 接続を観察します。ページがあるホスト名、ポート、スキームで読み込まれる一方、リロード用ソケットは別のものを使うことがあるため、両方を別々に確認する必要があります。文書化されたクライアント URL は、デプロイされた経路が本当に別の値を必要とする場合にのみ設定し、クライアントに回避策を教えるより経路を直すことを優先してください。

リスナーアドレス、受け入れた名前、許可した送信元、そして両方の結果をプロジェクトのメモに記録します。その記録は、次にワークスペースを起動して、なぜページは読み込まれるのに更新されないのかと疑問に思う人のために残ります。

関連記事