事象
開発環境で、開発用に設定したドメイン名(app.sample.localのようなもの)を使ったhttp://app.sample.local:3000のようなURL)でアクセスすると、ブラウザ画面上に「このページは動作していません」というメッセージと、「HTTP ERROR 401」というエラーメッセージが表示され、アプリケーション画面が表示されない状況に陥りました。
この問題が発生しているとき、全く同じ環境でlocalhostを使ったhttp://localhost:3000というURLでアクセスすると、このエラーは発生せず、正常に表示されるという現象が発生していました。
結論(根本原因)
調査の結果、想定していた3000ポートが、別プロセスによって使用中になっていることが原因でした。
解決策
ポートを使用しているプロセスを強制終了する
①使いたいポートの使用状況を確認する
lsof -i :3000
user@Users-MacBook-Pro ~ % lsof -i :3000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
Code\x20H AAAA xxxx 38u IPv4 XXXXXXXXXXXXXXXXXX 0t0 TCP localhost:hbci (LISTEN)
- ポート3000に何かプロセスが残っていることを確認
②上記コマンドで対象ポートを使用しているプロセスがあったので強制終了する
kill -9 AAAA
③もう一度lsof -i :3000を実行してポートを使用しているプロセスがいないことを確認し、アプリを再起動する
user@Users-MacBook-Pro ~ % lsof -i :3000
user@Users-MacBook-Pro ~ %
- ポートにプロセスが残っていないことを確認
- この状態で
npm run devを実行すると、アプリが正常に起動した
検証したこと
①アプリケーションの環境変数等の設定見直し
それまでアプリケーションのプログラム修正を行っていたため、その過程で必要な設定を書き換えてしまった可能性について検証を行いました。
結果として、「特に環境変数等の設定を変更した形跡がなかった」「同じ環境とアプリケーションで操作しているチームメンバーは問題なく起動できている」ことから、 ここに原因がある可能性は低いと判断しました。
②ネットワーク設定とホストの名前解決の確認
OSアップデートおよび再起動により、PCの基本設定が初期化された可能性の検証を行いました。
- etc/hostの確認
- 開発用に設定したドメイン(app.sample.local)の定義が消えていないことの確認
- 消えていないことを確認
- 開発用に設定したドメイン(app.sample.local)の定義が消えていないことの確認
- ブラウザキャッシュのクリア
- ブラウザ側に古い情報が残っていないことの確認
- 普段使用していない別のブラウザでの検証(普段chromeを使っていたため、safariで対象ドメインにアクセスしてみる)
- ブラウザ側のキャッシュをクリアしたり別ブラウザを使ったりしてみたが、効果がなかった
③macOSのセキュリティ、権限周りの調査
この問題が発生する前、自動でOSのアップデートがあったことを思い出し、アップデートの影響があるのではないかと考えました。
問題発生後に確認したOSのバージョンはmacOS Sequoia 15.7.3でした。
調べている過程でSequoiaへのアップデート以降、ローカルネットワークへの管理が厳格化されているという記事を見かけたため、以下の検証を行いました。
- システム設定>プライバシーとセキュリティ>ローカルネットワークで対象アプリケーションに権限が付与されていることの確認
- 権限は付与されていた。一度権限を外してつけ直すなども試したが、結果は変わらなかった
- /Library/Preferences/com.apple.networkextension.uuidcache.plistの削除
- このファイルはmacOS上のネットワーク拡張設定やローカルネットワークへのアプリのアクセス権限を記録しているものである
- 先ほどローカルネットワークを確認した際、chromeがたくさん表示されており、このファイルにその関連情報が記録されている記事を見つけたので、試すことにした。ちなみにいきなり削除は怖かったので名前を変更して移動させるにとどめた
- 結果は特に変わらなかった
④ツールを使ったターミナルからの直接リクエストでの検証
- curlを使ってHostヘッダーのテストを行った
-
curl -I -H "Host: app.sample.local"を実行(app.sample.localは問題が起こるドメイン) - ここでは200レスポンスが返ってきた=>サーバー自体は正常に応答できることを確認
-
紛らわしかった点(なぜ原因の特定が遅れたか)
- 問題が発生する前にOSの自動アップデートやそれに伴う再起動があったため、それ自体に問題があると推測してしまったため
- localhostではアプリケーションの画面が起動できていたため、ポートに問題があると思っていなかった
まとめ・教訓
-
エラーメッセージやログは、最初から丁寧に確認することが重要
-
3000 is in useのようなメッセージは、原因に直結する重要な手掛かりである可能性が高い
-
-
仮説を立てることは大切だが、原因が特定できない段階では先入観にとらわれすぎない
- 仮説は、調査の方向性を定めるためのもの
- 先入観があると、他の可能性への気づきが遅れることがある
- その時点で得られている事実に基づき、柔軟に仮説を更新していく必要がある
-
再起動直後は、ポートやプロセスの状態に特に注意する
- 再起動後はポート競合などの問題が起きやすい
-
ポート競合の調査には早めに
lsofを活用する- 使用中のプロセスを即座に特定でき、原因究明のための時間短縮につながる
参考