個人的備忘録：Docker環境でブラウザからアクセスできない原因と切り分け方法を自分なりにまとめてみた

## はじめに

Docker環境でDjangoアプリにブラウザからアクセスできない場合、考えられる原因とその切り分け方法を詳しく解説します。

:::note warn
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

## 発生していたエラー

- ブラウザから `http://<サーバーのIP>:8000` へアクセスできない
- `curl` コマンドで確認すると `Connection refused` や `Timeout` エラーが発生
- `docker logs django-dev` を確認すると `Listening at: http://127.0.0.1:8000` と表示されている
- `netstat` コマンドでポート8000がリッスンされていない
- `ufw` や `iptables` によるブロックの可能性あり

## チェックリスト

| **チェック項目**                  | **確認方法**                                              | **解決策** |
|----------------------------------|--------------------------------------------------|--------------------------------------------------|
| **ポートが公開されているか**       | `docker ps` でポート 8000 の公開状態を確認 | `docker-compose.yml` に `ports: "8000:8000"` を追加し、コンテナを再起動 |
| **Djangoが 0.0.0.0 でリッスンしているか** | `docker logs django-dev` で `Listening at: http://127.0.0.1:8000` になっていないか確認 | `manage.py runserver 0.0.0.0:8000` で起動 |
| **ALLOWED_HOSTS の設定ミス**     | `settings.py` の `ALLOWED_HOSTS` を確認 | `ALLOWED_HOSTS = ["your-server-ip", "localhost"]` に変更 |
| **ファイアウォールの設定を確認**   | `sudo netstat -tulnp | grep 8000` でポートが開いているか確認 | `sudo ufw allow 8000/tcp` でポートを開放 |
| **Nginx の設定ミス**              | `/etc/nginx/nginx.conf` の `proxy_pass` を確認 | `proxy_pass http://django-dev:8000;` の設定を修正し、Nginx を再起動 |

## 書こうと思ったきっかけ

この問題は、DockerでDjangoアプリを動作させる際によく発生するため、その切り分け手順をまとめることでスムーズにトラブルシューティングできるようにしたかったため。

## 1. コンテナのポートが正しく公開されているか確認

まず、Dockerのポートマッピングが正しく設定されているか確認しましょう。

### 確認方法
以下のコマンドを実行し、ポート設定を確認します。
```sh
 docker ps
```

**出力例:**
```
CONTAINER ID   IMAGE       COMMAND                  PORTS                    NAMES
123456789abc   django-app  "gunicorn --bind 0.…"   0.0.0.0:8000->8000/tcp   django-dev
```

`0.0.0.0:8000->8000/tcp` になっていれば正しく公開されています。

`0.0.0.0:8000` が表示されていない場合、 `docker-compose.yml` に以下の `ports:` 設定を追加してください。

```yaml
services:
  django-dev:
    ports:
      - "8000:8000"
```

この変更後、以下のコマンドでコンテナを再起動します。
```sh
 docker-compose up -d --force-recreate
```

## 2. Djangoが `0.0.0.0` でリッスンしているか確認

Djangoはデフォルトで `127.0.0.1` で動作するため、コンテナの外部からアクセスできません。

### 確認方法
```sh
 docker logs django-dev
```

**出力例:**
```
django-dev  | [INFO] Listening at: http://127.0.0.1:8000 (1)
```
`127.0.0.1` でリッスンしている場合、`0.0.0.0` に変更する必要があります。

### 解決策
`manage.py runserver` のオプションを修正:
```sh
python manage.py runserver 0.0.0.0:8000
```
または、`gunicorn` の設定を変更:
```sh
gunicorn --bind 0.0.0.0:8000 myproject.wsgi
```

## 3. `ALLOWED_HOSTS` の設定ミス

Djangoの `settings.py` に適切な `ALLOWED_HOSTS` を設定していないとアクセスがブロックされます。

### 確認方法
`settings.py` に以下のような設定があるか確認してください。
```python
ALLOWED_HOSTS = ["*"]
```
セキュリティ的に `"*"` は非推奨なので、必要なホストのみ指定するのがベストです。
```python
ALLOWED_HOSTS = ["your-server-ip", "localhost"]
```

## 4. ファイアウォールの設定

Linuxのファイアウォール (`ufw` など) が `8000` ポートをブロックしている可能性があります。

### 確認方法
```sh
sudo netstat -tulnp | grep 8000
```
または
```sh
sudo ss -tulnp | grep 8000
```

**ポート開放のコマンド:**
```sh
sudo ufw allow 8000/tcp
sudo systemctl restart ufw
```
また、クラウド環境（AWS、GCPなど）を使用している場合は、**セキュリティグループの設定** でポート `8000` を開放する必要があります。

## 5. Nginx の設定ミス

Djangoを `gunicorn` + `nginx` で動作させている場合、`proxy_pass` の設定ミスが原因でアクセスできない可能性があります。

### 確認方法
Nginxの設定ファイル (`/etc/nginx/sites-available/default` または `nginx.conf`) に以下のような設定があるか確認します。

```nginx
server {
    listen 80;
    server_name your-server-ip;

    location / {
        proxy_pass http://django-dev:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```

### Nginx をリスタート
```sh
sudo systemctl restart nginx
```

## まとめ

この問題は、ポートの公開設定、Djangoのリスニングアドレス、`ALLOWED_HOSTS`、ファイアウォール設定、Nginxの設定ミスなど複数の要因によって発生する可能性があります。

:::note warn
***チェックリストを活用し、段階的にトラブルシューティングを進めてください。***
:::

まずは `docker ps` でポートが `0.0.0.0:8000` になっているか確認し、それでもダメなら `docker logs django-dev` のエラーメッセージを確認し、ファイアウォールや Nginx の設定を見直してみてください。