😊

Django + Nginx環境で静的ファイルが404エラーになる問題の解決方法

に公開

Django + Nginx環境で静的ファイルが404エラーになる問題の解決方法

はじめに

DjangoアプリケーションをNginxでリバースプロキシ配信する際、静的ファイル(CSS、JavaScript、画像など)が404エラーになることがあります。本記事では、この問題の原因と解決方法を段階的に解説します。

問題の症状

以下のようなDjango 404エラーページが表示される:

Page not found (404)
Request Method: GET
Request URL: http://example.com/static/logo/logo_image.png

Using the URLconf defined in config.urls, Django tried these URL patterns, in this order:
1. [name='index']
2. blog/ [name='blog_list']
3. blog/<int:pk>/ [name='blog_detail']
...

The current path, static/logo/logo_image.png, didn't match any of these.

環境構成

  • サーバー: Linux (Amazon Linux等)
  • Webサーバー: Nginx
  • アプリケーション: Django
  • 静的ファイルの場所: /path/to/project/app_name/static/

原因の分析

1. 複数のServerブロックの競合

Nginxでは複数のserverブロックが同じポートをlistenしている場合、最初に見つけたものがデフォルトとして使用されます。

# /etc/nginx/nginx.conf にデフォルトのserverブロック
server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;  # ここが優先される
    ...
}
# /etc/nginx/conf.d/myapp.conf のカスタム設定
server {
    listen 80;  # 同じポートで競合
    location /static/ {
        alias /path/to/project/app_name/static/;
    }
    ...
}

2. ディレクトリアクセス権限の問題

Nginxのワーカープロセスが静的ファイルディレクトリにアクセスできない場合があります。

解決手順

Step 1: Nginxの設定状況を確認

現在の設定を確認します:

sudo nginx -T | grep -B 5 -A 15 "server {"

Step 2: デフォルトServerブロックの無効化

/etc/nginx/nginx.conf内のデフォルトserverブロックをコメントアウトします:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
sudo vi /etc/nginx/nginx.conf

以下の部分をコメントアウト:

# server {
#     listen       80;
#     listen       [::]:80;
#     server_name  _;
#     root         /usr/share/nginx/html;
#
#     include /etc/nginx/default.d/*.conf;
#     
#     error_page 404 /404.html;
#     location = /404.html {
#     }
#
#     error_page 500 502 503 504 /50x.html;
#     location = /50x.html {
#     }
# }

Step 3: カスタム設定ファイルの作成

/etc/nginx/conf.d/myapp.confを作成します:

upstream django_app {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name _;

    # 静的ファイルを直接配信
    location /static/ {
        alias /path/to/project/app_name/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Djangoアプリケーションへのプロキシ
    location / {
        proxy_pass http://django_app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Step 4: ディレクトリ権限の設定

Nginxワーカープロセスがファイルにアクセスできるよう権限を設定します:

# Nginxユーザーの確認
ps aux | grep nginx | head -2

# ディレクトリパス全体に実行権限を付与
sudo chmod 755 /home/username/
sudo chmod 755 /path/to/project/
sudo chmod 755 /path/to/project/app_name/
sudo chmod 755 /path/to/project/app_name/static/
sudo chmod 755 /path/to/project/app_name/static/images/

# ファイルに読み取り権限を付与
sudo chmod 644 /path/to/project/app_name/static/images/*

Step 5: 設定の適用とテスト

# 設定ファイルのテスト
sudo nginx -t

# Nginxの再読み込み
sudo systemctl reload nginx

# 動作確認
curl -I http://localhost/static/images/logo.png

トラブルシューティング

404エラーが続く場合

設定が正しく読み込まれているか確認:

sudo nginx -T | grep -A 10 "location /static/"

403 Forbiddenエラーの場合

権限問題の可能性があります:

# Nginxユーザーでのアクセステスト
sudo -u nginx ls -la /path/to/project/app_name/static/

# エラーログの確認
sudo tail -10 /var/log/nginx/error.log

パス設定の間違い

location /static/aliasのパスが正しく対応しているか確認:

# ❌ 間違い: 末尾スラッシュの不一致
location /static {  # スラッシュなし
    alias /path/to/static/;  # スラッシュあり
}

# ✅ 正しい: 末尾スラッシュを統一
location /static/ {  # スラッシュあり
    alias /path/to/static/;  # スラッシュあり
}

WhiteNoiseとの使い分け

現在の推奨構成(Nginx + WhiteNoise併存)

実際の運用では、以下のような構成が安全で効率的です:

server {
    listen 80;
    
    # Nginxで静的ファイルを直接配信(高速)
    location /static/ {
        alias /path/to/project/app_name/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    location / {
        proxy_pass http://django_app;
        # プロキシ設定
    }
}
# settings.py(WhiteNoiseも残す)
MIDDLEWARE = [
    "whitenoise.middleware.WhiteNoiseMiddleware",  # 残しておく
    # ...
]
STATIC_ROOT = "/path/to/static/"

この構成のメリット:

  • Nginxが優先: 静的ファイルはNginxが高速配信
  • フォールバック: Nginx設定にミスがあってもWhiteNoiseが動作
  • 開発環境対応: Nginxなしの環境でもWhiteNoiseが機能

WhiteNoiseのみで配信する場合

Nginxでの静的ファイル配信設定を削除し、すべてDjangoに委ねる方法:

server {
    listen 80;
    
    # 静的ファイル設定なし
    
    location / {
        proxy_pass http://django_app;
        # プロキシ設定
    }
}

この場合、すべての静的ファイルリクエストがDjangoに渡され、WhiteNoiseが処理します。

まとめ

Django + Nginx環境での静的ファイル404エラーの主な原因は:

  1. Serverブロックの競合: デフォルト設定が優先される
  2. 権限問題: Nginxユーザーがファイルにアクセスできない
  3. パス設定ミス: locationとaliasの不一致

これらを順序立てて解決することで、静的ファイルが正常に配信されるようになります。特に権限設定は見落としがちなポイントなので、注意深く確認することが重要です。

参考資料

Discussion