Nginx 知识体系 · 下篇:高级与实战


第九章 缓存机制

9.1 浏览器缓存(expires)

nginx 复制代码
# 方式一: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)

nginx 复制代码
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 缓存控制策略

nginx 复制代码
# 指定条件绕过缓存
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 网关  │
             │  (路由/鉴权)  │
             └──┬──┬──┬────┘
                │  │  │
         ┌──────┘  │  └──────┐
         ▼         ▼         ▼
    ┌────────┐┌────────┐┌────────┐
    │用户服务 ││商品服务 ││订单服务 │
    └────────┘└────────┘└────────┘
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 Server

CDN 缓存静态资源,减少源站压力。Nginx 作为源站负责动态内容和回源策略。

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
bash 复制代码
# /etc/keepalived/keepalived.conf(Master 节点)
vrrp_script check_nginx {
    script "/usr/bin/killall -0 nginx"
    interval 2
    weight -20
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    virtual_ipaddress {
        192.168.1.100
    }

    track_script {
        check_nginx
    }
}

第十一章 安全体系

11.1 HTTPS 安全加固

nginx 复制代码
# 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

nginx 复制代码
# 连接级限制
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 攻击

nginx 复制代码
# 针对特定接口严格限流
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

nginx 复制代码
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 限流与黑名单

nginx 复制代码
# 使用 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 配置热更新

bash 复制代码
# 平滑重载(不中断服务)
nginx -t && nginx -s reload

# 原理:
# 1. Master 读取新配置
# 2. 启动新的 Worker 进程
# 3. 旧 Worker 处理完当前请求后退出
# 4. 全程不中断已建立的连接

12.2 滚动发布

nginx 复制代码
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 灰度发布

nginx 复制代码
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 复制代码
# 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
yaml 复制代码
# docker-compose.yml
version: '3.8'
services:
  nginx:
    image: nginx:1.24-alpine
    ports:
      - "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/nginx
    restart: unless-stopped

12.5 Kubernetes 部署

yaml 复制代码
# Ingress Controller(K8s 中 Nginx 的典型用法)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts: [app.example.com]
      secretName: app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80

第十三章 故障排查

13.1 启动失败

bash 复制代码
# 检查配置语法
nginx -t

# 常见原因:
# - 配置文件语法错误(缺少分号、括号不匹配)
# - 端口被占用(见13.2)
# - 权限不足(80端口需要root)
# - 证书文件路径错误或证书过期

13.2 端口占用

bash 复制代码
# 查看端口占用
sudo lsof -i :80
sudo netstat -tlnp | grep :80
sudo ss -tlnp | grep :80

# 终止占用进程
sudo kill -9 <PID>
# 或修改 Nginx 监听端口

13.3 403 错误

bash 复制代码
# 排查清单:
# 1. 文件权限:Nginx Worker 用户是否有读权限
ls -la /var/www/html/
chmod -R 755 /var/www/html/
chown -R nginx:nginx /var/www/html/

# 2. SELinux 限制(CentOS)
getenforce
setsebool -P httpd_read_user_content 1
# 或临时关闭:setenforce 0

# 3. 没有 index 文件且未开启 autoindex
# 4. allow/deny 规则拦截

13.4 404 错误

bash 复制代码
# 排查清单:
# 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 错误

bash 复制代码
# 502 Bad Gateway:后端服务没响应
# 排查:
# 1. 后端服务是否启动
curl http://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 域名解析问题

bash 复制代码
# 检查 DNS 解析
nslookup example.com
dig example.com

# Nginx 中使用域名做 upstream 时的坑:
# Nginx 启动时解析一次 DNS,之后不再更新!
# 解决方案:
resolver 8.8.8.8 valid=30s;
set $backend "http://dynamic-host.example.com";
proxy_pass $backend;    # 使用变量才会触发动态解析

13.7 性能瓶颈分析

bash 复制代码
# 查看 Nginx 连接状态
curl http://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 代码,实现复杂业务逻辑。

nginx 复制代码
# 使用 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 动态配置

nginx 复制代码
# 使用 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 网关实现

nginx 复制代码
# 完整的 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

nginx 复制代码
# 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 复制代码
// 自定义模块基本结构(C 语言)
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
    ngx_str_t response = 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_t out = { .buf = b, .next = NULL };
    return ngx_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

附录:生产环境完整配置模板

nginx 复制代码
# /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;
}

相关推荐
小五传输2 小时前
内外网文件交换系统产品推荐:安全高效一体化,破解内外网传输难题
大数据·运维·安全
佳xuan2 小时前
linux运维
linux·运维·服务器
如果'\'真能转义说2 小时前
《数据不丢失!本地挂载的 Docker 一键启动PS1脚本》
运维·docker·容器
aramae2 小时前
Linux多线程编程(二):互斥锁、线程安全与死锁剖析
linux·运维·服务器·网络·安全·centos
爱学习的小囧3 小时前
ESXi 存储路径丢失(PDL/APD)完整处置教程:分清类型再操作,一步不踩坑
linux·运维·服务器·网络·esxi·vmware
子非鱼@Itfuture3 小时前
ThreadLocal 是什么?如何用?以及最佳使用场景
java·开发语言·spring
Lumos_7773 小时前
Linux -- 信号
linux·运维·服务器
leikooo3 小时前
Skills 实战:Unsplash → COS 自动化配图
运维·ai·自动化
Lumos_7773 小时前
Linux -- 管道
linux·运维·服务器