Nginx 作為靜態資源服務器或反向代理時,CSS/JS/圖片返回 404 是最常見的配置錯誤。核心原因在於 **location 匹配優先級** 與 **root/alias 指令用法** 的誤解。本文系統講解 Nginx 處理靜態文件的正確配置模式,解決路徑映射錯誤、優先級衝突、緩存優化等問題。
| 指令 | 路徑拼接邏輯 | 適用場景 |
|---|---|---|
root | 請求 URI **完整拼接** 到 root 路徑後location /static/ { root /data; }請求 /static/style.css → /data/static/style.css | 目錄結構與 URI 保持一致 |
alias | 請求 URI **替換 location 前綴** 後拼接location /static/ { alias /data/assets/; }請求 /static/style.css → /data/assets/style.css | URI 與實際目錄結構不一致 |
鐵律:alias **必須**以 / 結尾;location 使用正則時**不能用 alias** (僅支援 root)。
優先級從高到低:
1. = 精確匹配 location = /logo.png { ... }
2. ^~ 前綴匹配 (不再正則) location ^~ /static/ { ... }
3. ~ / ~* 正則匹配 location ~ \.(css|js|png)$ { ... }
4. / 通用前綴匹配 location / { ... }
陷阱:正則 location (~) 優先級**高於**普通前綴 location。若配置:
location / { proxy_pass https://backend; } # 所有請求代理到後端
location ~ \.(css|js)$ { root /data/static; } # 靜態文件正則
請求 /style.css 會匹配正則 location,**正常返回靜態文件**。但請求 /api/user.css (動態生成的 CSS) 也會被正則攔截,**錯誤返回 404**。
server {
listen 80;
server_name example.com;
root /data/www/example.com; # 全局 root, 所有 location 繼承
# 1. 優先處理靜態資源 (前綴匹配 ^~, 避免正則陷阱)
location ^~ /static/ {
# 實際路徑: /data/www/example.com/static/
expires 30d;
add_header Cache-Control "public";
access_log off;
try_files $uri =404; # 明確 404, 不落入後端
}
location ^~ /uploads/ {
# 用戶上傳文件, 禁用 PHP 執行 (安全)
location ~ \.php$ { deny all; }
expires 7d;
add_header Cache-Control "public";
}
# 2. 特定文件類型正則 (僅作為兜底, 不作為主要入口)
location ~* \.(jpg|jpeg|png|gif|ico|webp|css|js|woff|woff2|ttf|svg|mp4|webm)$ {
# 僅匹配未被上方 ^~ 捕獲的請求
expires 30d;
add_header Cache-Control "public";
access_log off;
try_files $uri =404;
}
# 3. 動態請求代理到 PHP-FPM
location / {
try_files $uri $uri/ /index.php?$query_string; # Laravel/ThinkPHP 路由支援
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_intercept_errors on;
}
# 4. 禁用隱藏文件訪問
location ~ /\. { deny all; access_log off; log_not_found off; }
}
location ^~ /app/ {
alias /data/www/example.com/dist/; # 注意 alias 尾部 /
try_files $uri $uri/ /app/index.html; # SPA 歷史模式回退
expires 1h; # HTML 不長期緩存
}
location ^~ /project1/ {
alias /data/www/project1/;
try_files $uri $uri/ /project1/index.html;
}
location ^~ /project2/ {
alias /data/www/project2/;
try_files $uri $uri/ /project2/index.php?$query_string;
}
location ~* \.(jpg|png|gif)$ {
valid_referers none blocked example.com *.example.com;
if ($invalid_referer) {
return 403; # 或 rewrite 到默認圖片
}
expires 30d;
}
# 開啟調試日誌 (需 nginx 編譯時 --with-debug)
error_log /var/log/nginx/debug.log debug;
# 或使用 ngx_lua 打印匹配信息
location / {
default_type text/plain;
echo "location: $uri";
echo "document_root: $document_root";
echo "request_filename: $request_filename";
}
^~ 前綴匹配,避免正則優先級陷阱。root 用於目錄結構一致,alias 用於目錄重映射 (注意尾部 /)。try_files $uri =404 明確靜態文件不存在時返回 404,不落入動態後端。location ~ \.php$ { deny all; } 防止腳本執行。expires + Cache-Control 減少重複請求。遵循「前綴優先、root/alias 分明、try_files 兜底、安全隔離」原則,可徹底解決 Nginx 靜態資源 404 難題。