【Nginx】Nginx需具体配置示例(涵盖了复杂场景下的高级应用)

小破孩
2025-07-16 / 0 评论 / 4 阅读 / 正在检测是否收录...

以下是 Nginx 常见场景的具体配置示例,配置文件可存放在 /etc/nginx/conf.d/ 目录下(Linux)或直接修改 nginx.conf(Windows):

一、基础配置:静态网站托管

配置文件/etc/nginx/conf.d/mysite.conf

server {
    listen 80;
    server_name example.com www.example.com;  # 替换为你的域名
    
    # 网站根目录
    root /var/www/html;
    index index.html index.htm;
    
    # 日志配置
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    
    # 静态文件缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;  # 静态资源缓存30天
    }
    
    # 错误页面
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
}

操作步骤

  1. 创建网站目录:sudo mkdir -p /var/www/html
  2. 添加测试文件:echo "Hello, Nginx!" > /var/www/html/index.html
  3. 验证配置:nginx -t
  4. 重载配置:nginx -s reload

二、反向代理:转发到后端服务

场景1:代理到本地 Node.js 应用(端口3000)

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://localhost: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_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

场景2:代理到多个后端服务器(负载均衡)

# 定义后端服务器组
upstream backend_servers {
    server backend1.example.com weight=5;  # 权重5
    server backend2.example.com weight=3;  # 权重3
    server backend3.example.com backup;    # 备份服务器
}

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://backend_servers;
        # 其他 proxy_set_header 配置同上
    }
}

三、HTTPS 配置(使用 Let's Encrypt 证书)

前提条件

  1. 已安装 Certbot:sudo apt install certbot python3-certbot-nginx
  2. 域名已解析到服务器 IP

自动配置(推荐)

sudo certbot --nginx -d example.com -d www.example.com

Certbot 会自动修改 Nginx 配置并设置证书自动更新。

手动配置示例

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;  # 强制 HTTPS
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    # 证书路径(Let's Encrypt 默认路径)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
    # SSL 优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 其他配置(如 root、location 等)同 HTTP 配置
}

四、URL 重写与跳转

示例1:www 到非 www 跳转

server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

示例2:路径重写

location /old-path/ {
    rewrite ^/old-path/(.*)$ /new-path/$1 permanent;  # 301 永久重定向
}

示例3:基于参数跳转

if ($args ~* "id=([0-9]+)") {
    return 301 https://example.com/item/$1;
}

五、限流配置(防爬/防刷)

限制单个 IP 的请求频率

# http 块中定义限流规则
http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
    
    server {
        listen 80;
        server_name example.com;
        
        location /api/ {
            limit_req zone=mylimit burst=20 nodelay;
            # 每秒最多10个请求,突发最多20个,超出的请求直接返回503
        }
    }
}

六、WebSocket 代理支持

配置示例

server {
    listen 80;
    server_name ws.example.com;
    
    location /ws/ {
        proxy_pass http://backend_websocket_server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        
        # 防止 WebSocket 连接超时
        proxy_read_timeout 86400;
    }
}

七、多站点配置(虚拟主机)

在同一服务器托管多个域名

# 站点1
server {
    listen 80;
    server_name site1.com www.site1.com;
    root /var/www/site1;
}

# 站点2
server {
    listen 80;
    server_name site2.com www.site2.com;
    root /var/www/site2;
}

八、静态文件优化配置

配置 Gzip 压缩

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
}

九、常见问题处理配置

1. 解决跨域请求(CORS)

location /api/ {
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
    
    # OPTIONS 请求直接返回 204
    if ($request_method = 'OPTIONS') {
        return 204;
    }
}

2. 隐藏 Nginx 版本信息

http {
    server_tokens off;  # 隐藏响应头中的 Nginx 版本
}

配置验证与重载

每次修改配置后,务必执行:

nginx -t  # 验证配置语法
nginx -s reload  # 重载配置(不中断服务)

以上配置可根据实际需求组合使用,例如同时配置 HTTPS、反向代理和限流。如需更复杂的场景(如 A/B 测试、灰度发布),可进一步扩展配置。

以下是 Nginx 更高级的扩展配置示例,适用于复杂场景:

十、A/B 测试与灰度发布

基于 Cookie 的流量分发

http {
    # 定义变量存储分流规则
    map $cookie_ab_test $backend {
        default backend_a;
        "b"    backend_b;
    }
    
    upstream backend_a {
        server backend1.example.com;
    }
    
    upstream backend_b {
        server backend2.example.com;
    }
    
    server {
        listen 80;
        server_name example.com;
        
        # 首次访问设置 Cookie
        if ($cookie_ab_test = "") {
            set $ab_test $random % 2;  # 随机分为两组
            if ($ab_test = 0) {
                add_header Set-Cookie "ab_test=a; path=/; domain=.example.com";
            }
            if ($ab_test = 1) {
                add_header Set-Cookie "ab_test=b; path=/; domain=.example.com";
            }
        }
        
        location / {
            proxy_pass http://$backend;
        }
    }
}

