0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【もう悩まない】ローカル開発のポート被り対策|ルール作りから解決コマンドまで

Posted at

はじめに

「昨日まで動いていたのに、別のプロジェクトを立ち上げたらエラーになった」

ローカル開発をしていると、一度は遭遇するこの問題。Address already in use というエラーメッセージに悩まされた経験がある方も多いのではないでしょうか。

この記事では、ポート被りの「今すぐ解決したい」から「二度と起こさない仕組み作り」まで、実践的な対策を紹介します。

この記事で解決できること

  • 「Address already in use」エラーの即座の解消
  • ポート番号の体系的な管理ルール
  • Docker環境でのポート設定のベストプラクティス
  • チーム開発での運用方法

対象読者

  • ローカル開発環境を構築している方(初心者〜中級者)
  • 複数プロジェクトを並行して開発している方
  • Docker未経験でもOK

まずはエラーを解決する(今すぐ使えるコマンド集)

「理屈はいいから、今すぐ動かしたい!」という方のために、解決コマンドを先に紹介します。

エラーの原因

Address already in use エラーは、使用したいポートが既に別のプロセスに占有されている状態で発生します。よくある原因は以下の通りです。

  • サーバーを停止せずにターミナルを閉じた
  • 別のプロジェクトが同じポートで起動中
  • 前回のプロセスがゾンビ化して残っている

参考:Address already in useのエラーを解決する - Qiita

ポートを使っているプロセスの特定

Mac / Linux の場合

# 指定したポートを使っているプロセスを特定
lsof -i :3000

# 出力例
# COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
# node    12345  user   23u  IPv4  0x1234  0t0  TCP *:3000 (LISTEN)

lsof は「List Open Files」の略で、どのプロセスがどのファイル(ポートを含む)を開いているかを表示するコマンドです。

参考:lsof Command in Linux with Examples - GeeksforGeeks

Windows の場合

# 指定したポートを使っているプロセスを特定
netstat -ano | findstr :3000

# 出力例
# TCP    0.0.0.0:3000    0.0.0.0:0    LISTENING    12345

一番右の数字(12345)がプロセスID(PID)です。

参考:Netstatコマンドとは。概要やオプション、その使い方を徹底解説!

プロセスの終了方法

Mac / Linux の場合

# 通常の終了(推奨)
kill 12345

# 強制終了(通常の終了で止まらない場合のみ)
kill -9 12345

kill -9 は強制終了オプションです。まずは -9 なしで試し、それでも終了しない場合のみ使用してください。

Windows の場合

# プロセスを終了
taskkill /PID 12345

# 強制終了
taskkill /PID 12345 /F

参考:特定のポート番号を使用しているプロセスを見つけ、終了する方法 - Qiita

ワンライナーで一気に解決(Mac / Linux)

毎回PIDを確認するのが面倒な場合、以下のワンライナーが便利です。

# ポート3000を使っているプロセスを強制終了
lsof -ti :3000 | xargs kill -9

よく使われるポート番号一覧

「なぜ3000?なぜ8080?」という疑問を持ったことはありませんか?ポート番号には慣習的な使い分けがあります。

ポート番号の分類

ポート番号は0〜65535の範囲で、IANAにより以下の3つに分類されています。

範囲 名称 用途
0〜1023 システムポート(Well-known Ports) HTTP(80)、HTTPS(443)など標準プロトコル用。管理者権限(root)が必要
1024〜49151 登録済みポート(Registered Ports) 特定のアプリケーション用にIANAが管理
49152〜65535 動的/プライベートポート 一時的な通信や開発用に自由に使用可能

参考:TCPやUDPにおけるポート番号の一覧 - Wikipedia

開発でよく使われるポート番号

