はじめに
Node.js / Express のアプリを起動しました。
APP_DB_HOST=127.0.0.1 \
APP_DB_USER=admin \
APP_DB_PASSWORD=password123 \
APP_DB_NAME=employeedb \
npm start
ログを見る限り、正常に起動しています。
> employee-management@1.0.0 start
> node server.js
[CONFIG] Secrets Manager not available. Using default values.
サーバーがポート3000で起動しました
データベースに接続しました
しかし、ブラウザで次にアクセスすると動きません。
http://localhost:3000/
表示されたエラーは次のようなものでした。
Error: ENOENT: no such file or directory, open '/var/folders/.../T/.org.chromium.Chromium.ZVQp1f'
Chromium という文字が見えたため、最初は Chrome / Chromium の一時ファイルや、VS Code Dev Containers の port forwarding あたりを疑いました。
curl でも同じエラー
ブラウザだけの問題かどうかを切り分けるため、curl で確認しました。
curl -v http://127.0.0.1:3000/
結果は次の通りです。
< HTTP/1.1 404 Not Found
< X-Powered-By: Express
...
<pre>Error: ENOENT: no such file or directory, open '/var/folders/.../T/.org.chromium.Chromium.ZVQp1f'</pre>
curl でも同じエラーが返りました。
つまり、ブラウザだけの問題ではなさそうです。
lsof で確認する
そこで、3000 番ポートを掴んでいるプロセスを確認しました。
lsof -nP -iTCP:3000 -sTCP:LISTEN
結果は次の通りです。
COMMAND PID USER FD TYPE NAME
SwiftQuot 37567 yamauchi 17u IPv6 TCP *:3000 (LISTEN)
いました。
3000 番を使っていたのは、今回起動したつもりのアプリではなく、SwiftQuot でした。
SwiftQuot とは
SwiftQuot は、以前 Tauri で作った自作GUIアプリです。
終了したつもりでしたが、実際にはバックグラウンドで動き続け、3000 番ポートを待ち受けていました。
自作アプリだと分かったので、すぐに停止しました。
kill 37567
その後、あらためて 3000 番を確認します。
lsof -nP -iTCP:3000 -sTCP:LISTEN
何も表示されなければ、3000 番は空いています。
ポイント
単純なポート競合なら、普通は npm start の段階で EADDRINUSE になるはずです。
しかし今回は、ログ上は次のように見えていました。
サーバーがポート3000で起動しました
データベースに接続しました
そのため、最初はポート競合だと気づきませんでした。
とはいえ、実際に localhost:3000 へアクセスしたときに、期待しているアプリへ届いているとは限りません。
ログだけでなく、実際にそのポートを誰が掴んでいるかを見るのが大事でした。
まとめ
localhost:3000 が動かないときは、Chrome、VS Code、Dev Container などを疑う前に、まずこれを見ると早いです。
lsof -nP -iTCP:3000 -sTCP:LISTEN
今回は、終了したつもりの Tauri 製自作GUIアプリが 3000 番で待ち受けていました。
localhost の賊を破るには、まず lsof。
足元のポートを見るだけで、遠回りを避けられることがあります。