Linuxでサービスやアプリ起動時の「bind: Address already in use」を修正する

beginner🐧 Linux2026-06-30| Linux (Ubuntu, Debian, CentOS, RHEL, Arch) — ネットワークポートにバインドするあらゆるサービスやアプリケーション(Nginx、Node.js、Python、Java、PostgreSQL、Redisなど)

Error Message

bind: Address already in use
#ネットワーク#ポート#サービス#プロセス#lsof

TL;DR

アプリが使用しようとしているポートに、すでに別のプロセスがリッスンしています。ss -tlnp | grep : または lsof -i : で特定し、そのプロセスを終了するか、アプリのポートを変更してください。

# ポート8080を使用しているプロセスを探す
ss -tlnp | grep :8080

# 終了する(PIDを実際の番号に置き換える)
kill -9 

# サービスを再起動する
systemctl restart your-service

何が起きているのか

すべてのネットワークサービスは、ソケット上で bind() を呼び出すことでポートを確保します。bind: Address already in use というエラーは、別のプロセスがすでにそのポートを占有しているか、直前に停止したプロセスがソケットを TIME_WAIT 状態のままにしており、OSがまだ解放していないために、OSがその要求を拒否したことを意味します。

よくある2つのケース:

  • アプリを素早く再起動したため、古いプロセスがまだクリーンアップ中である(TIME_WAIT
  • まったく別のプロセスがポートを取得している — アプリの別インスタンス、競合するサービス、または以前のクラッシュによるゾンビプロセス

ステップ1:ポートを占有しているプロセスを特定する

8080 を実際に使用しようとしているポート番号に置き換えてください。

ss を使用する(モダンな Linux で推奨)

ss -tlnp | grep :8080

出力例:

LISTEN  0  128  0.0.0.0:8080  0.0.0.0:*  users:(("node",pid=12345,fd=18))

PIDはそこに表示されます — この例では 12345 で、Node.js プロセスが動作しています。

lsof を使用する

lsof -i :8080

出力例:

COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
node    12345   ubuntu   18u  IPv4  98765      0t0  TCP *:8080 (LISTEN)

fuser を使用する

fuser 8080/tcp

PIDのみを出力します — スクリプト処理に便利です。

ステップ2:対処方法を選択する

オプション A — 古いプロセスを終了する

自分のアプリの古いインスタンスが残っている場合:

# まずグレースフルキル
kill 12345

# 数秒経っても終了しない場合、強制終了
kill -9 12345

その後、通常どおりサービスを再起動してください。

オプション B — ポートを使用しているシステムサービスを停止する

nginxapache2postgres などがポートを占有している場合:

# どのサービスか確認する
systemctl status nginx

# 停止する
systemctl stop nginx

オプション C — ポート上のすべてのプロセスを一括終了する

fuser -k 8080/tcp

そのポートにバインドされているすべてのプロセスを終了します。共有サーバーで使用する場合は慎重に。

オプション D — アプリケーションのポートを変更する

触れるべきでない別のサービスが正当にポートを使用している場合は、アプリを別のポートでリッスンするよう設定してください。例えば、Node.js アプリの場合:

// この部分を変更する
const PORT = process.env.PORT || 3001;
app.listen(PORT);

または起動時に環境変数で指定する:

PORT=3001 node server.js

ステップ3:TIME_WAIT を処理する(素早い再起動のシナリオ)

サービスを停止してすぐに再起動した場合、自分のプロセスがなくなっているにもかかわらずエラーが表示されることがあります。カーネルは遅延パケットを適切に処理するため、ソケットを短時間(通常60秒)TIME_WAIT 状態に保持します。

自分で管理するサービスに対する最善の対処法は、アプリケーションコードで SO_REUSEADDR を設定することです。ほとんどのフレームワークやサーバーはこれを自動的に行いますが、生のソケットコードを書いている場合は:

// C言語の場合
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

システムサービスの場合、手っ取り早い回避策として30〜60秒待ってから再試行する方法があります。または ss -s で TIME_WAIT カウントが減少するのを確認できます:

watch -n1 'ss -s'

ステップ4:修正を確認する

ポートを解放した(または設定を変更した)後、サービスを起動する前にポートが空いていることを確認してください:

# ポートが空いていれば何も表示されない
ss -tlnp | grep :8080

次にサービスを起動し、実際にリッスンしているか確認します:

systemctl start your-service

# 起動を確認
ss -tlnp | grep :8080

# curl でテスト
curl -v http://localhost:8080/health

ボーナス:起動前に競合するポートを確認する

新しいサービスをデプロイする前に、サーバーでどのポートがすでに使用されているかを確認しておくと良いでしょう:

# リッスン中のすべてのポートを一覧表示
ss -tlnp

# ss が使えない場合は netstat
netstat -tlnp

コンテナや複雑なネットワーク構成で、ポート計画と合わせてCIDR範囲やサブネット割り当てを把握する必要がある場合、ToolCraft の IP Subnet Calculator はブラウザ上でネットワーク計算を素早く行うのに便利です — データのアップロードは不要で、完全にプライベートです。

今後の予防策

  • ソケットコードで SO_REUSEADDR を使用する — TIME_WAIT による再起動の問題を解消できます
  • サービスのポートをドキュメント化する — 各サービスが使用するポートを簡単なリストにまとめておくと、新しいサービスを追加する際の誤った競合を防げます
  • プロセスマネージャーを使用するsystemdpm2supervisor などのツールは再起動前にクリーンなシャットダウンを行い、古いプロセスによるポート競合を軽減します
  • systemd ユニットで Restart=alwaysRestartSec=2 を設定する — 再起動の間にカーネルがソケットを解放する時間を確保できます

Related Error Notes