ポート 用途 使用例
80 HTTP(本番環境) Apache, nginx
443 HTTPS(本番環境) SSL/TLS通信
3000 フロントエンド開発 React, Next.js, Rails
3306 MySQL データベース
5173 Vite フロントエンド開発サーバー
5432 PostgreSQL データベース
8000 バックエンド開発 Django, FastAPI
8080 代替HTTPポート Tomcat, プロキシサーバー, Spring Boot
9000 管理ツール系 PHP-FPM, SonarQube

参考:ポートの基礎知識とよく使われるポート番号のまとめ - ZennServer Options | Vite(公式)

なぜ8080がよく使われるのか?

8080は「代替HTTPポート」として広く認知されています。0〜1023のポート番号はLinuxでは管理者権限(root)が必要なため、開発環境では80番の代わりに8080を使うのが慣習となりました。

参考:root権限の管理 - LinuC


ポート被りを防ぐルール作り

ここからが本題です。エラーを「解決する」だけでなく「予防する」ためのルール作りを紹介します。

ポート管理のルール化(2つの方式)

複数プロジェクトを同時起動する場合、ポート競合を防ぐルールを決めておくと便利です。ここでは2つの方式を紹介します。

方式1: オフセット方式

各ツールのデフォルトポートに、プロジェクトごとの固定値を加算する方式です。

ツール デフォルト プロジェクトA (+1) プロジェクトB (+2)
React / Next.js 3000 3001 3002
Vite 5173 5174 5175
Django / FastAPI 8000 8001 8002
PostgreSQL 5432 5433 5434

メリット: デフォルトポートに近いので、ドキュメントとの対応がわかりやすい

デメリット: 各ツールのデフォルトポートを覚えておく必要がある

参考:【ポート競合対策】個人開発でローカル環境のポート番号割り当ての工夫 - Zenn

方式2: ブロック方式(筆者はこちらを採用)

プロジェクトごとに「ポートの百の位」を固定し、末尾の数字を 3層アーキテクチャ に対応させる方式です。4000番台を使うことで、よく使われるデフォルトポート(3000, 3306, 5432, 8080など)との衝突を回避できます。

プロジェクト ポート範囲 プレゼンテーション層 (0x) アプリケーション層 (1x) データ層 (2x)
A 4100-4199 4100 4110 4120
B 4200-4299 4200 4210 4220
C 4300-4399 4300 4310 4320

末尾の割り当てルール:

末尾 役割
プレゼンテーション層 00 Frontend(メイン)
01 Storybook / Preview
アプリケーション層 10 Backend API
11 Admin API
データ層 20 PostgreSQL
21 MySQL
30 Redis(キャッシュ)
補助ツール 40 Adminer / pgAdmin
41 MailHog等

メリット:

  • 「プロジェクトAは41xx」と覚えるだけで済む
  • ポート番号を見れば即座にプロジェクトと役割がわかる(4120 = A案件のDB)
  • 十の位でアーキテクチャ層が判別できる(0x=画面、1x=API、2x-3x=データ)
  • デフォルトポートを覚えている必要がない
  • デフォルトポートと衝突しない

デメリット: デフォルトポートとの対応がわかりにくい

ブロック方式の可視化

ブロック方式なら「プロジェクトAは41xx」と覚えるだけで、十の位を見ればどの層のサービスかも即座にわかります。


環境変数(.env)での管理

コード内にポート番号をハードコードするのは避けましょう。環境変数で管理することで、競合時の変更が容易になります。

.env.example を用意する

プロジェクトのルートに .env.example を作成し、デフォルト値を記載します。

# .env.example
PORT=3000
API_PORT=8000
DB_PORT=5432
DATABASE_URL=postgres://localhost:5432/mydb

各自のローカルで .env を作成

# .env(.gitignoreに追加すること)
PORT=3005
API_PORT=8005
DB_PORT=5435
DATABASE_URL=postgres://localhost:5435/mydb

アプリケーション側での読み込み例

Node.js の場合

// dotenvを使用
require('dotenv').config();

const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

Python (Django) の場合

import os
from dotenv import load_dotenv

load_dotenv()

PORT = int(os.getenv('PORT', 8000))

