Nginx 憑藉高併發、低記憶體特性成為主流 Web 伺服器。本文實戰演示四大常見需求:目錄認證、防盜鏈、頻寬限制、多域名虛擬主機,並解決 PHP 應用中 $_SERVER['SERVER_NAME'] 取值異常問題。
# 安裝工具
yum install -y httpd-tools # CentOS/RHEL
apt install -y apache2-utils # Debian/Ubuntu
# 建立密碼檔(-c 建立新檔,-b 批次模式指定密碼)
htpasswd -bc /usr/local/nginx/conf/htpasswd admin 'StrongP@ssw0rd'
# 新增使用者(不加 -c)
htpasswd -b /usr/local/nginx/conf/htpasswd user2 'Passw0rd'
server {
listen 80;
server_name example.com;
root /var/www/html;
# ⚠️ 關鍵:location 區塊順序!必須放在 PHP 處理區塊之前
location ~ ^/admin/ {
auth_basic "Admin Area - Authorization Required";
auth_basic_user_file /usr/local/nginx/conf/htpasswd;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
原理:Nginx 依序匹配 location,若 PHP 區塊在前,.php 檔案會優先進入 fastcgi 處理,繞過 auth_basic。將保護區塊前置即可解決。
server {
# ...
location ~* \.(gif|png|jpg|jpeg|webp|flv|swf|mp4|pdf|zip|rar)$ {
valid_referers none blocked *.example.com example.com ~.google. ~.bing.;
if ($invalid_referer) {
# 方案一:返回 403
return 403;
# 方案二:重導向到預設圖片
# rewrite ^/ /images/hotlink.png last;
# 方案三:重導向到警告頁
# rewrite ^/ https://example.com/hotlink.html redirect;
}
# 可選:快取優化
expires 30d;
add_header Cache-Control "public";
}
}
參數說明:
none:允許無 Referer(直接輸入網址、書籤)blocked:允許 Referer 被防火牆/代理過滤的請求*.example.com:允許的域名(支援萬用字元)~.google.:正則匹配允許搜尋引擎抓取# 生成簽名腳本(Python 範例)
# import hmac, hashlib, base64, time
# secret = b'my_secret_key'
# expire = int(time.time()) + 3600 # 1 小時有效
# path = '/protected/video.mp4'
# sig = base64.urlsafe_b64encode(hmac.new(secret, f'{path}{expire}'.encode(), hashlib.md5).digest()).decode().rstrip('=')
# url = f'https://example.com{path}?md5={sig}&expires={expire}'
location /protected/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "my_secret_key$secure_link_expires$uri";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; } # 過期
# 通過驗證,提供檔案
}
http {
# 定義共享記憶體區域:key 為客戶端 IP,大小 10MB 可儲存約 16 萬狀態
limit_conn_zone $binary_remote_addr zone=perip:10m;
# 或以 server_name 為 key 限制單站總連線
limit_conn_zone $server_name zone=perserver:10m;
}
server {
# 限制單 IP 單站並發連線數
location /download/ {
limit_conn perip 5;
limit_conn perserver 1000;
}
}
location ~* \.(zip|rar|gz|tar|exe|mp4|mkv|iso)$ {
limit_conn perip 2; # 單 IP 最多 2 條下載連線
limit_rate 512k; # 每連線限速 512 KB/s
limit_rate_after 1m; # 前 1MB 不限速,之後限速(體驗優化)
}
進階:動態限速 根據使用者等級或時間段調整:
map $cookie_user_level $download_limit {
default 512k;
vip 2m;
premium 0; # 0 = 不限速
}
location /download/ {
limit_rate $download_limit;
}
配置泛域名時:
server_name *.example.com example.com;
PHP 中 $_SERVER['SERVER_NAME'] 永遠返回第一個域名(*.example.com),導致多站點識別失效。
FastCGI 參數預設傳遞 $server_name(Nginx 變數,取 server_name 第一項),而非實際請求的 Host 標頭。
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
# 關鍵修正:使用 $host(請求 Host 標頭)而非 $server_name
fastcgi_param SERVER_NAME $host;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 同時建議關閉重導向時使用 server_name 第一項
server_name_in_redirect off;
# 主站
server {
listen 80;
server_name example.com www.example.com;
root /var/www/main;
# ...
}
# 子站 A(獨立配置檔 /etc/nginx/conf.d/site-a.conf)
server {
listen 80;
server_name a.example.com;
root /var/www/site-a;
# ...
}
# 泛域名站點(動態站點,如 SaaS 多租戶)
server {
listen 80;
server_name ~^(?.+)\.saas\.example\.com$;
root /var/www/saas;
# PHP 中可用 $subdomain 變數識別租戶
# fastcgi_param TENANT $subdomain;
}
# 語法檢查
nginx -t
# 平滑重載(不中斷現有連線)
nginx -s reload
# 或
systemctl reload nginx
server_tokens off;add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff;client_max_body_size 10m;limit_req_zone 限制登入 API 頻率