Nginx 配置详解教程¶
本文聚焦 Nginx 各类配置场景,从基础语法到生产实战,覆盖静态服务、反向代理、负载均衡、HTTPS、缓存、限流、日志等核心主题。
目录¶
1. 配置文件结构¶
Nginx 配置文件采用层级块结构,核心层次如下:
main(全局)
├── events { }
└── http { }
├── upstream { }
├── server { }
│ ├── location { }
│ └── location { }
└── server { }
文件路径(Ubuntu/Debian):
/etc/nginx/
├── nginx.conf # 主配置文件,通常只保留全局和 http 骨架
├── conf.d/ # 推荐在此放自定义配置(*.conf 自动加载)
├── sites-available/ # 虚拟主机配置文件存放
├── sites-enabled/ # 软链接到 sites-available 中已启用的站点
├── snippets/ # 可复用的配置片段
├── mime.types # MIME 类型映射表
└── fastcgi_params # FastCGI 默认参数
主配置文件骨架:
# nginx.conf
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 引入 conf.d 下所有配置
include /etc/nginx/conf.d/*.conf;
# 引入已启用的虚拟主机
include /etc/nginx/sites-enabled/*;
}
2. 全局配置(main 块)¶
全局块位于配置文件最外层,影响 Nginx 整体行为。
# 运行 Nginx 的系统用户(需与静态文件权限匹配)
user www-data;
# 工作进程数,auto = CPU 核心数
# 可手动指定,如 worker_processes 4;
worker_processes auto;
# 工作进程绑定 CPU(多核优化,减少上下文切换)
# worker_cpu_affinity auto;
# worker_cpu_affinity 0001 0010 0100 1000; # 手动绑定 4 核
# 工作进程优先级,-20(最高)到 19(最低),默认 0
worker_priority 0;
# 工作进程可打开的最大文件描述符数(需与系统 ulimit 配合)
worker_rlimit_nofile 65535;
# 错误日志路径及级别(debug | info | notice | warn | error | crit | alert | emerg)
error_log /var/log/nginx/error.log warn;
# PID 文件路径
pid /var/run/nginx.pid;
# 是否以守护进程方式运行(生产环境 on,Docker 中通常 off)
# daemon on;
# 加载动态模块
# load_module modules/ngx_http_image_filter_module.so;
3. events 块¶
events 块控制 Nginx 处理网络事件的方式。
events {
# 每个工作进程的最大并发连接数
# 总并发 = worker_processes × worker_connections
worker_connections 1024;
# 事件驱动模型(Linux 推荐 epoll,macOS 用 kqueue,默认自动选择)
use epoll;
# 是否允许一个工作进程同时接受多个新连接(on = 高并发场景更高效)
multi_accept on;
# accept 互斥锁,防止惊群问题(Nginx 1.11.3+ 默认关闭,性能更好)
# accept_mutex on;
# accept_mutex_delay 500ms;
}
4. http 块核心参数¶
http {
# MIME 类型
include /etc/nginx/mime.types;
default_type application/octet-stream; # 未知类型默认值
# 字符集
charset utf-8;
# 高效文件传输(直接从内核发送文件,绕过用户空间,显著提升静态文件性能)
sendfile on;
# 与 sendfile 配合,等待数据积累到一定量再发送(减少网络包数量)
tcp_nopush on;
# 禁用 Nagle 算法,减少延迟(适合实时交互场景)
tcp_nodelay on;
# 关闭 server_tokens,不在响应头暴露 Nginx 版本号
server_tokens off;
# 长连接保持时间(单位秒),第二个参数是发送给客户端的 Keep-Alive 头值
keepalive_timeout 65 60;
# 单个长连接最多处理的请求数
keepalive_requests 1000;
# 客户端请求体最大值(文件上传限制)
client_max_body_size 20m;
# 请求体缓冲区大小(超过则写入临时文件)
client_body_buffer_size 128k;
# 请求头缓冲区(超大 Header 时调大)
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;
# 哈希表大小(服务器名称哈希,域名多时需调大)
server_names_hash_bucket_size 128;
server_names_hash_max_size 1024;
# 开启变量哈希(map 等模块需要)
variables_hash_max_size 1024;
variables_hash_bucket_size 64;
}
5. server 块与虚拟主机¶
一个 http 块中可以有多个 server,Nginx 根据 listen 端口和 server_name 来匹配请求。
5.1 基本虚拟主机¶
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html index.htm;
access_log /var/log/nginx/example.access.log main;
error_log /var/log/nginx/example.error.log warn;
}
5.2 默认服务器¶
当请求的 Host 不匹配任何 server_name 时,使用 default_server:
server {
listen 80 default_server;
server_name _; # _ 匹配所有未命中的域名
return 444; # 直接断开连接,不返回任何内容
}
5.3 server_name 匹配方式¶
# 精确匹配(优先级最高)
server_name example.com;
# 通配符前缀
server_name *.example.com;
# 通配符后缀
server_name example.*;
# 正则匹配(以 ~ 开头,优先级低于精确和通配符)
server_name ~^(www\.)?example\.com$;
# 正则捕获组(可在配置中引用 $1)
server_name ~^(api|admin)\.example\.com$;
# 此时 $1 = api 或 admin,可用于 root 路径等
root /var/www/$1;
匹配优先级: 精确名称 > 通配符前缀(*.example.com)> 通配符后缀(example.*)> 正则
5.4 多端口监听¶
server {
listen 80;
listen 8080;
listen [::]:80; # IPv6
server_name example.com;
# ...
}
6. location 匹配规则¶
location 是 Nginx 最灵活的配置单元,决定如何处理特定路径的请求。
6.1 匹配语法¶
语法 |
类型 |
说明 |
|---|---|---|
|
前缀匹配 |
URI 以 /path 开头即匹配 |
|
精确匹配 |
URI 完全等于 /path |
|
优先前缀 |
匹配后不再检查正则 |
|
正则(区分大小写) |
正则匹配 |
|
正则(忽略大小写) |
正则匹配,不区分大小写 |
|
命名 location |
用于内部跳转 |
6.2 匹配优先级(从高到低)¶
1. = 精确匹配
2. ^~ 优先前缀匹配
3. ~ 或 ~* 正则匹配(按配置文件顺序,先匹配先生效)
4. 普通前缀匹配(取最长前缀)
6.3 示例¶
server {
# 精确匹配首页,直接返回
location = / {
return 200 "exact root";
}
# 优先前缀匹配 /static,不走正则
location ^~ /static/ {
root /var/www;
}
# 正则:匹配图片文件(不区分大小写)
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 30d;
add_header Cache-Control "public";
}
# 正则:PHP 处理
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# 普通前缀匹配(兜底)
location / {
try_files $uri $uri/ /index.html;
}
}
6.4 try_files¶
try_files 按顺序检查文件是否存在,找不到则执行最后一个参数:
location / {
# 依次尝试:文件 → 目录 → 重写到 index.php
try_files $uri $uri/ /index.php?$query_string;
}
location / {
# 依次尝试:文件 → 返回 404
try_files $uri $uri/ =404;
}
# 命名 location 跳转
location / {
try_files $uri @backend;
}
location @backend {
proxy_pass http://127.0.0.1:3000;
}
7. 静态文件服务¶
7.1 基本配置¶
server {
listen 80;
server_name static.example.com;
# 文档根目录
root /var/www/static;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# 禁止访问隐藏文件(.htaccess, .git 等)
location ~ /\. {
deny all;
}
}
7.2 静态文件缓存头¶
# 图片、字体、媒体文件 - 长期缓存
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|woff|woff2|ttf|eot)$ {
expires 90d;
add_header Cache-Control "public, immutable";
access_log off; # 关闭静态资源日志,减少 IO
}
# CSS、JS - 中期缓存(配合 Hash 文件名使用 immutable)
location ~* \.(css|js)$ {
expires 30d;
add_header Cache-Control "public";
}
# HTML - 不缓存,确保用户拿到最新页面
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
7.3 目录列表(文件服务器)¶
location /files/ {
root /data;
autoindex on; # 开启目录列表
autoindex_exact_size off; # 文件大小用 KB/MB 显示,不显示精确字节数
autoindex_localtime on; # 使用本地时间
}
7.4 alias 与 root 的区别¶
# root:将 location 前缀追加到 root 后
# 请求 /static/a.js → 实际路径 /var/www/static/a.js
location /static/ {
root /var/www;
}
# alias:用 alias 路径替换 location 前缀
# 请求 /static/a.js → 实际路径 /data/assets/a.js
location /static/ {
alias /data/assets/; # 注意:alias 末尾必须有斜杠
}
8. 反向代理配置¶
8.1 基本反向代理¶
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
# 传递真实 Host,让后端知道原始域名
proxy_set_header Host $host;
# 传递客户端真实 IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# HTTP/1.1 支持 WebSocket 和长连接
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
8.2 proxy_pass 的 URL 末尾斜杠问题¶
# 不带斜杠:将完整 URI 传给后端
# 请求 /api/users → 后端收到 /api/users
location /api {
proxy_pass http://backend;
}
# 带斜杠:去掉 location 前缀后转发
# 请求 /api/users → 后端收到 /users
location /api/ {
proxy_pass http://backend/;
}
# 带路径的 proxy_pass:同样去掉前缀再拼接
# 请求 /api/users → 后端收到 /v1/users
location /api/ {
proxy_pass http://backend/v1/;
}
8.3 代理缓冲配置¶
location / {
proxy_pass http://backend;
# 开启代理缓冲(默认开启)
proxy_buffering on;
# 响应头缓冲区
proxy_buffer_size 4k;
# 响应体缓冲区(个数 × 大小)
proxy_buffers 8 16k;
# 忙碌缓冲区上限(正在写入客户端的最大缓冲量)
proxy_busy_buffers_size 32k;
# 临时文件大小上限(缓冲区满后溢出到磁盘)
proxy_temp_file_write_size 64k;
proxy_max_temp_file_size 1024m;
# 对大文件/流媒体关闭缓冲,直接透传
# proxy_buffering off;
}
8.4 代理错误处理¶
location / {
proxy_pass http://backend;
# 后端返回这些状态码时,转给 error_page 处理
proxy_intercept_errors on;
# 自定义错误页
error_page 502 503 504 /50x.html;
location = /50x.html {
root /var/www/errors;
}
# 后端不可用时尝试备用(需配合 upstream)
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 10s;
}
9. 负载均衡配置¶
9.1 upstream 基本配置¶
upstream backend {
# 默认:轮询(Round Robin)
server 192.168.1.10:3000;
server 192.168.1.11:3000;
server 192.168.1.12:3000;
}
server {
location / {
proxy_pass http://backend;
}
}
9.2 server 参数详解¶
upstream backend {
server 192.168.1.10:3000 weight=5; # 权重,默认 1,越大越多请求
server 192.168.1.11:3000 weight=3;
server 192.168.1.12:3000 weight=1
max_fails=3 # 失败多少次标记为不可用
fail_timeout=30s; # 标记不可用后多久重新尝试
server 192.168.1.13:3000 backup; # 备用服务器,主服务器全挂才启用
server 192.168.1.14:3000 down; # 标记为永久下线(维护用)
# 每个 worker 进程保持的长连接数
keepalive 32;
}
9.3 负载均衡策略¶
# 最少连接(适合请求处理时间差异大的场景)
upstream backend {
least_conn;
server 192.168.1.10:3000;
server 192.168.1.11:3000;
}
# IP Hash(同一客户端 IP 固定到同一服务器,适合有 Session 的应用)
upstream backend {
ip_hash;
server 192.168.1.10:3000;
server 192.168.1.11:3000;
}
# 哈希(按任意 key 分配,如 URL,适合缓存服务器)
upstream backend {
hash $request_uri consistent; # consistent = 一致性哈希,节点变动影响最小
server 192.168.1.10:3000;
server 192.168.1.11:3000;
}
# 随机(Nginx 1.15.1+)
upstream backend {
random two least_conn; # 随机选 2 个,再选连接数少的
server 192.168.1.10:3000;
server 192.168.1.11:3000;
}
9.4 健康检查(商业版 / OpenResty)¶
开源 Nginx 通过 max_fails + fail_timeout 做被动检查。如需主动健康检查,使用 nginx_upstream_check_module:
upstream backend {
server 192.168.1.10:3000;
server 192.168.1.11:3000;
# 需要 nginx_upstream_check_module
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "HEAD / HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
10. HTTPS / SSL 配置¶
10.1 Let’s Encrypt 自动证书¶
# 安装 certbot
sudo apt install certbot python3-certbot-nginx
# 自动申请并配置证书
sudo certbot --nginx -d example.com -d www.example.com
# 测试自动续期
sudo certbot renew --dry-run
# 查看证书到期时间
sudo certbot certificates
10.2 完整 SSL 配置¶
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# 证书和私钥
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 版本(只允许 1.2 和 1.3,禁用旧版本)
ssl_protocols TLSv1.2 TLSv1.3;
# 加密套件(Mozilla 现代推荐配置)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off; # TLS 1.3 客户端选择更合理
# Session 缓存(减少握手开销)
ssl_session_cache shared:SSL:10m; # 10MB,约可缓存 40000 个 Session
ssl_session_timeout 1d;
ssl_session_tickets off; # 禁用 Tickets(提升前向保密性)
# OCSP Stapling(加速证书验证,让 Nginx 代替浏览器查询证书状态)
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
# HSTS(强制 HTTPS,max-age 单位秒,2年 = 63072000)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
location / {
root /var/www/example.com;
index index.html;
}
}
# HTTP 强制跳转 HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# Let's Encrypt 验证路径不跳转
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
10.3 DH 参数(增强密钥交换安全性)¶
# 生成 DH 参数(2048 位,耗时较长)
openssl dhparam -out /etc/nginx/dhparam.pem 2048
ssl_dhparam /etc/nginx/dhparam.pem;
10.4 双证书配置(ECC + RSA)¶
# ECC 证书(速度快,优先使用)
ssl_certificate /path/to/ecc/fullchain.pem;
ssl_certificate_key /path/to/ecc/privkey.pem;
# RSA 证书(兼容旧客户端)
ssl_certificate /path/to/rsa/fullchain.pem;
ssl_certificate_key /path/to/rsa/privkey.pem;
11. HTTP/2 与 HTTP/3¶
11.1 HTTP/2¶
server {
# 在 listen 后加 http2 即开启(需要 SSL)
listen 443 ssl http2;
# HTTP/2 服务器推送(提前推送关键资源)
location = /index.html {
http2_push /style.css;
http2_push /app.js;
}
# 推送预加载 Link 头中声明的资源
http2_push_preload on;
}
11.2 HTTP/3(QUIC,Nginx 1.25+)¶
server {
listen 443 ssl http2;
listen 443 quic reuseport; # HTTP/3 over QUIC(UDP)
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# 通知客户端支持 HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400';
}
12. Gzip 压缩¶
http {
# 开启 Gzip
gzip on;
# 压缩级别(1-9,越高压缩率越好但越耗 CPU,推荐 4-6)
gzip_comp_level 5;
# 最小压缩大小(小于此值不压缩,单位字节)
gzip_min_length 1024;
# 压缩缓冲区
gzip_buffers 16 8k;
# 兼容 HTTP/1.0 代理
gzip_http_version 1.1;
# 需要压缩的 MIME 类型(text/html 默认压缩,无需指定)
gzip_types
text/plain
text/css
text/javascript
text/xml
application/json
application/javascript
application/x-javascript
application/xml
application/xml+rss
application/atom+xml
image/svg+xml
font/ttf
font/otf;
# 在响应头加 Vary: Accept-Encoding(告知代理服务器分别缓存压缩和非压缩版本)
gzip_vary on;
# 对代理请求也压缩(any = 无论 Via 头如何)
gzip_proxied any;
# 关闭对 IE6 的 Gzip(IE6 有 Gzip bug)
gzip_disable "msie6";
}
预压缩静态文件(减少实时压缩 CPU 开销):
location ~* \.(css|js|json|svg)$ {
# 优先使用预压缩的 .gz 文件
gzip_static on;
}
# 提前生成 .gz 文件
gzip -k -9 /var/www/static/app.js
# 生成 app.js.gz,Nginx 会自动选用
13. 缓存配置¶
13.1 代理缓存(proxy_cache)¶
http {
# 定义缓存区(名称 cache_zone,路径,层级,共享内存大小,最大缓存大小,非活跃时间)
proxy_cache_path /var/cache/nginx
levels=1:2 # 目录层级(避免单目录文件过多)
keys_zone=cache_zone:10m # 共享内存 key 存储区,10MB 约存 80000 个 key
max_size=2g # 磁盘最大使用量
inactive=60m # 60 分钟内未被访问则删除
use_temp_path=off; # 直接写入缓存目录(减少一次文件复制)
server {
location / {
proxy_pass http://backend;
proxy_cache cache_zone;
# 缓存 key(默认按完整 URL 缓存)
proxy_cache_key "$scheme$proxy_host$request_uri";
# 对不同状态码设置不同缓存时间
proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m; # 其他状态码缓存 1 分钟
# 当后端请求失败时,继续使用过期缓存(防止缓存穿透)
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# 后台异步更新缓存(不阻塞当前请求)
proxy_cache_background_update on;
# 同一 key 同时只允许一个请求回源,其他请求等待(防止缓存击穿)
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
# 在响应头中添加缓存命中状态(HIT/MISS/BYPASS/EXPIRED)
add_header X-Cache-Status $upstream_cache_status;
# 跳过缓存的条件(POST 请求、带 Cookie 的请求等)
proxy_cache_bypass $http_pragma $http_authorization;
proxy_no_cache $http_pragma $http_authorization;
}
# 手动清除缓存(需要 ngx_cache_purge 模块)
# location ~ /purge(/.*) {
# proxy_cache_purge cache_zone "$scheme$proxy_host$1";
# }
}
}
13.2 FastCGI 缓存(PHP)¶
http {
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=fcgi_cache:10m
max_size=1g
inactive=30m;
server {
set $skip_cache 0;
# POST 请求不缓存
if ($request_method = POST) { set $skip_cache 1; }
# 带 query string 的请求不缓存
if ($query_string != "") { set $skip_cache 1; }
# 管理后台不缓存
if ($request_uri ~* "/admin/") { set $skip_cache 1; }
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache fcgi_cache;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Cache $upstream_cache_status;
}
}
}
14. 限流与限速¶
14.1 请求频率限制(limit_req)¶
防止单个 IP 请求过于频繁,抵御暴力破解和 DDoS。
http {
# 定义限流区域(按 IP 限制,内存 10MB)
# 1MB 约存 16000 个 IP
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
# 也可以按 URL 限制
limit_req_zone $uri zone=uri_limit:10m rate=100r/s;
# 登录接口单独严格限制
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s;
server {
# 全局应用限流(允许突发 20 个请求,超出排队等待)
location / {
limit_req zone=req_limit burst=20 nodelay;
# burst:允许突发请求数(短期超出 rate 的队列容量)
# nodelay:突发请求直接处理,不延迟(超出 burst 才拒绝)
}
# 登录接口严格限流
location /login {
limit_req zone=login_limit burst=5;
limit_req_status 429; # 超限返回 429(默认 503)
}
}
}
14.2 并发连接限制(limit_conn)¶
http {
# 按 IP 限制并发连接数
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# 按 server_name 限制
limit_conn_zone $server_name zone=server_conn:10m;
server {
# 每个 IP 最多 10 个并发连接
limit_conn conn_limit 10;
# 整个 server 最多 1000 个连接
limit_conn server_conn 1000;
# 超限返回状态码(默认 503)
limit_conn_status 503;
# 日志级别(默认 error)
limit_conn_log_level warn;
}
}
14.3 带宽限速¶
location /downloads/ {
# 下载速度限制为 512KB/s
limit_rate 512k;
# 前 10MB 不限速,之后限速(让小文件快速下载,大文件限速)
limit_rate_after 10m;
limit_rate 200k;
}
15. 访问控制¶
15.1 IP 白名单 / 黑名单¶
location /admin/ {
# 白名单
allow 192.168.1.0/24; # 允许整个网段
allow 10.0.0.1; # 允许单个 IP
allow 127.0.0.1;
deny all; # 拒绝其他所有
}
# 黑名单(先放行,最后允许其他)
location / {
deny 192.168.1.100; # 屏蔽指定 IP
deny 10.0.0.0/8; # 屏蔽整个网段
allow all;
}
15.2 HTTP Basic 认证¶
# 生成密码文件(需要 apache2-utils)
sudo apt install apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 添加更多用户(不带 -c,否则覆盖)
sudo htpasswd /etc/nginx/.htpasswd user2
location /private/ {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
15.3 防盗链(referer 检查)¶
location ~* \.(jpg|png|gif|mp4)$ {
valid_referers none blocked example.com *.example.com;
# none:直接访问(无 Referer 头)
# blocked:Referer 存在但被防火墙删除了 http:// 前缀
if ($invalid_referer) {
return 403;
# 或者返回替换图片
# rewrite ^ /images/forbidden.jpg last;
}
}
15.4 地理位置限制(需要 GeoIP2 模块)¶
# 加载 GeoIP2 模块
load_module modules/ngx_http_geoip2_module.so;
http {
geoip2 /var/lib/GeoIP/GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_country_code country iso_code;
}
map $geoip2_country_code $allowed_country {
default 1;
CN 1;
US 1;
# 屏蔽特定国家
KP 0;
RU 0;
}
server {
if ($allowed_country = 0) {
return 403;
}
}
}
16. 日志配置¶
16.1 日志格式¶
http {
# 自定义日志格式(JSON 格式,方便 ELK/Loki 采集)
log_format json_log escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"upstream_addr":"$upstream_addr",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for"'
'}';
# 传统格式(combined 是默认格式)
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 带响应时间的扩展格式
log_format detailed
'$remote_addr - [$time_local] "$request" $status $body_bytes_sent '
'rt=$request_time uct=$upstream_connect_time uht=$upstream_header_time urt=$upstream_response_time';
# 全局访问日志
access_log /var/log/nginx/access.log main;
}
16.2 server 和 location 级别的日志¶
server {
access_log /var/log/nginx/app.access.log json_log;
error_log /var/log/nginx/app.error.log warn;
# 静态资源不记录日志(减少 IO)
location ~* \.(ico|css|js|gif|jpg|png|woff)$ {
access_log off;
}
# 健康检查不记录日志
location = /health {
access_log off;
return 200 "OK";
}
}
16.3 日志轮转(logrotate)¶
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每天轮转
missingok # 文件不存在不报错
rotate 14 # 保留 14 天
compress # 压缩旧日志
delaycompress # 上一个周期不压缩(方便排查最近问题)
notifempty # 日志为空不轮转
sharedscripts
postrotate
# 向 Nginx 发送 USR1 信号,重新打开日志文件
nginx -s reopen
endscript
}
17. 安全加固配置¶
http {
# 隐藏版本号
server_tokens off;
# 防止点击劫持(禁止 iframe 嵌入)
add_header X-Frame-Options "SAMEORIGIN" always;
# 禁止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" always;
# XSS 防护(现代浏览器 CSP 更好,但保留兼容旧浏览器)
add_header X-XSS-Protection "1; mode=block" always;
# 内容安全策略(CSP)- 根据业务调整
add_header Content-Security-Policy
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"
always;
# 控制 Referer 信息泄露
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 权限策略(限制浏览器功能)
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# 限制请求方法(只允许 GET/POST/HEAD)
server {
if ($request_method !~ ^(GET|HEAD|POST)$) {
return 405;
}
}
# 防止慢速攻击(Slowloris)
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
# 限制请求体(防止大文件攻击)
client_max_body_size 10m;
}
18. WebSocket 代理¶
WebSocket 升级需要特殊处理 Upgrade 和 Connection 头。
http {
# map 处理 Connection 升级头
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location /ws/ {
proxy_pass http://websocket_backend;
# WebSocket 必须是 HTTP/1.1
proxy_http_version 1.1;
# 传递升级头
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 传递客户端信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 关闭超时(WebSocket 连接应该长期保持)
proxy_read_timeout 86400s; # 24 小时
proxy_send_timeout 86400s;
# 关闭缓冲(WebSocket 需要实时传输)
proxy_buffering off;
}
}
}
19. upstream 高级配置¶
19.1 长连接复用¶
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
# Nginx 与后端保持的长连接数(HTTP/1.1 开启)
keepalive 32;
# 单个长连接最多复用请求数(防止连接过久)
keepalive_requests 1000;
# 长连接空闲超时
keepalive_timeout 60s;
}
server {
location / {
proxy_pass http://backend;
# 必须是 HTTP/1.1 才能复用长连接
proxy_http_version 1.1;
# 清除 Connection 头,否则默认 close 会关闭长连接
proxy_set_header Connection "";
}
}
19.2 故障转移配置¶
upstream backend {
server 192.168.1.10:3000 max_fails=3 fail_timeout=30s;
server 192.168.1.11:3000 max_fails=3 fail_timeout=30s;
server 192.168.1.12:3000 backup;
}
server {
location / {
proxy_pass http://backend;
# 在哪些情况下尝试下一台服务器
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
# 最多重试几次
proxy_next_upstream_tries 3;
# 重试总时间限制
proxy_next_upstream_timeout 10s;
}
}
20. 重写与重定向¶
20.1 return 指令(推荐,性能好)¶
# 301 永久重定向(浏览器会缓存)
return 301 https://$host$request_uri;
# 302 临时重定向
return 302 https://new.example.com$request_uri;
# 直接返回响应(不经过 proxy)
return 200 "OK";
return 404;
return 429 "Too Many Requests";
20.2 rewrite 指令¶
# 语法:rewrite regex replacement [flag]
# flag: last | break | redirect(302) | permanent(301)
# 去掉 index.php(SEO 优化)
rewrite ^/index\.php(/?.*)$ $1 last;
# 旧路径重写到新路径
rewrite ^/old/(.*)$ /new/$1 permanent;
# 添加 www
if ($host = 'example.com') {
rewrite ^(.*)$ https://www.example.com$1 permanent;
}
# 目录结构重写(WordPress / Laravel 等)
location / {
try_files $uri $uri/ /index.php?$args;
}
20.3 rewrite flag 说明¶
flag |
说明 |
|---|---|
|
终止当前 rewrite,用新 URI 重新匹配 location |
|
终止 rewrite,在当前 location 继续处理 |
|
返回 302 临时重定向 |
|
返回 301 永久重定向 |
20.4 常用重写场景¶
# www 和非 www 统一(非 www 跳 www)
server {
listen 80;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
# 强制末尾斜杠
rewrite ^([^.]*[^/])$ $1/ permanent;
# 移除末尾斜杠
rewrite ^/(.*)/+$ /$1 permanent;
# URL 大小写统一(转小写,需要 Lua 或 map)
map $uri $uri_lowercase {
~^(.+)$ $1;
}
21. 变量与 map 模块¶
21.1 常用内置变量¶
变量 |
说明 |
|---|---|
|
请求的 Host(优先:请求行 > 请求头 > server_name) |
|
匹配的 server_name |
|
完整 URI(含查询字符串) |
|
当前 URI(不含查询字符串,rewrite 后会变化) |
|
查询字符串 |
|
客户端 IP |
|
二进制格式 IP(limit_req 用,节省内存) |
|
http 或 https |
|
GET / POST / PUT 等 |
|
响应状态码 |
|
后端服务器地址 |
|
后端响应时间 |
|
总请求时间(含客户端传输) |
|
客户端 UA |
|
来源页 |
|
经过代理的原始 IP 链 |
21.2 map 模块¶
map 根据一个变量的值映射出另一个变量,性能优于 if。
http {
# 移动端检测
map $http_user_agent $is_mobile {
default 0;
~*android 1;
~*iphone 1;
~*ipod 1;
~*mobile 1;
}
# 根据来源国家设置语言
map $geoip2_country_code $lang {
default en;
CN zh;
TW zh;
JP ja;
KR ko;
}
# 根据设备跳转不同站点
server {
if ($is_mobile) {
return 302 https://m.example.com$request_uri;
}
}
}
21.3 geo 模块(按 IP 段设置变量)¶
geo $remote_addr $is_internal {
default 0;
10.0.0.0/8 1;
172.16.0.0/12 1;
192.168.0.0/16 1;
127.0.0.1/32 1;
}
22. 超时参数全解¶
http {
# ===== 客户端相关超时 =====
# 读取请求头的超时(从连接建立到读完请求头)
client_header_timeout 10s;
# 读取请求体的超时(两次读操作之间的最大间隔,不是总时间)
client_body_timeout 30s;
# 向客户端发送响应的超时(两次写操作之间的间隔)
send_timeout 30s;
# 长连接超时
keepalive_timeout 65s;
# ===== 代理相关超时 =====
# 与后端建立连接的超时(通常 60s 内连不上就是后端挂了)
proxy_connect_timeout 60s;
# 读取后端响应的超时(两次读操作之间,不是整个响应时间)
proxy_read_timeout 60s;
# 向后端发送请求的超时
proxy_send_timeout 60s;
# ===== FastCGI 相关超时 =====
fastcgi_connect_timeout 60s;
fastcgi_read_timeout 300s; # PHP 脚本执行可能较慢
fastcgi_send_timeout 60s;
# ===== 解析器超时 =====
resolver_timeout 10s;
}
23. 常用完整配置示例¶
23.1 前端单页应用(SPA)¶
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/app/dist;
index index.html;
# HTML 不缓存,保证更新即时生效
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# 静态资源长期缓存(文件名含 Hash)
location ~* \.(js|css|png|jpg|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# SPA 路由:所有未匹配路径返回 index.html
location / {
try_files $uri $uri/ /index.html;
}
# API 反向代理
location /api/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
23.2 Node.js / Python 应用反向代理¶
upstream node_app {
server 127.0.0.1:3000;
keepalive 16;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/ssl/certs/example.crt;
ssl_certificate_key /etc/ssl/private/example.key;
ssl_protocols TLSv1.2 TLSv1.3;
# 请求日志
access_log /var/log/nginx/api.access.log detailed;
# 全局限流
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s;
location / {
limit_req zone=api_limit burst=50 nodelay;
proxy_pass http://node_app;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
# 后端出错时的降级
proxy_next_upstream error timeout http_502 http_503;
proxy_next_upstream_tries 2;
}
location = /health {
access_log off;
proxy_pass http://node_app;
}
}
23.3 WordPress / PHP 配置¶
server {
listen 80;
server_name blog.example.com;
root /var/www/wordpress;
index index.php;
# 阻止 WordPress 系统文件直接访问
location = /wp-config.php { deny all; }
location ~ /\. { deny all; }
location ~ /wp-admin/includes { deny all; }
location ~ /readme\.(html|txt) { deny all; }
# 静态资源缓存
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2?)$ {
expires 30d;
log_not_found off;
access_log off;
}
# WordPress 固定链接支持
location / {
try_files $uri $uri/ /index.php?$args;
}
# PHP 处理
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
23.4 微服务网关配置¶
http {
# 各微服务 upstream
upstream user_service { server 127.0.0.1:8001; keepalive 8; }
upstream order_service { server 127.0.0.1:8002; keepalive 8; }
upstream product_service { server 127.0.0.1:8003; keepalive 8; }
limit_req_zone $binary_remote_addr zone=global:20m rate=100r/s;
server {
listen 443 ssl http2;
server_name gateway.example.com;
# 全局限流
limit_req zone=global burst=200 nodelay;
# 用户服务
location /api/users/ {
proxy_pass http://user_service/;
include snippets/proxy_params.conf;
}
# 订单服务
location /api/orders/ {
proxy_pass http://order_service/;
include snippets/proxy_params.conf;
}
# 商品服务
location /api/products/ {
proxy_pass http://product_service/;
include snippets/proxy_params.conf;
}
}
}
# /etc/nginx/snippets/proxy_params.conf
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_next_upstream error timeout http_502 http_503;
24. 调试与排障技巧¶
24.1 配置验证¶
# 测试配置语法(不重启)
sudo nginx -t
# 显示完整编译参数(查看已编译的模块)
nginx -V
# 显示配置文件路径
nginx -T # 输出所有配置(含 include 的文件,适合排查 include 问题)
24.2 常用调试命令¶
# 重新生效
nginx -s reload
# 实时跟踪访问日志
tail -f /var/log/nginx/access.log
# 实时跟踪错误日志
tail -f /var/log/nginx/error.log
# 查看指定域名的请求
tail -f /var/log/nginx/access.log | grep "example.com"
# 统计最多访问的 IP(排查攻击)
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 统计响应状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 查看 Nginx 进程
ps aux | grep nginx
# 查看 Nginx 监听端口
ss -tlnp | grep nginx
24.3 开启 debug 日志¶
# 只对特定 IP 开启 debug(避免日志量过大)
error_log /var/log/nginx/debug.log debug;
events {
debug_connection 192.168.1.100; # 只 debug 这个 IP
}
24.4 常见问题速查¶
现象 |
排查方向 |
|---|---|
502 Bad Gateway |
后端服务未启动,或 proxy_read_timeout 太短 |
504 Gateway Timeout |
后端响应慢,增大 proxy_read_timeout |
413 Request Entity Too Large |
client_max_body_size 设置过小 |
403 Forbidden |
文件权限不对(需 www-data 可读),或 deny all 生效 |
499 Client Closed Request |
客户端主动断开,后端响应太慢 |
location 不生效 |
检查匹配优先级,用 nginx -T 确认最终配置 |
upstream 无法连接 |
确认后端端口和防火墙规则,检查 SELinux |
SSL 握手失败 |
证书链不完整,或 TLS 版本不兼容 |
24.5 性能分析¶
# 查看 stub_status(需开启 stub_status 模块)
location = /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
# 输出示例:
# Active connections: 43
# server accepts handled requests
# 1000 1000 5000
# Reading: 1 Writing: 2 Waiting: 40
# 使用 ab 压测
ab -n 10000 -c 100 http://localhost/
# 使用 wrk 压测
wrk -t4 -c100 -d30s http://localhost/
最后更新:2025 年 | Nginx 版本:1.24 / 1.25(Mainline)