運用のポイント

  1. .env.example はリポジトリにコミットする
  2. .env.gitignore に追加し、各自のローカルで管理
  3. 競合が発生したら .env の値を変更するだけで対応可能

Dockerでのポート管理

Dockerを使用している場合、コンテナ内部のポートは固定し、ホスト側のポートだけをプロジェクトごとにずらすのが定石です。

基本的なポートマッピング

# docker-compose.yml
version: '3'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"  # ホストの8080 → コンテナの80

ホスト側ポート:コンテナ側ポート の形式で指定します。

参考:docker-compose の ports 指定まとめ - Qiita

プロジェクトごとにポートをずらす

ブロック方式(3層アーキテクチャ対応)を採用した場合の例です。

# プロジェクトA(41xx)の docker-compose.yml
version: '3'
services:
  # プレゼンテーション層(0x)
  web:
    image: node:18
    ports:
      - "4100:3000"
  # アプリケーション層(1x)
  api:
    image: python:3.11
    ports:
      - "4110:8000"
  # データ層(2x)
  db:
    image: postgres:15
    ports:
      - "4120:5432"
# プロジェクトB(42xx)の docker-compose.yml
version: '3'
services:
  web:
    image: node:18
    ports:
      - "4200:3000"
  api:
    image: python:3.11
    ports:
      - "4210:8000"
  db:
    image: postgres:15
    ports:
      - "4220:5432"

環境変数と組み合わせる

ポート番号を .env ファイルで管理すると、より柔軟になります。

# docker-compose.yml
version: '3'
services:
  web:
    image: node:18
    ports:
      - "${WEB_PORT:-4100}:3000"
  db:
    image: postgres:15
    ports:
      - "${DB_PORT:-4120}:5432"
# .env(プロジェクトAの場合)
WEB_PORT=4100
DB_PORT=4120

ローカル専用にする(セキュリティ対策)

外部からのアクセスを防ぐため、ホスト側のIPを 127.0.0.1 に限定できます。

ports:
  - "127.0.0.1:3000:3000"

参考:Dockerでサーバー構築する際のポート指定で気をつけること - UCWD-Studio


チーム開発での運用Tips

ポート管理表を作成する

チームで開発する場合、ポート割り当てを一覧化しておくと便利です。ブロック方式を採用した場合の例:

プロジェクト 範囲 Frontend (0x) Backend (1x) Database (2x) 備考
ECサイト 41xx 4100 4110 4120 本番リリース済み
管理画面 42xx 4200 4210 4220 開発中
モバイルAPI 43xx - 4310 4320 API専用

READMEに書くべき情報

プロジェクトのREADMEには、最低限以下を記載しましょう。

## 開発環境

### 使用ポート(ブロック方式: 41xx)

| 層 | サービス | ポート |
|:--|:--|:--|
| プレゼンテーション | Frontend | 4100 |
| アプリケーション | Backend API | 4110 |
| データ | PostgreSQL | 4120 |

### 起動方法
1. `.env.example``.env` にコピー
2. `docker-compose up -d`
3. http://localhost:4100 にアクセス

### ポート競合時の対処
`.env` ファイルの `PORT` を変更してください。

まとめ

ローカル開発でのポート被りを防ぐために、最低限やるべき3つのことをまとめます。

1. エラー時の対処法を覚える

# Mac/Linux: ポートを使っているプロセスを確認
lsof -i :3000

# Windows: ポートを使っているプロセスを確認
netstat -ano | findstr :3000

2. ポート番号は環境変数で管理する

# .env
PORT=3000

コードにハードコードしない。これだけで競合時の対応が楽になります。

3. プロジェクトごとにポート管理ルールを決める

「プロジェクトAは41xx」のようにブロック方式でルール化すると、ポート番号を見ただけでどのプロジェクトかわかります。さらに十の位を3層アーキテクチャに対応させれば(0x=画面、1x=API、2x=DB)、どの層のサービスかも一目瞭然です。


参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?