症状

nginxで静的ファイル(CSS、JavaScript、画像など)にアクセスすると404 Not Foundが返される

結論:まずこれを確認

  1. nginx -T で実際に読み込まれている設定を確認
  2. root または alias のパスが実際のファイルパスと一致しているか確認
  3. ファイルとディレクトリのパーミッションを確認(nginxユーザーが読めるか)

トラブルシューティングフロー

    flowchart TD
    A[静的ファイルが404] --> B{error.logを確認}
    B -->|No such file or directory| C[パス設定を確認]
    B -->|Permission denied| D[パーミッション確認]
    B -->|エラーなし| E[access.logを確認]
    C --> F{root/aliasの設定}
    F -->|rootを使用| G[rootセクションへ]
    F -->|aliasを使用| H[aliasセクションへ]
    D --> I[パーミッションセクションへ]
    E --> J[リクエストが届いているか確認]
  

よくある原因

  • rootパスの誤り - rootディレクティブのパスがファイルの実際の場所と異なる
  • aliasの末尾スラッシュ - aliasディレクティブで末尾スラッシュの有無が不一致
  • パーミッション不足 - nginxの実行ユーザーがファイルを読み取れない
  • SELinuxの制限 - SELinuxがファイルアクセスをブロックしている(RHEL/CentOS系)
  • locationブロックの優先順位 - 別のlocationブロックが先にマッチしている
  • シンボリックリンクの設定 - disable_symlinks が有効になっている
  • try_filesの設定ミス - 静的ファイルの前にバックエンドへ転送している

確認手順

ステップ1: エラーログを確認する

    # 最新のエラーログを確認
sudo tail -50 /var/log/nginx/error.log

# 特定のファイル名でフィルタ
sudo grep "ファイル名" /var/log/nginx/error.log
  

🔍 チェックポイント: No such file or directory または Permission denied のメッセージを探す

ステップ2: 実際の設定を確認する

    # 読み込まれている設定を全て表示
sudo nginx -T

# 設定ファイルのシンタックスチェック
sudo nginx -t
  

🔍 チェックポイント: root または alias の値をメモする

ステップ3: ファイルパスを検証する

    # 設定から読み取ったパスにファイルが存在するか確認
ls -la /設定で指定したパス/ファイル名

# rootの場合: root + URI がファイルパスになる
# 例: root /var/www/html; で /css/style.css へアクセス
#     → /var/www/html/css/style.css を探す
ls -la /var/www/html/css/style.css

# aliasの場合: alias がURIの該当部分を置き換える
# 例: location /static/ { alias /var/www/files/; }
#     → /static/image.png は /var/www/files/image.png を探す
ls -la /var/www/files/image.png
  

🔍 チェックポイント: ファイルが存在し、パスが正しいことを確認

ステップ4: パーミッションを確認する

    # nginxの実行ユーザーを確認
ps aux | grep nginx

# ファイルのパーミッションを確認
ls -la /var/www/html/css/style.css

# ディレクトリのパーミッションを再帰的に確認
namei -l /var/www/html/css/style.css
  

🔍 チェックポイント: nginxユーザー(通常 nginx または www-data)がすべてのディレクトリに対して x(実行)権限、ファイルに対して r(読み取り)権限を持っている

ステップ5: SELinuxを確認する(RHEL/CentOS系のみ)

    # SELinuxの状態を確認
getenforce

# httpd_sys_content_t のコンテキストを確認
ls -Z /var/www/html/

# 拒否されたログを確認
sudo ausearch -m avc -ts recent
  

🔍 チェックポイント: Enforcing の場合、ファイルに httpd_sys_content_t コンテキストがあるか確認

ステップ6: locationブロックの優先順位を確認する

    # 設定を確認し、該当URIにマッチするlocationを特定
sudo nginx -T | grep -A 10 "location"
  

🔍 チェックポイント: より具体的な(または正規表現の)locationブロックが先にマッチしていないか確認

nginx の location マッチング優先順位:

  1. = 完全一致
  2. ^~ 前方一致(正規表現より優先)
  3. ~ / ~* 正規表現
  4. 前方一致(最長マッチ)

NG行動(やってはいけないこと)

  • chmod 777 を使う - セキュリティリスク。適切な権限(644 for files, 755 for dirs)を設定する
  • SELinuxを無効化する - 代わりにコンテキストを正しく設定する
  • 設定変更後にreloadしない - nginx -s reload を忘れると変更が反映されない
  • error.logを確認せずに設定を変更する - 原因を特定してから修正する
  • 本番環境で直接設定を編集する - 必ず nginx -t でテストしてからreload

よくある質問(FAQ)

Q1: rootとaliasの違いは?

A: root はlocationのURIをそのまま追加する。alias はlocationで指定した部分を置き換える。

    # root の場合
location /images/ {
    root /var/www;
}
# /images/photo.jpg → /var/www/images/photo.jpg

# alias の場合
location /images/ {
    alias /var/www/photos/;
}
# /images/photo.jpg  /var/www/photos/photo.jpg
  

Q2: aliasで末尾スラッシュは必要?

A: locationが /images/ のようにスラッシュで終わる場合、aliasも /var/www/photos/ のようにスラッシュで終わる必要がある。不一致だとパスが正しく構成されない。

Q3: 特定のファイルだけ404になる

A: ファイル名に特殊文字(スペース、日本語など)が含まれていないか確認。また、.htaccess は nginx では無視されるため、Apache からの移行時に注意。

関連するエラー・症状

  • (関連記事準備中)
  • (関連記事準備中)
  • (関連記事準備中)

解決しない場合

公式ドキュメント

確認すべきログファイル

  • /var/log/nginx/error.log - エラーの詳細
  • /var/log/nginx/access.log - リクエストの到達確認
  • /var/log/audit/audit.log - SELinux拒否ログ(RHEL系)

次に調べるキーワード

  • nginx try_files 404
  • nginx location priority
  • nginx symlink permission