Nginx 知识体系 · 下篇:高级与实战
第九章 缓存机制
9.1 浏览器缓存(expires)
# 方式一:expires 指令 location ~* \.(jpg|png|gif|css|js)$ { expires 30d; # 30天过期 } # 方式二:Cache-Control(更灵活,推荐) location ~* \.(css|js)$ { add_header Cache-Control "public, max-age=2592000, immutable"; } # 不缓存动态内容 location /api/ { add_header Cache-Control "no-store, no-cache, must-revalidate"; add_header Pragma "no-cache"; }缓存策略建议:
| 资源类型 | 策略 | 说明 |
|---|---|---|
| HTML | no-cache | 每次验证,保证最新 |
| CSS/JS(带hash) | immutable, max-age=1y | 文件名含hash,永久缓存 |
| 图片/字体 | max-age=30d | 较长缓存 |
| API 响应 | no-store | 禁止缓存 |
9.2 代理缓存(proxy_cache)
http { # 定义缓存区域 proxy_cache_path /var/cache/nginx levels=1:2 # 目录层级 keys_zone=my_cache:10m # 共享内存区域(存key) max_size=10g # 磁盘最大缓存 inactive=60m # 60分钟未访问则清除 use_temp_path=off; # 不使用临时路径 server { location / { proxy_pass http://backend; proxy_cache my_cache; proxy_cache_valid 200 301 302 10m; # 成功响应缓存10分钟 proxy_cache_valid 404 1m; # 404 缓存1分钟 proxy_cache_key "$scheme$host$request_uri"; # 添加缓存状态头(调试用) add_header X-Cache-Status $upstream_cache_status; # 值:HIT / MISS / EXPIRED / BYPASS / STALE } } }9.3 缓存控制策略
# 指定条件绕过缓存 proxy_cache_bypass $http_cache_control $cookie_nocache; # 指定不缓存的条件 proxy_no_cache $arg_nocache $http_pragma; # 后端宕机时使用过期缓存(容灾) proxy_cache_use_stale error timeout updating http_500 http_502 http_503; # 缓存锁(防止缓存击穿) proxy_cache_lock on; proxy_cache_lock_timeout 5s; # 手动清除缓存(需要 ngx_cache_purge 模块) location ~ /purge(/.*) { allow 127.0.0.1; deny all; proxy_cache_purge my_cache "$scheme$host$1"; }第十章 架构设计
10.1 单机部署
Client → Nginx → 本机应用(Node/Java/Python)最简单的部署方式,适合小型项目和开发环境。
10.2 反向代理架构
┌────────────────┐ Client ──→ Nginx ──→│ App Server │ │ (单台后端) │ └────────────────┘适合中小型项目,Nginx 负责 SSL 终端、静态资源、请求转发。
10.3 负载均衡架构
┌─── App Server 1 Client ──→ Nginx ──┤─── App Server 2 (LB) └─── App Server 3水平扩展,Nginx 按策略分发流量。
10.4 微服务网关架构
┌─────────────┐ │ Nginx 网关 │ │ (路由/鉴权) │ └──┬──┬──┬────┘ │ │ │ ┌──────┘ │ └──────┐ ▼ ▼ ▼ ┌────────┐┌────────┐┌────────┐ │用户服务 ││商品服务 ││订单服务 │ └────────┘└────────┘└────────┘# 微服务网关配置示例 upstream user_service { server 10.0.1.1:8001; server 10.0.1.2:8001; } upstream product_service { server 10.0.2.1:8002; server 10.0.2.2:8002; } upstream order_service { server 10.0.3.1:8003; server 10.0.3.2:8003; } server { listen 443 ssl; location /api/user/ { proxy_pass http://user_service; } location /api/product/ { proxy_pass http://product_service; } location /api/order/ { proxy_pass http://order_service; } }10.5 CDN + Nginx
Client → CDN 边缘节点 → Nginx 源站 → App ServerCDN 缓存静态资源,减少源站压力。Nginx 作为源站负责动态内容和回源策略。
# 源站配置:设置 CDN 友好的缓存头 location ~* \.(css|js|jpg|png)$ { add_header Cache-Control "public, max-age=31536000"; add_header CDN-Cache-Control "max-age=86400"; # CDN 专用缓存头 }10.6 高可用(Keepalived)
VIP: 192.168.1.100 ┌──────────┐ │ 虚拟 IP │ └────┬─────┘ ┌───────┴───────┐ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ Nginx Master│ │ Nginx Backup│ │ (MASTER) │ │ (BACKUP) │ │ 优先级 100 │ │ 优先级 90 │ └─────────────┘ └─────────────┘ Master 宕机 → VIP 自动漂移到 Backup# /etc/keepalived/keepalived.conf(Master 节点)vrrp_script check_nginx{script"/usr/bin/killall -0 nginx"interval2weight-20}vrrp_instance VI_1{state MASTER interface eth0 virtual_router_id51priority100advert_int1virtual_ipaddress{192.168.1.100}track_script{check_nginx}}第十一章 安全体系
11.1 HTTPS 安全加固
# TLS 安全最佳实践 ssl_protocols TLSv1.2 TLSv1.3; # 禁用旧协议 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; ssl_ecdh_curve X25519:P-256; # OCSP Stapling(加速证书验证) ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 valid=300s;11.2 防 DDoS
# 连接级限制 limit_conn_zone $binary_remote_addr zone=ddos_conn:10m; limit_conn ddos_conn 50; # 每 IP 50 连接 # 请求级限制 limit_req_zone $binary_remote_addr zone=ddos_req:10m rate=30r/s; limit_req zone=ddos_req burst=50 nodelay;11.3 防 CC 攻击
# 针对特定接口严格限流 location /api/login { limit_req zone=strict_limit burst=5 nodelay; # 每秒2次 # 验证 User-Agent(拦截简单爬虫) if ($http_user_agent ~* "curl|wget|python|scrapy") { return 403; } }11.4 安全 Header
server { # 防止点击劫持 add_header X-Frame-Options "SAMEORIGIN" always; # 防止 MIME 类型嗅探 add_header X-Content-Type-Options "nosniff" always; # XSS 防护 add_header X-XSS-Protection "1; mode=block" always; # HSTS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # CSP 内容安全策略 add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'" always; # 隐藏 Nginx 版本号 server_tokens off; }11.5 限流与黑名单
# 使用 geo 模块定义黑名单 geo $blocked_ip { default 0; 1.2.3.4 1; 5.6.7.0/24 1; } server { if ($blocked_ip) { return 444; # 直接关闭连接,不返回任何内容 } } # 或使用外部文件 # include /etc/nginx/blocklist.conf;第十二章 运维与部署
12.1 配置热更新
# 平滑重载(不中断服务)nginx-t&&nginx-sreload# 原理:# 1. Master 读取新配置# 2. 启动新的 Worker 进程# 3. 旧 Worker 处理完当前请求后退出# 4. 全程不中断已建立的连接12.2 滚动发布
upstream backend { server 10.0.0.1:8080; # 先更新这台 server 10.0.0.2:8080; server 10.0.0.3:8080; } # 滚动流程: # 1. 标记 server1 为 down → reload # 2. 更新 server1 应用 # 3. 恢复 server1 → reload # 4. 对 server2、server3 重复12.3 灰度发布
upstream stable { server 10.0.0.1:8080; } upstream canary { server 10.0.0.2:8080; } # 方式一:按 Cookie map $cookie_version $backend { "canary" canary; default stable; } # 方式二:按 IP 百分比 split_clients "$remote_addr" $backend { 10% canary; # 10% 流量到金丝雀 * stable; # 90% 流量到稳定版 } server { location / { proxy_pass http://$backend; } }12.4 Docker 部署
# Dockerfile FROM nginx:1.24-alpine COPY nginx.conf /etc/nginx/nginx.conf COPY conf.d/ /etc/nginx/conf.d/ COPY html/ /usr/share/nginx/html/ EXPOSE 80 443# docker-compose.ymlversion:'3.8'services:nginx:image:nginx:1.24-alpineports:-"80:80"-"443:443"volumes:-./nginx.conf:/etc/nginx/nginx.conf:ro-./conf.d:/etc/nginx/conf.d:ro-./ssl:/etc/nginx/ssl:ro-./logs:/var/log/nginxrestart:unless-stopped12.5 Kubernetes 部署
# Ingress Controller(K8s 中 Nginx 的典型用法)apiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:app-ingressannotations:nginx.ingress.kubernetes.io/rewrite-target:/nginx.ingress.kubernetes.io/ssl-redirect:"true"spec:ingressClassName:nginxtls:-hosts:[app.example.com]secretName:app-tlsrules:-host:app.example.comhttp:paths:-path:/apipathType:Prefixbackend:service:name:api-serviceport:number:8080-path:/pathType:Prefixbackend:service:name:web-serviceport:number:80第十三章 故障排查
13.1 启动失败
# 检查配置语法nginx-t# 常见原因:# - 配置文件语法错误(缺少分号、括号不匹配)# - 端口被占用(见13.2)# - 权限不足(80端口需要root)# - 证书文件路径错误或证书过期13.2 端口占用
# 查看端口占用sudolsof-i:80sudonetstat-tlnp|grep:80sudoss-tlnp|grep:80# 终止占用进程sudokill-9<PID># 或修改 Nginx 监听端口13.3 403 错误
# 排查清单:# 1. 文件权限:Nginx Worker 用户是否有读权限ls-la/var/www/html/chmod-R755/var/www/html/chown-Rnginx:nginx /var/www/html/# 2. SELinux 限制(CentOS)getenforce setsebool-Phttpd_read_user_content1# 或临时关闭:setenforce 0# 3. 没有 index 文件且未开启 autoindex# 4. allow/deny 规则拦截13.4 404 错误
# 排查清单:# 1. root 路径配置错误# 2. location 匹配不到# 3. try_files 配置问题(SPA 应用常见)# 4. proxy_pass URI 拼接错误(带不带 / 的区别)# 调试:开启 debug 日志error_log /var/log/nginx/error.log debug;13.5 502 / 504 错误
# 502 Bad Gateway:后端服务没响应# 排查:# 1. 后端服务是否启动curlhttp://127.0.0.1:8080/health# 2. upstream 地址是否正确# 3. 后端服务是否崩溃(查看后端日志)# 504 Gateway Timeout:后端响应超时# 解决:调大超时时间proxy_connect_timeout 60s;proxy_read_timeout 120s;proxy_send_timeout 60s;13.6 域名解析问题
# 检查 DNS 解析nslookupexample.comdigexample.com# Nginx 中使用域名做 upstream 时的坑:# Nginx 启动时解析一次 DNS,之后不再更新!# 解决方案:resolver8.8.8.8valid=30s;set$backend"http://dynamic-host.example.com";proxy_pass$backend;# 使用变量才会触发动态解析13.7 性能瓶颈分析
# 查看 Nginx 连接状态curlhttp://localhost/nginx_status# 查看系统资源top-p$(pgrep -d, nginx)# CPU/内存ss-s# 连接统计ulimit-n# 文件描述符上限# 常见瓶颈及解决:# - worker_connections 不够 → 增大# - 文件描述符不够 → ulimit -n 65535# - CPU 满 → 检查 gzip level、正则匹配# - 内存不够 → 减小 buffer、限制缓存大小# - 磁盘 I/O → 开启 sendfile、使用 SSD第十四章 进阶扩展
14.1 OpenResty(Lua)
OpenResty = Nginx + LuaJIT,支持在 Nginx 中嵌入 Lua 代码,实现复杂业务逻辑。
# 使用 Lua 实现动态限流 location /api/ { access_by_lua_block { local limit = require "resty.limit.req" local lim, err = limit.new("my_limit", 100, 50) local delay, err = lim:incoming(ngx.var.remote_addr, true) if not delay then return ngx.exit(429) end } proxy_pass http://backend; } # 使用 Lua 操作 Redis location /cache { content_by_lua_block { local redis = require "resty.redis" local red = redis:new() red:connect("127.0.0.1", 6379) local val = red:get("my_key") ngx.say(val) } }Lua 执行阶段:
| 阶段 | 指令 | 用途 |
|---|---|---|
| rewrite | rewrite_by_lua | URL 重写 |
| access | access_by_lua | 鉴权、限流 |
| content | content_by_lua | 生成响应内容 |
| log | log_by_lua | 自定义日志 |
| header_filter | header_filter_by_lua | 修改响应头 |
| body_filter | body_filter_by_lua | 修改响应体 |
14.2 动态配置
# 使用 Consul + consul-template 动态更新 upstream # consul-template 模板: upstream backend { {{range service "web"}} server {{.Address}}:{{.Port}}; {{end}} } # 或使用 Nginx Plus 的动态 upstream API # 或使用 OpenResty + lua-resty-dns 动态解析14.3 API 网关实现
# 完整的 API 网关配置 server { listen 443 ssl; # 统一鉴权 location /api/ { access_by_lua_block { local token = ngx.req.get_headers()["Authorization"] if not token then return ngx.exit(401) end -- 验证 JWT token... } # 限流 limit_req zone=api burst=20 nodelay; # 路由转发 location /api/user/ { proxy_pass http://user_svc; } location /api/order/ { proxy_pass http://order_svc; } location /api/product/ { proxy_pass http://product_svc; } } }14.4 HTTP/2 与 HTTP/3
# HTTP/2(需要 HTTPS) server { listen 443 ssl http2; # http2_push /css/style.css; # Server Push(已被弃用) # http2_max_concurrent_streams 128; } # HTTP/3(QUIC,Nginx 1.25+) server { listen 443 ssl; listen 443 quic reuseport; # QUIC 监听 ssl_protocols TLSv1.3; # HTTP/3 要求 TLS 1.3 add_header Alt-Svc 'h3=":443"; ma=86400'; # 告知浏览器支持 HTTP/3 # 开启 0-RTT(加速连接建立) ssl_early_data on; }14.5 模块开发
// 自定义模块基本结构(C 语言)#include<ngx_config.h>#include<ngx_core.h>#include<ngx_http.h>staticngx_int_tngx_http_hello_handler(ngx_http_request_t*r){ngx_str_tresponse=ngx_string("Hello from custom module!");r->headers_out.status=NGX_HTTP_OK;r->headers_out.content_length_n=response.len;ngx_http_send_header(r);ngx_buf_t*b=ngx_create_temp_buf(r->pool,response.len);ngx_memcpy(b->pos,response.data,response.len);b->last=b->pos+response.len;b->last_buf=1;ngx_chain_tout={.buf=b,.next=NULL};returnngx_http_output_filter(r,&out);}常用第三方模块:
| 模块 | 功能 |
|---|---|
| ngx_cache_purge | 手动清除缓存 |
| ngx_brotli | Brotli 压缩(比 gzip 更优) |
| headers-more | 灵活操作 HTTP 头 |
| lua-nginx-module | 嵌入 Lua 脚本 |
| njs | 嵌入 JavaScript |
第十五章 对比与选型
15.1 Nginx vs Apache
| 维度 | Nginx | Apache |
|---|---|---|
| 架构 | 事件驱动,异步非阻塞 | 进程/线程模型(prefork/worker) |
| 并发能力 | 数万级 | 千级 |
| 内存消耗 | 极低 | 较高 |
| 静态文件 | 极快 | 较慢 |
| 动态内容 | 需反代到后端 | 直接集成(mod_php) |
| .htaccess | ❌ 不支持 | ✅ 支持 |
| 模块加载 | 编译时确定(动态模块需重编译) | 运行时动态加载 |
| 适用场景 | 高并发、反向代理、负载均衡 | 传统 PHP 项目、共享主机 |
结论:新项目首选 Nginx;老旧 PHP 项目或需要.htaccess时用 Apache。
15.2 Nginx vs Tomcat
| 维度 | Nginx | Tomcat |
|---|---|---|
| 定位 | Web Server / 反向代理 | Java Servlet 容器 |
| 静态文件 | 极强 | 较弱 |
| 动态内容 | 不直接处理 | 运行 Java 应用 |
| 并发能力 | 数万级 | 数百到数千 |
典型组合:Client → Nginx(SSL终端 + 静态资源 + 负载均衡) → Tomcat(Java 应用)
15.3 Nginx vs Envoy
| 维度 | Nginx | Envoy |
|---|---|---|
| 开发语言 | C | C++ |
| 配置方式 | 静态文件 | 动态 API(xDS) |
| 服务发现 | 需第三方 | 原生支持 |
| 可观测性 | 基础 | 丰富(分布式追踪、指标) |
| 热更新 | reload(微秒级中断) | 热重启(零中断) |
| 适用场景 | 通用 Web/反向代理/LB | Service Mesh(Istio Sidecar) |
选型建议:
- 传统 Web 项目:Nginx(成熟稳定、资料丰富)
- 云原生/Service Mesh:Envoy(Istio 默认 Sidecar)
- 需要 Lua 扩展:OpenResty(Nginx + Lua)
- 需要商业支持:Nginx Plus
附录:生产环境完整配置模板
# /etc/nginx/nginx.conf user nginx; worker_processes auto; worker_rlimit_nofile 65535; error_log /var/log/nginx/error.log warn; pid /run/nginx.pid; events { worker_connections 65535; multi_accept on; use epoll; } http { include mime.types; default_type application/octet-stream; # ── 日志 ── log_format main '$remote_addr - [$time_local] "$request" ' '$status $body_bytes_sent $request_time'; access_log /var/log/nginx/access.log main; # ── 性能 ── sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; keepalive_requests 1000; # ── 压缩 ── gzip on; gzip_vary on; gzip_min_length 1k; gzip_comp_level 4; gzip_types text/plain text/css application/json application/javascript text/xml image/svg+xml; # ── 安全 ── server_tokens off; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; # ── 限流 ── limit_req_zone $binary_remote_addr zone=global:10m rate=30r/s; limit_conn_zone $binary_remote_addr zone=conn:10m; # ── 缓存 ── proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cache:10m max_size=5g inactive=60m; # ── 引入站点配置 ── include /etc/nginx/conf.d/*.conf; }