十一、基于用户区域的流量路由

根据 IP 地理位置分发请求

# 需要安装 ngx_http_geoip2_module 模块
http {
    geoip2 /path/to/GeoLite2-Country.mmdb {
        $geoip2_data_country_code country iso_code;
    }
    
    map $geoip2_data_country_code $backend {
        default backend_global;
        "CN"    backend_china;
        "US"    backend_usa;
    }
    
    upstream backend_global {
        server global.example.com;
    }
    
    upstream backend_china {
        server china.example.com;
    }
    
    upstream backend_usa {
        server usa.example.com;
    }
    
    server {
        listen 80;
        server_name example.com;
        
        location / {
            proxy_pass http://$backend;
        }
    }
}

十二、内容缓存配置

配置代理缓存(如缓存 API 响应)

http {
    # 定义缓存参数
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
    
    server {
        listen 80;
        server_name api.example.com;
        
        location /static-api/ {
            proxy_pass http://backend_api;
            proxy_cache my_cache;
            proxy_cache_key "$scheme$request_method$host$request_uri";
            proxy_cache_valid 200 302 12h;  # 成功响应缓存12小时
            proxy_cache_valid 404 1m;       # 404缓存1分钟
            
            # 缓存命中时添加响应头,便于调试
            add_header X-Cache $upstream_cache_status;
        }
    }
}

十三、健康检查与自动剔除故障节点

配置主动健康检查(需 nginx-plus 或 lua 模块)

http {
    upstream backend_servers {
        server backend1.example.com max_fails=3 fail_timeout=30s;
        server backend2.example.com max_fails=3 fail_timeout=30s;
        
        # 健康检查(Nginx Plus 功能)
        zone backend 64k;
        health_check interval=5s fails=3 passes=2 uri=/health;
    }
    
    server {
        listen 80;
        server_name example.com;
        
        location / {
            proxy_pass http://backend_servers;
        }
    }
}

使用 Lua 模块实现健康检查(开源版)

# 需要安装 ngx_lua 模块
http {
    lua_shared_dict healthcheck 1m;
    
    init_by_lua_block {
        local hc = require "resty.healthcheck"
        local checker = hc.new({
            name = "backend_checker",
            shm_name = "healthcheck",
            type = "http",
            http_req = "GET /health HTTP/1.0\r\nHost: backend\r\n\r\n",
            interval = 2000,  # 2秒检查一次
            timeout = 1000,   # 超时时间1秒
            fall = 3,         # 连续3次失败标记为不可用
            rise = 2,         # 连续2次成功标记为可用
        })
        
        -- 添加后端服务器
        checker:add_target("backend1.example.com", nil, 80, true)
        checker:add_target("backend2.example.com", nil, 80, true)
        
        -- 启动后台检查
        local ok, err = checker:start()
        if not ok then
            ngx.log(ngx.ERR, "failed to start health checker: ", err)
            return
        end
    }
    
    upstream backend_servers {
        server backend1.example.com;
        server backend2.example.com;
        
        # 使用 Lua 脚本判断服务器是否健康
        server 0.0.0.1;  # 防止 upstream 为空
        
        balancer_by_lua_block {
            local hc = require "resty.healthcheck"
            local checker = hc.new({
                name = "backend_checker",
                shm_name = "healthcheck",
                type = "http",
            })
            
            local ok, err = checker:get_reachable()
            if not ok then
                ngx.log(ngx.ERR, "no reachable backend server: ", err)
                return ngx.exit(500)
            end
            
            -- 设置要代理的服务器
            local host, port = ok.host, ok.port
            local ok, err = ngx.balancer.set_current_peer(host, port)
            if not ok then
                ngx.log(ngx.ERR, "failed to set current peer: ", err)
                return ngx.exit(500)
            end
        }
    }
}

十四、请求限流与熔断

基于漏桶算法的限流

http {
    # 定义漏桶限流规则
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;  # 每秒5个请求
    
    server {
        listen 80;
        server_name api.example.com;
        
        location /api/ {
            limit_req zone=api_limit burst=10 nodelay;  # 突发10个请求
            
            # 超过限流时返回自定义错误页面
            error_page 503 @api_blocked;
        }
        
        location @api_blocked {
            default_type application/json;
            return 503 '{"error":"Too many requests","code":429}';
        }
    }
}

熔断机制(当后端服务不可用时)

upstream backend_servers {
    server backend1.example.com;
    server backend2.example.com;
    
    # 当后端服务器返回500、502、503、504时,将请求转发到其他服务器
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}

