- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. nginx 架构与配置结构
- 2. Virtual Host / Server Block 配置
- 3. 反向代理配置
- 4. 负载均衡
- 5. SSL/TLS 配置
- 6. 缓存配置
- 7. Rate Limiting 与 Connection Limiting
- 8. Gzip/Brotli 压缩
- 9. 安全响应头
- 10. 访问控制 (Access Control)
- 11. 日志配置
- 12. 性能调优
- 13. URL Rewriting 与 Redirection
- 14. 静态文件服务优化
- 15. 健康检查与监控
- 生产环境配置综合检查清单
- 参考资料
1. nginx 架构与配置结构
1.1 事件驱动架构:Master-Worker 模型
nginx 采用了与 Apache httpd 的进程/线程模型根本不同的事件驱动(Event-Driven)架构。这一设计哲学正是 nginx 能在单台服务器上处理数十万个并发连接的核心原因。
┌─────────────────────────────────────────────────────────┐
│ Master Process │
│ - 读取并校验配置文件 │
│ - 创建/管理 Worker 进程 (fork) │
│ - 端口绑定 (80, 443) │
│ - 信号处理 (reload, stop, reopen) │
└─────────┬───────────┬───────────┬───────────┬───────────┘
│ │ │ │
┌─────▼─────┐ ┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│ Worker 0 │ │Worker 1│ │Worker 2│ │Worker 3│
│ Event Loop │ │ ... │ │ ... │ │ ... │
│ epoll/kq │ │ │ │ │ │ │
│ 数千 conn │ │ │ │ │ │ │
└───────────┘ └────────┘ └────────┘ └────────┘
Master Process 以 root 权限运行,负责解析配置文件、绑定端口和管理 Worker 进程。它通过 fork() 系统调用创建 Worker,重载配置时不会中断已有连接,而是先启动新的 Worker,再对旧 Worker 执行 graceful shutdown。
Worker Process 是实际处理客户端请求的核心单元。每个 Worker 运行独立的事件循环,利用操作系统的 I/O 多路复用机制(Linux 上是 epoll,FreeBSD/macOS 上是 kqueue)在不阻塞的情况下同时处理数千个连接。相比为每个连接分配一个线程的方式,上下文切换和内存开销大幅降低。
1.2 nginx.conf 的配置上下文结构
nginx 配置遵循分层的上下文(Context)结构。子上下文会继承父级的配置,若在子级重新声明相同指令则会覆盖父级。
# ============================================
# Main Context (全局配置)
# ============================================
user nginx; # 运行 Worker 进程的用户
worker_processes auto; # 按 CPU 核心数创建 Worker
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
# ============================================
# Events Context (连接处理配置)
# ============================================
events {
worker_connections 1024; # 每个 Worker 的最大并发连接数
multi_accept on; # 一次接受多个连接
use epoll; # Linux 上使用 epoll (默认值)
}
# ============================================
# HTTP Context (HTTP 协议配置)
# ============================================
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# ========================================
# Server Context (虚拟主机)
# ========================================
server {
listen 80;
server_name example.com;
# ====================================
# Location Context (URL 路径匹配)
# ====================================
location / {
root /var/www/html;
index index.html;
}
location /api/ {
proxy_pass http://backend;
}
}
}
# ============================================
# Stream Context (TCP/UDP 代理, L4)
# ============================================
stream {
server {
listen 3306;
proxy_pass mysql_backend;
}
}
上下文层级小结:
| 上下文 | 位置 | 作用 |
|---|---|---|
| Main | 最顶层 | 全局配置 (user, worker, pid, error_log) |
| Events | Main 内部 | 连接处理机制 (worker_connections) |
| HTTP | Main 内部 | HTTP 协议相关的全部配置 |
| Server | HTTP 内部 | 虚拟主机(按域名配置) |
| Location | Server 内部 | 按 URL 路径的请求处理规则 |
| Upstream | HTTP 内部 | 后端服务器组(负载均衡) |
| Stream | Main 内部 | TCP/UDP L4 代理 |
1.3 配置文件结构化的最佳实践
在生产环境中,不要把所有配置塞进单个 nginx.conf,而应模块化管理。
/etc/nginx/
├── nginx.conf # 主配置 (用 include 拆分)
├── conf.d/ # 公共配置片段
│ ├── ssl-params.conf # SSL/TLS 公共参数
│ ├── proxy-params.conf # 反向代理公共请求头
│ ├── security-headers.conf # 安全响应头
│ └── gzip.conf # 压缩配置
├── sites-available/ # 按站点划分的配置文件
│ ├── example.com.conf
│ ├── api.example.com.conf
│ └── admin.example.com.conf
├── sites-enabled/ # 已启用的站点 (符号链接)
│ ├── example.com.conf -> ../sites-available/example.com.conf
│ └── api.example.com.conf -> ../sites-available/api.example.com.conf
└── snippets/ # 可复用的配置片段
├── letsencrypt.conf
└── fastcgi-php.conf
# nginx.conf 主文件
http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*.conf;
}
2. Virtual Host / Server Block 配置
nginx 的 Server Block 相当于 Apache 的 Virtual Host,让一台服务器可以托管多个域名。
2.1 基本 Server Block 配置
# /etc/nginx/sites-available/example.com.conf
# ── 主域名 ──
server {
listen 80;
listen [::]:80; # IPv6 支持
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
# 按域名拆分访问日志
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ =404;
}
}
# ── 第二个域名 ──
server {
listen 80;
listen [::]:80;
server_name blog.example.com;
root /var/www/blog.example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
2.2 Default Server (catch-all)
这是处理未定义域名请求的默认 server 块。出于安全考虑,推荐用 444(直接断开连接)响应。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _; # 所有未匹配的域名
# 未定义主机的请求立即断开连接
return 444;
}
2.3 Server Name 匹配优先级
nginx 匹配 server_name 时遵循以下优先级:
- 精确名称:
server_name example.com - 前置通配符:
server_name *.example.com - 后置通配符:
server_name example.* - 正则表达式:
server_name ~^(?<subdomain>.+)\.example\.com$ - default_server:以上全部未匹配时
# 用正则表达式捕获子域名
server {
listen 80;
server_name ~^(?<subdomain>.+)\.example\.com$;
location / {
root /var/www/$subdomain;
}
}
2.4 站点的启用与停用
# 启用站点
sudo ln -s /etc/nginx/sites-available/example.com.conf \
/etc/nginx/sites-enabled/example.com.conf
# 校验配置
sudo nginx -t
# 重载(不中断服务)
sudo systemctl reload nginx
3. 反向代理配置
3.1 基本 Reverse Proxy
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
# ── 必需的代理请求头 ──
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
}
各请求头的作用:
| 请求头 | 用途 |
|---|---|
Host | 传递原始请求的 Host 头 |
X-Real-IP | 真实客户端 IP(在代理之后识别原始 IP) |
X-Forwarded-For | 经过代理链累积的客户端 IP 列表 |
X-Forwarded-Proto | 原始协议 (http/https) —— 后端据此判断是否重定向 |
X-Forwarded-Host | 原始 Host 头 |
X-Forwarded-Port | 原始端口 |
3.2 可复用的代理参数片段
# /etc/nginx/conf.d/proxy-params.conf
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_http_version 1.1;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
# 在 Server Block 中用 include 复用
location / {
proxy_pass http://backend;
include /etc/nginx/conf.d/proxy-params.conf;
}
3.3 WebSocket 代理
WebSocket 使用 HTTP Upgrade 机制,因此必须显式传递 Upgrade 和 Connection 这两个逐跳(hop-by-hop)头。nginx 默认不会转发这些头。
# ── 用 map 动态设置 Connection 头 ──
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name ws.example.com;
location /ws/ {
proxy_pass http://127.0.0.1:8080;
# WebSocket 必需配置
proxy_http_version 1.1; # 必须用 HTTP/1.1 (支持 Upgrade)
proxy_set_header Upgrade $http_upgrade; # 传递客户端的 Upgrade 头
proxy_set_header Connection $connection_upgrade; # 动态 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;
# WebSocket 是长连接,需要延长超时
proxy_read_timeout 86400s; # 24 小时 (默认 60 秒会断开空闲连接)
proxy_send_timeout 86400s;
}
}
3.4 基于路径的路由(微服务)
server {
listen 80;
server_name api.example.com;
# 用户服务
location /api/users/ {
proxy_pass http://user-service:3001/; # 注意结尾的 /: 去掉 /api/users/ 后再转发
include /etc/nginx/conf.d/proxy-params.conf;
}
# 订单服务
location /api/orders/ {
proxy_pass http://order-service:3002/;
include /etc/nginx/conf.d/proxy-params.conf;
}
# 支付服务
location /api/payments/ {
proxy_pass http://payment-service:3003/;
include /etc/nginx/conf.d/proxy-params.conf;
proxy_read_timeout 120s; # 支付需要延长超时
}
}
注意:
proxy_passURL 结尾若带/,location匹配到的部分会被去掉。/api/users/123请求会转发为http://user-service:3001/123。若不带/,则原样转发完整 URI。
4. 负载均衡
4.1 Upstream 块与算法
# ============================================
# 1. Round Robin (默认值)
# 按顺序分发请求
# ============================================
upstream backend_roundrobin {
server 10.0.0.1:8080; # 默认权重 1
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
# ============================================
# 2. Weighted Round Robin (加权轮询)
# 按服务器性能比例分发
# ============================================
upstream backend_weighted {
server 10.0.0.1:8080 weight=5; # 请求的 5/8
server 10.0.0.2:8080 weight=2; # 请求的 2/8
server 10.0.0.3:8080 weight=1; # 请求的 1/8
}
# ============================================
# 3. Least Connections (最少连接)
# 转发到活跃连接最少的服务器
# ============================================
upstream backend_leastconn {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
# ============================================
# 4. IP Hash (会话保持)
# 相同客户端 IP → 相同服务器
# ============================================
upstream backend_iphash {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
# ============================================
# 5. Generic Hash (自定义哈希)
# 基于任意变量的哈希
# ============================================
upstream backend_hash {
hash $request_uri consistent; # 基于 URI + 一致性哈希
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
算法选择指南:
| 算法 | 适用场景 | 注意事项 |
|---|---|---|
| Round Robin | 无状态服务、配置相同的服务器 | 服务器配置有差异时会失衡 |
| Weighted | 服务器配置不同的情况 | 需要手动维护权重 |
| Least Connections | 请求处理时间波动大的情况 | 若以短请求为主则与 Round Robin 相近 |
| IP Hash | 需要会话保持的情况(遗留应用) | 增减服务器时会发生重新分配 |
| Generic Hash | 缓存优化(相同 URI → 相同服务器) | 推荐使用 consistent 哈希 |
4.2 服务器状态与备份
upstream backend {
least_conn;
server 10.0.0.1:8080; # 正常服务器
server 10.0.0.2:8080; # 正常服务器
server 10.0.0.3:8080 backup; # 备份: 上面服务器全部宕机时启用
server 10.0.0.4:8080 down; # 停用 (维护中)
server 10.0.0.5:8080 max_fails=3 fail_timeout=30s;
# max_fails=3: 30 秒内失败 3 次判定为异常
# fail_timeout=30s: 判定异常后 30 秒内不再分配请求
}
4.3 Keepalive 连接池
复用与后端服务器之间的 TCP 连接,降低连接建立/释放的开销。
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
keepalive 32; # 每个 Worker 保持的空闲连接数
keepalive_requests 1000; # 单个连接可处理的最大请求数
keepalive_timeout 60s; # 空闲连接的保持时间
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1; # keepalive 必须用 HTTP/1.1
proxy_set_header Connection ""; # 用空值代替 "close" 以启用 keepalive
}
}
5. SSL/TLS 配置
5.1 基本 HTTPS 配置
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;
# ── 协议 ──
ssl_protocols TLSv1.2 TLSv1.3; # 停用 TLS 1.0, 1.1
# ── Cipher Suites (用于 TLS 1.2) ──
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 下推荐 off
# ── Elliptic Curves ──
ssl_ecdh_curve X25519:secp384r1:secp256r1;
# ── 会话复用 ──
ssl_session_cache shared:SSL:10m; # 10MB = 约 40,000 个会话
ssl_session_timeout 1d; # 会话有效期
ssl_session_tickets off; # 保证 Forward Secrecy
root /var/www/example.com/html;
index index.html;
}
5.2 HTTP → HTTPS 重定向
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 所有 HTTP 请求 301 重定向到 HTTPS
return 301 https://$host$request_uri;
}
5.3 HSTS (HTTP Strict Transport Security)
# 添加到 HTTPS server block 内部
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
max-age=63072000:2 年内只使用 HTTPS(建议至少 1 年)includeSubDomains:对所有子域名同样生效preload:具备登记到浏览器 HSTS Preload 列表的资格always:即使是错误响应(4xx、5xx)也发送该头
5.4 OCSP Stapling
OCSP Stapling 由服务器代为完成证书有效性校验,省去客户端直接查询 CA 的过程。既提升了初次连接速度,也保护了隐私。
ssl_stapling on;
ssl_stapling_verify on;
# 用于校验 OCSP 响应的信任链 (包含 Let's Encrypt 中间证书)
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# 用于查询 OCSP 响应服务器的 DNS resolver
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
5.5 生产环境 SSL 整合片段
# /etc/nginx/conf.d/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
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;
ssl_ecdh_curve X25519:secp384r1:secp256r1;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 在 Server Block 中 include
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/conf.d/ssl-params.conf;
# ... 其余配置
}
5.6 Let's Encrypt 自动续期 (Certbot)
# 签发证书
sudo certbot --nginx -d example.com -d www.example.com
# 测试自动续期
sudo certbot renew --dry-run
# Cron 自动续期 (certbot 通常已自行配置,此处显式写出)
echo "0 0,12 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx'" \
| sudo tee /etc/cron.d/certbot-renew
6. 缓存配置
6.1 Proxy Cache(反向代理缓存)
# ── 在 HTTP Context 中定义缓存路径 ──
proxy_cache_path /var/cache/nginx/proxy
levels=1:2 # 两级目录结构 (分散文件)
keys_zone=proxy_cache:10m # 存放缓存键的共享内存 (1MB ≈ 8,000 个键)
max_size=1g # 磁盘缓存最大容量
inactive=60m # 60 分钟未使用的缓存会被删除
use_temp_path=off; # 不使用临时文件路径 (直接写入 → 提升性能)
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend;
proxy_cache proxy_cache; # 指定缓存区
proxy_cache_valid 200 302 10m; # 200, 302 响应缓存 10 分钟
proxy_cache_valid 404 1m; # 404 响应缓存 1 分钟
proxy_cache_use_stale error timeout
updating
http_500 http_502
http_503 http_504; # 后端出错时提供 stale 缓存
proxy_cache_lock on; # 并发请求时只放行一个到后端
proxy_cache_min_uses 2; # 只缓存被请求 2 次以上的 URL
# 用于调试的缓存状态响应头
add_header X-Cache-Status $upstream_cache_status;
}
# 绕过缓存 (管理员用)
location /api/ {
proxy_pass http://backend;
proxy_cache proxy_cache;
# Cookie 中含 nocache,或请求头带 Cache-Control: no-cache 时绕过
proxy_cache_bypass $http_cache_control;
proxy_no_cache $cookie_nocache;
}
}
X-Cache-Status 的取值:
| 状态 | 含义 |
|---|---|
HIT | 直接由缓存提供 |
MISS | 无缓存 → 请求后端 |
EXPIRED | 缓存已过期 → 重新请求后端 |
STALE | 已过期但按 stale 策略提供 |
UPDATING | 更新过程中提供 stale 缓存 |
BYPASS | 已绕过缓存 |
6.2 FastCGI Cache(PHP 等)
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=fastcgi_cache:10m
max_size=512m
inactive=30m;
server {
listen 80;
server_name wordpress.example.com;
# 定义绕过缓存的条件
set $skip_cache 0;
# POST 请求不缓存
if ($request_method = POST) {
set $skip_cache 1;
}
# 带查询字符串时不缓存
if ($query_string != "") {
set $skip_cache 1;
}
# 排除 WordPress 管理页面
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php") {
set $skip_cache 1;
}
# 排除已登录用户
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_cache fastcgi_cache;
fastcgi_cache_valid 200 30m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_use_stale error timeout updating http_500;
add_header X-FastCGI-Cache $upstream_cache_status;
}
}
6.3 浏览器缓存(静态资源)
# ── 对静态文件设置长期浏览器缓存 ──
location ~* \.(jpg|jpeg|png|gif|ico|webp|avif|svg)$ {
expires 30d; # 设置 Expires 头
add_header Cache-Control "public, immutable"; # 浏览器无需重新验证即可使用缓存
access_log off; # 关闭静态文件日志 (减少 I/O)
}
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public";
}
location ~* \.(woff|woff2|ttf|eot)$ {
expires 365d;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin "*"; # 字体 CORS
}
# ── HTML 使用短缓存或 no-cache ──
location ~* \.html$ {
expires -1; # no-cache
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
7. Rate Limiting 与 Connection Limiting
7.1 Rate Limiting(请求速率限制)
nginx 的 Rate Limiting 使用漏桶(Leaky Bucket)算法。请求进入桶(zone),并按设定的速率(rate)被处理。
# ── 在 HTTP Context 中定义 Zone ──
# 键: 客户端 IP
# 共享内存: 10MB (约可存 160,000 个 IP 地址)
# 速率: 每秒 10 个请求
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# 登录端点: 每秒 1 个 (防止 Brute Force)
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
# API 端点: 每秒 50 个
limit_req_zone $binary_remote_addr zone=api:10m rate=50r/s;
# 超出 Rate Limit 时的日志级别
limit_req_status 429; # 用 429 Too Many Requests 代替默认的 503
limit_req_log_level warn;
server {
listen 80;
server_name example.com;
# ── 普通页面 ──
location / {
limit_req zone=general burst=20 nodelay;
# burst=20: 瞬时最多允许超出 20 个
# nodelay: burst 范围内的请求不延迟,立即处理
proxy_pass http://backend;
}
# ── 登录页面 ──
location /login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://backend;
}
# ── API ──
location /api/ {
limit_req zone=api burst=100 nodelay;
proxy_pass http://backend;
}
}
burst 与 nodelay 的工作原理:
Rate: 10r/s, Burst: 20
时刻 0 到达 30 个请求:
├── 10 个: 立即处理 (rate 范围内)
├── 20 个: 存入 burst 队列
│ 无 nodelay 时: 以 100ms 间隔处理 (共 2 秒)
│ 有 nodelay 时: 立即处理 (仅占用队列槽位)
└── 其余: 429 拒绝
7.2 Connection Limiting(并发连接限制)
# 限制每个客户端 IP 的并发连接数
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
# 限制整台服务器的并发连接数
limit_conn_zone $server_name zone=conn_per_server:10m;
limit_conn_status 429;
limit_conn_log_level warn;
server {
listen 80;
server_name example.com;
# 每个 IP 最多 100 个并发连接
limit_conn conn_per_ip 100;
# 每台服务器最多 10,000 个并发连接
limit_conn conn_per_server 10000;
# 下载带宽限制 (可选)
location /downloads/ {
limit_conn conn_per_ip 5; # 下载按 IP 限制为 5 个
limit_rate 500k; # 每个连接限速 500KB/s
limit_rate_after 10m; # 前 10MB 不限速,之后开始限速
}
}
7.3 IP 白名单与 Rate Limiting 结合
# 内网免除 Rate Limiting
geo $limit {
default 1;
10.0.0.0/8 0; # 内网
192.168.0.0/16 0; # 内网
172.16.0.0/12 0; # 内网
}
map $limit $limit_key {
0 ""; # 空键 → 不应用 Rate Limiting
1 $binary_remote_addr; # 外部 IP → 应用 Rate Limiting
}
limit_req_zone $limit_key zone=api:10m rate=10r/s;
8. Gzip/Brotli 压缩
8.1 Gzip 压缩配置
# /etc/nginx/conf.d/gzip.conf
gzip on;
gzip_vary on; # 添加 Vary: Accept-Encoding 头
gzip_proxied any; # 代理响应也压缩
gzip_comp_level 6; # 压缩级别 (1-9, 6 是性能/压缩率的平衡点)
gzip_min_length 1000; # 小于 1KB 的文件压缩无效 → 排除
gzip_buffers 16 8k; # 压缩缓冲区
gzip_types
text/plain
text/css
text/javascript
text/xml
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/vnd.ms-fontobject
font/opentype
font/ttf
image/svg+xml
image/x-icon;
# 排除已压缩的文件 (图片、视频等不列入 gzip_types)
gzip_disable "msie6"; # 对 IE6 停用 (遗留)
8.2 Brotli 压缩配置
Brotli 比 Gzip 提供高出 15-25% 的压缩率。绝大多数现代浏览器都支持,在 nginx 中需要 ngx_brotli 模块。
# Brotli 动态压缩
brotli on;
brotli_comp_level 6; # 动态压缩推荐 6 (11 会让 CPU 过载)
brotli_min_length 1000;
brotli_types
text/plain
text/css
text/javascript
text/xml
application/javascript
application/json
application/xml
application/rss+xml
font/opentype
font/ttf
image/svg+xml;
# Brotli 静态压缩 (提供预先压缩好的 .br 文件)
brotli_static on;
8.3 Dual Compression 策略
对支持 Brotli 的浏览器用 Brotli,对不支持的浏览器回退到 Gzip。
# 构建时预压缩静态文件 (CI/CD 流水线)
# gzip -k -9 dist/**/*.{js,css,html,json,svg}
# brotli -k -q 11 dist/**/*.{js,css,html,json,svg}
# nginx 配置
brotli_static on; # 存在 .br 文件时优先提供
gzip_static on; # 存在 .gz 文件时提供 (不支持 Brotli 时)
gzip on; # 没有预压缩文件时动态 gzip
压缩性能对比:
| 算法 | 压缩率 (普通 JS) | CPU 负载 (动态) | 浏览器支持 |
|---|---|---|---|
| Gzip L6 | 70-75% | 低 | 99%+ |
| Brotli L6 | 75-80% | 中 | 96%+ |
| Brotli L11 | 80-85% | 高 (仅限静态) | 96%+ |
9. 安全响应头
9.1 综合安全响应头配置
# /etc/nginx/conf.d/security-headers.conf
# ── 防止 Clickjacking ──
add_header X-Frame-Options "DENY" always;
# DENY: 任何站点都不能用 iframe 嵌入
# SAMEORIGIN: 仅同域名允许 iframe
# 参考: CSP frame-ancestors 是更现代的替代方案
# ── 防止 MIME 类型嗅探 ──
add_header X-Content-Type-Options "nosniff" always;
# 防止浏览器忽略 Content-Type 而自行判断
# ── XSS 过滤器 (遗留, 现代浏览器使用 CSP) ──
add_header X-XSS-Protection "0" always;
# 最新建议: "0" (停用) —— CSP 更安全也更准确
# ── 控制 Referrer 信息 ──
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 同域名: 发送完整 URL
# 不同域名: 只发送 origin(域名)
# HTTP→HTTPS 降级: 不发送
# ── 权限策略 (控制摄像头、麦克风、定位等) ──
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
# 停用所有功能 (只放行需要的)
# ── HSTS ──
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# ── Cross-Origin 策略 ──
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
9.2 Content Security Policy (CSP)
CSP 是最强大的安全响应头,但配置复杂。推荐先以 Report-Only 模式起步,监控违规情况后再逐步启用。
# ── 第 1 阶段: Report-Only 模式 (不拦截,仅上报违规) ──
add_header Content-Security-Policy-Report-Only
"default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
report-uri /csp-report;" always;
# ── 第 2 阶段: 正式启用 (违规时拦截) ──
add_header Content-Security-Policy
"default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';" always;
9.3 在 Server Block 中统一应用
server {
listen 443 ssl http2;
server_name example.com;
include /etc/nginx/conf.d/ssl-params.conf;
include /etc/nginx/conf.d/security-headers.conf;
# 安全相关的补充配置
server_tokens off; # 隐藏 nginx 版本信息
more_clear_headers Server; # 移除 Server 头 (headers-more 模块)
# ...
}
10. 访问控制 (Access Control)
10.1 基于 IP 的访问控制
# ── 管理页面: 仅允许特定 IP ──
location /admin/ {
allow 10.0.0.0/8; # 内网
allow 203.0.113.50; # 特定管理员 IP
deny all; # 其余全部拒绝
proxy_pass http://backend;
}
# ── 屏蔽特定 IP ──
location / {
deny 192.168.1.100; # 屏蔽特定 IP
deny 10.0.0.0/24; # 屏蔽子网
allow all; # 其余放行
# 注意: allow/deny 的顺序很重要! 先匹配到的规则生效
proxy_pass http://backend;
}
10.2 HTTP Basic Authentication
# 创建 htpasswd 文件
sudo apt install apache2-utils # Debian/Ubuntu
# sudo yum install httpd-tools # RHEL/CentOS
# 创建用户 (-c: 新建文件, -B: bcrypt 哈希)
sudo htpasswd -cB /etc/nginx/.htpasswd admin
# 追加用户
sudo htpasswd -B /etc/nginx/.htpasswd developer
# ── 对特定路径启用 Basic Auth ──
location /admin/ {
auth_basic "Administrator Area"; # 认证提示信息
auth_basic_user_file /etc/nginx/.htpasswd; # 密码文件
proxy_pass http://backend;
}
# ── 仅对特定路径免除认证 ──
location /admin/health {
auth_basic off; # 健康检查免除认证
proxy_pass http://backend;
}
10.3 IP + Auth 组合(satisfy 指令)
location /admin/ {
# satisfy any → IP 放行 OR 认证成功,满足其一即可访问
# satisfy all → IP 放行 AND 认证成功,两者都满足才能访问
satisfy any;
# IP 白名单
allow 10.0.0.0/8;
deny all;
# Basic Auth (从 IP 白名单之外访问时)
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://backend;
}
10.4 基于 GeoIP 的访问控制
# 需要 GeoIP2 模块 (ngx_http_geoip2_module)
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
auto_reload 60m;
$geoip2_data_country_code country iso_code;
}
# 屏蔽特定国家
map $geoip2_data_country_code $allowed_country {
default yes;
CN no; # 中国
RU no; # 俄罗斯
}
server {
if ($allowed_country = no) {
return 403;
}
}
11. 日志配置
11.1 基本日志配置
# ── Access Log ──
# 默认 log_format: combined
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log combined;
# ── Error Log ──
# 级别: debug, info, notice, warn, error, crit, alert, emerg
error_log /var/log/nginx/error.log warn;
11.2 JSON 日志格式(对接日志分析工具)
JSON 形式的结构化日志,对于对接 Elasticsearch、Datadog、Splunk 这类分析工具是必不可少的。
log_format json_combined escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request_method":"$request_method",'
'"request_uri":"$request_uri",'
'"server_protocol":"$server_protocol",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for",'
'"upstream_addr":"$upstream_addr",'
'"upstream_status":"$upstream_status",'
'"upstream_response_time":"$upstream_response_time",'
'"ssl_protocol":"$ssl_protocol",'
'"ssl_cipher":"$ssl_cipher",'
'"request_id":"$request_id"'
'}';
access_log /var/log/nginx/access.json.log json_combined;
11.3 条件日志
# ── 排除健康检查请求的日志 ──
map $request_uri $loggable {
~*^/health 0;
~*^/ready 0;
~*^/metrics 0;
default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;
# ── 只把出错请求单独记录 ──
map $status $is_error {
~^[45] 1;
default 0;
}
access_log /var/log/nginx/error_requests.log combined if=$is_error;
# ── 记录慢请求 (1 秒以上) ──
map $request_time $is_slow {
~^[1-9] 1; # 1 秒以上
~^[0-9]{2} 1; # 10 秒以上
default 0;
}
access_log /var/log/nginx/slow_requests.log json_combined if=$is_slow;
11.4 按域名拆分日志
server {
server_name example.com;
access_log /var/log/nginx/example.com.access.log json_combined;
error_log /var/log/nginx/example.com.error.log warn;
}
server {
server_name api.example.com;
access_log /var/log/nginx/api.example.com.access.log json_combined;
error_log /var/log/nginx/api.example.com.error.log warn;
}
11.5 日志轮转 (logrotate)
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每天轮转
missingok # 日志文件不存在也不报错
rotate 14 # 保留 14 天
compress # gzip 压缩
delaycompress # 上一个文件暂不压缩
notifempty # 空文件不轮转
create 0640 nginx adm # 新文件权限
sharedscripts
postrotate
# 向 nginx 发送重新打开日志文件的信号
if [ -f /run/nginx.pid ]; then
kill -USR1 $(cat /run/nginx.pid)
fi
endscript
}
12. 性能调优
12.1 Worker 进程与连接
# ── Main Context ──
worker_processes auto; # 按 CPU 核心数 (手动: 4, 8 等)
worker_rlimit_nofile 65535; # 每个 Worker 的最大文件描述符数
events {
worker_connections 4096; # 每个 Worker 的最大并发连接数
multi_accept on; # 在一次事件循环中接受多个连接
use epoll; # Linux: epoll (默认值)
}
最大并发连接数公式:
最大连接数 = worker_processes x worker_connections
例: 4 workers x 4096 connections = 16,384 个并发连接
作为反向代理时 (客户端 + 后端共 2 个连接):
实际并发客户端 = 16,384 / 2 = 8,192
12.2 Keepalive 配置
http {
# ── 客户端 Keepalive ──
keepalive_timeout 65; # 客户端 keepalive 保持时间 (秒)
keepalive_requests 1000; # 单个 keepalive 连接可处理的最大请求数
# ── 超时 ──
client_body_timeout 12; # 接收客户端请求体的超时
client_header_timeout 12; # 接收客户端请求头的超时
send_timeout 10; # 向客户端发送响应的超时
reset_timedout_connection on; # 超时连接立即重置 (释放内存)
}
12.3 缓冲区配置
http {
# ── 客户端请求缓冲区 ──
client_body_buffer_size 16k; # 请求体缓冲区 (超出则写入磁盘)
client_header_buffer_size 1k; # 请求头缓冲区
client_max_body_size 100m; # 最大上传大小 (默认 1MB)
large_client_header_buffers 4 16k; # 大请求头用的缓冲区
# ── 代理缓冲区 ──
proxy_buffers 16 32k; # 存放后端响应的缓冲区
proxy_buffer_size 16k; # 第一段响应 (响应头) 缓冲区
proxy_busy_buffers_size 64k; # 正在发往客户端的缓冲区大小
proxy_temp_file_write_size 64k; # 写入磁盘的临时文件大小
}
12.4 生产环境性能调优汇总
# /etc/nginx/nginx.conf —— 生产环境优化
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
# ── MIME 与基础配置 ──
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8;
server_tokens off; # 隐藏版本信息
# ── 文件传输优化 ──
sendfile on; # 内核级文件传输
tcp_nopush on; # 与 sendfile 配合: 优化数据包
tcp_nodelay on; # 停用 Nagle 算法
aio on; # 异步 I/O
# ── Keepalive ──
keepalive_timeout 65;
keepalive_requests 1000;
# ── 超时 ──
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;
reset_timedout_connection on;
# ── 缓冲区 ──
client_body_buffer_size 16k;
client_header_buffer_size 1k;
client_max_body_size 100m;
large_client_header_buffers 4 16k;
# ── Open File Cache ──
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# ── 压缩、SSL、日志等的 include ──
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*.conf;
}
13. URL Rewriting 与 Redirection
13.1 return 指令(推荐)
return 比 rewrite 更简单也更高效。大多数需要变更 URL 的场景,都应优先考虑 return。
# ── HTTP → HTTPS 重定向 ──
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# ── www → non-www 归一化 ──
server {
listen 443 ssl http2;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
# ── 域名变更重定向 ──
server {
listen 80;
listen 443 ssl http2;
server_name old-domain.com www.old-domain.com;
return 301 https://new-domain.com$request_uri;
}
# ── 特定路径重定向 ──
location /old-page {
return 301 /new-page;
}
# ── 维护模式 ──
location / {
return 503; # Service Unavailable
}
# 与 error_page 组合
error_page 503 /maintenance.html;
location = /maintenance.html {
root /var/www/html;
internal;
}
13.2 rewrite 指令
rewrite 用于需要基于正则表达式做 URL 转换的场景。
# ── 基本语法 ──
# rewrite regex replacement [flag];
# flag: last | break | redirect (302) | permanent (301)
# ── 转换为不带版本号的 API 路径 ──
rewrite ^/api/v1/(.*)$ /api/$1 last;
# /api/v1/users → 内部重写为 /api/users
# last: 重新开始 location 匹配
# ── 去掉扩展名 (Clean URL) ──
rewrite ^/(.*)\.html$ /$1 permanent;
# /about.html → /about (301 重定向)
# ── 带查询字符串的重写 ──
rewrite ^/search/(.*)$ /search?q=$1? last;
# 在结尾加 ? 可去掉原有的查询字符串
# ── 多语言 URL ──
rewrite ^/ko/(.*)$ /$1?lang=ko last;
rewrite ^/en/(.*)$ /$1?lang=en last;
rewrite ^/ja/(.*)$ /$1?lang=ja last;
rewrite 标志对比:
| 标志 | 行为 | 用途 |
|---|---|---|
last | 重写后重新匹配 location | 变更内部路由 |
break | 重写后在当前 location 内继续处理 | 当前块内的转换 |
redirect | 302 临时重定向 | 临时迁移 |
permanent | 301 永久重定向 | 永久迁移 |
13.3 try_files 指令
try_files 会按顺序检查文件/目录是否存在,在 SPA 或各类框架中不可或缺。
# ── SPA (React、Vue、Angular 等) ──
location / {
root /var/www/spa;
try_files $uri $uri/ /index.html;
# 1. $uri: 检查请求的文件是否存在
# 2. $uri/: 检查目录是否存在
# 3. /index.html: 以上都没有则返回 index.html (SPA 路由)
}
# ── Next.js / Nuxt.js ──
location / {
try_files $uri $uri/ @proxy;
}
location @proxy {
proxy_pass http://127.0.0.1:3000;
include /etc/nginx/conf.d/proxy-params.conf;
}
# ── PHP (WordPress、Laravel) ──
location / {
try_files $uri $uri/ /index.php?$args;
}
# ── 静态文件优先 → 回退到后端 ──
location / {
root /var/www/static;
try_files $uri @backend;
}
location @backend {
proxy_pass http://app_server;
}
13.4 条件重定向
# ── 移动设备重定向 ──
if ($http_user_agent ~* "(Android|iPhone|iPad)") {
return 302 https://m.example.com$request_uri;
}
# ── 基于特定查询参数 ──
if ($arg_redirect) {
return 302 $arg_redirect;
}
# ── 用 map 管理复杂的重定向 ──
map $request_uri $redirect_uri {
/old-blog/post-1 /blog/new-post-1;
/old-blog/post-2 /blog/new-post-2;
/products/legacy /shop/all;
default "";
}
server {
if ($redirect_uri) {
return 301 $redirect_uri;
}
}
14. 静态文件服务优化
14.1 核心文件传输指令
http {
# ── sendfile ──
# 使用内核的 sendfile() 系统调用把文件直接发送到 socket
# 消除用户态内存拷贝,降低 CPU 使用率和上下文切换
sendfile on;
# ── tcp_nopush ──
# 与 sendfile 协同工作: 把 HTTP 头和文件开头放进同一个数据包发送
# 减少网络包数量,提升带宽效率
tcp_nopush on;
# ── tcp_nodelay ──
# 停用 Nagle 算法: 小数据包立即发送
# 降低 keepalive 连接上的延迟 (可与 tcp_nopush 同时使用)
tcp_nodelay on;
}
传输方式对比:
sendfile off (默认):
磁盘 → 内核缓冲区 → 用户态内存 (nginx) → 内核 socket 缓冲区 → 网络
[读取] [拷贝] [写入]
sendfile on:
磁盘 → 内核缓冲区 ─────────────────────────→ 内核 socket 缓冲区 → 网络
[读取] [零拷贝: 无需 CPU 介入] [发送]
14.2 Open File Cache
缓存被反复请求的文件的描述符、大小和修改时间,把文件系统查询降到最低。
http {
# 最多缓存 10,000 个文件信息, 30 秒未使用则移除
open_file_cache max=10000 inactive=30s;
# 每 60 秒重新校验一次已缓存的信息
open_file_cache_valid 60s;
# 只缓存被请求 2 次以上的文件 (过滤一次性请求)
open_file_cache_min_uses 2;
# 文件不存在(ENOENT)的错误也缓存 (避免反复查询不存在的文件)
open_file_cache_errors on;
}
14.3 静态文件服务综合配置
server {
listen 443 ssl http2;
server_name static.example.com;
root /var/www/static;
# ── 图片 ──
location ~* \.(jpg|jpeg|png|gif|ico|webp|avif|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
access_log off;
log_not_found off; # 404 日志也关闭
# 图片专用限制
limit_rate 2m; # 每个连接 2MB/s
}
# ── CSS/JS (配合缓存失效策略) ──
location ~* \.(css|js)$ {
expires 365d; # 文件名带哈希时可长期缓存
add_header Cache-Control "public, immutable";
gzip_static on;
brotli_static on;
}
# ── 字体 ──
location ~* \.(woff|woff2|ttf|eot|otf)$ {
expires 365d;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin "*";
}
# ── 媒体文件 ──
location ~* \.(mp4|webm|ogg|mp3|wav)$ {
expires 30d;
add_header Cache-Control "public";
# 支持 Range 请求 (视频拖动)
add_header Accept-Ranges bytes;
}
# ── 禁止目录列表 ──
location / {
autoindex off;
}
# ── 阻止访问隐藏文件 ──
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
14.4 HTTP/2 Server Push(可选)
# 在客户端请求之前预先推送关键资源
location = /index.html {
http2_push /css/main.css;
http2_push /js/app.js;
http2_push /images/logo.webp;
}
参考:HTTP/2 Server Push 已在部分浏览器中停止支持,
103 Early Hints正成为其替代方案。
15. 健康检查与监控
15.1 Stub Status(基础监控)
用 nginx OSS 自带的 stub_status 模块可以查看实时连接状态。
server {
listen 8080; # 用独立端口隔离
server_name localhost;
# 只允许内网访问
allow 10.0.0.0/8;
allow 127.0.0.1;
deny all;
location /nginx_status {
stub_status;
}
location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
}
stub_status 输出示例:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
| 项目 | 含义 |
|---|---|
Active connections | 当前活跃连接数 (Reading + Writing + Waiting) |
accepts | 累计接受的连接数 |
handled | 累计处理的连接数 (等于 accepts 即为正常) |
requests | 累计处理的请求数 |
Reading | 正在读取客户端请求头的连接数 |
Writing | 正在向客户端发送响应的连接数 |
Waiting | keepalive 空闲连接数 |
15.2 被动健康检查(Upstream 监控)
nginx OSS 只支持基于真实流量的被动健康检查。
upstream backend {
server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.3:8080 max_fails=3 fail_timeout=30s backup;
# max_fails=3: 30 秒内连续失败 3 次则判定该服务器异常
# fail_timeout=30s: 判定异常后 30 秒内不再向该服务器发送请求
# 30 秒后重新发送请求确认是否恢复
}
server {
location / {
proxy_pass http://backend;
# 设置哪些响应被判定为"失败"
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_timeout 10s; # 尝试下一台服务器的最长时间
proxy_next_upstream_tries 3; # 最大重试次数
}
}
15.3 主动健康检查(NGINX Plus 或外部方案)
# ── NGINX Plus 中的主动健康检查 ──
upstream backend {
zone backend_zone 64k; # 必须有共享内存区
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}
server {
location / {
proxy_pass http://backend;
health_check interval=5s # 每 5 秒检查一次
fails=3 # 失败 3 次判定异常
passes=2 # 成功 2 次判定恢复
uri=/health; # 健康检查端点
}
}
15.4 Prometheus 集成 (nginx-prometheus-exporter)
# docker-compose.yml
services:
nginx-exporter:
image: nginx/nginx-prometheus-exporter:1.3
command:
- --nginx.scrape-uri=http://nginx:8080/nginx_status
ports:
- '9113:9113'
depends_on:
- nginx
# prometheus.yml
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['nginx-exporter:9113']
15.5 自定义健康检查端点
# ── Liveness Probe (确认 nginx 自身在运行) ──
location = /healthz {
access_log off;
return 200 "alive\n";
add_header Content-Type text/plain;
}
# ── Readiness Probe (含后端连接的确认) ──
location = /readyz {
access_log off;
proxy_pass http://backend/health;
proxy_connect_timeout 2s;
proxy_read_timeout 2s;
# 后端响应失败时返回 503
error_page 502 503 504 = @not_ready;
}
location @not_ready {
return 503 "not ready\n";
add_header Content-Type text/plain;
}
# 在 Kubernetes 中的用法
apiVersion: v1
kind: Pod
spec:
containers:
- name: nginx
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
生产环境配置综合检查清单
这里整理了把 nginx 部署到生产环境时需要确认的核心项目。
| 分类 | 项目 | 状态 |
|---|---|---|
| 架构 | 设置 worker_processes auto | [ ] |
| 架构 | 设置合适的 worker_connections 值 | [ ] |
| SSL/TLS | 仅启用 TLSv1.2 + TLSv1.3 | [ ] |
| SSL/TLS | 配置强 Cipher Suites | [ ] |
| SSL/TLS | 启用 OCSP Stapling | [ ] |
| SSL/TLS | 配置 HSTS 响应头 | [ ] |
| SSL/TLS | HTTP → HTTPS 重定向 | [ ] |
| 安全 | server_tokens off | [ ] |
| 安全 | 配置安全响应头 (CSP、X-Frame-Options 等) | [ ] |
| 安全 | 配置 Rate Limiting | [ ] |
| 安全 | 管理页面的访问控制 | [ ] |
| 性能 | 启用 sendfile、tcp_nopush、tcp_nodelay | [ ] |
| 性能 | 配置 Gzip/Brotli 压缩 | [ ] |
| 性能 | 配置 open_file_cache | [ ] |
| 性能 | 配置静态文件的浏览器缓存 | [ ] |
| 性能 | 配置 Upstream keepalive | [ ] |
| 缓存 | 配置 proxy_cache 或 fastcgi_cache | [ ] |
| 缓存 | 配置 proxy_cache_use_stale | [ ] |
| 监控 | 启用 stub_status (仅限内部) | [ ] |
| 监控 | 搭建健康检查端点 | [ ] |
| 日志 | 配置 JSON 日志格式 | [ ] |
| 日志 | 配置日志轮转 | [ ] |
| 日志 | 排除健康检查/静态文件日志 | [ ] |
| 代理 | 配置必需的代理请求头 | [ ] |
| 代理 | 配置 WebSocket 代理 (按需) | [ ] |
| 负载均衡 | 选择合适的算法 | [ ] |
| 负载均衡 | 配置备份服务器 | [ ] |
参考资料
- Nginx Official Documentation
- Nginx Beginner's Guide
- DigitalOcean - Understanding Nginx Configuration File Structure
- Inside NGINX: How We Designed for Performance and Scale
- NGINX Reverse Proxy Guide
- Nginx WebSocket Proxying
- NGINX HTTP Load Balancing
- NGINX TLS 1.3 Hardening Guide
- A Guide to Caching with NGINX
- Rate Limiting with NGINX
- NGINX Gzip Compression Guide
- Tuning NGINX for Performance
- Creating NGINX Rewrite Rules
- NGINX sendfile, tcp_nopush, tcp_nodelay Explained
- NGINX Health Checks
- Mozilla SSL Configuration Generator