十五、WebSocket 集群与会话保持

基于 IP Hash 的会话保持

upstream websocket_backend {
    ip_hash;  # 相同IP的请求始终转发到同一后端服务器
    server backend1.example.com:8080;
    server backend2.example.com:8080;
}

server {
    listen 80;
    server_name ws.example.com;
    
    location /ws/ {
        proxy_pass http://websocket_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        
        # 保持长连接
        proxy_read_timeout 3600s;
    }
}

十六、自定义日志格式与分析

JSON 格式日志

http {
    log_format json_log '{
        "timestamp": "$time_iso8601",
        "remote_addr": "$remote_addr",
        "host": "$host",
        "request": "$request",
        "status": $status,
        "body_bytes_sent": $body_bytes_sent,
        "request_time": $request_time,
        "upstream_response_time": "$upstream_response_time",
        "http_referer": "$http_referer",
        "http_user_agent": "$http_user_agent"
    }';
    
    server {
        listen 80;
        server_name example.com;
        
        access_log /var/log/nginx/access_json.log json_log;
    }
}

十七、HTTP/2 与 TLS 优化配置

HTTP/2 与 OCSP 装订

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;
    
    # 启用 OCSP 装订
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # TLS 优化
    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
    
    # HTTP/2 优化
    http2_push_preload on;  # 启用 HTTP/2 预推送
}

十八、自定义错误页面

配置全局错误页面

http {
    # 定义错误页面路径
    error_page 400 /errors/400.html;
    error_page 401 /errors/401.html;
    error_page 403 /errors/403.html;
    error_page 404 /errors/404.html;
    error_page 500 502 503 504 /errors/50x.html;
    
    server {
        listen 80;
        server_name example.com;
        
        location /errors/ {
            internal;  # 只允许内部重定向访问
            root /var/www/html;
        }
    }
}

十九、Nginx 与 Lua 脚本集成

示例:请求签名验证

# 需要安装 ngx_lua 模块
server {
    listen 80;
    server_name api.example.com;
    
    location /api/ {
        # 验证请求签名
        access_by_lua_block {
            local secret_key = "your_secret_key"
            local request_time = ngx.var.arg_timestamp
            local signature = ngx.var.arg_signature
            
            # 检查时间戳是否过期(防止重放攻击)
            local current_time = os.time()
            if not request_time or math.abs(current_time - tonumber(request_time)) > 300 then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say('{"error":"Invalid timestamp"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end
            
            # 验证签名
            local args = ngx.req.get_uri_args()
            local sorted_keys = {}
            for k, _ in pairs(args) do
                if k ~= "sign" then
                    table.insert(sorted_keys, k)
                end
            end
            table.sort(sorted_keys)
            
            local sign_str = ""
            for _, k in ipairs(sorted_keys) do
                sign_str = sign_str .. k .. "=" .. args[k] .. "&"
            end
            sign_str = sign_str .. "key=" .. secret_key
            
            local resty_sha1 = require "resty.sha1"
            local str = require "resty.string"
            local sha1 = resty_sha1:new()
            sha1:update(sign_str)
            local digest = sha1:final()
            local calculated_sign = str.to_hex(digest)
            
            if calculated_sign ~= signature then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say('{"error":"Invalid signature"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end
        }
        
        proxy_pass http://backend_api;
    }
}

二十、基于 JWT 的认证

JWT 验证示例

# 需要安装 lua-resty-jwt 模块
server {
    listen 80;
    server_name auth.example.com;
    
    location /api/ {
        access_by_lua_block {
            local jwt = require "resty.jwt"
            local secret = "your_jwt_secret"
            
            -- 从请求头中获取 JWT
            local auth_header = ngx.var.http_Authorization
            if not auth_header then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say('{"error":"Authorization header missing"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end
            
            -- 提取 token
            local _, _, token = string.find(auth_header, "Bearer%s+(.+)")
            if not token then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say('{"error":"Invalid token format"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end
            
            -- 验证 JWT
            local jwt_obj = jwt:verify(secret, token)
            if not jwt_obj.verified then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say('{"error":"' .. jwt_obj.reason .. '"}')
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end
            
            -- 将用户信息传递给后端
            ngx.req.set_header("X-User-ID", jwt_obj.payload.user_id)
            ngx.req.set_header("X-User-Role", jwt_obj.payload.role)
        }
        
        proxy_pass http://backend_api;
    }
}

配置验证与重载

每次修改配置后,务必执行:

nginx -t  # 验证配置语法
nginx -s reload  # 重载配置(不中断服务)

以上配置涵盖了复杂场景下的高级应用,可根据实际需求组合使用。对于生产环境,建议先在测试环境验证配置,确保稳定性。

0

评论 (0)

取消