Nginx 是绝大多数 Web 架构的入口。配置得当,它是铜墙铁壁;配置粗糙,它就是性能瓶颈和安全隐患。本文是一份实战导向的速查手册,覆盖从初次部署到生产调优的全链路。


一、基础结构速览

Nginx 的配置由指令(directive)和块(block)组成,层级关系决定作用域。

主配置文件: /etc/nginx/nginx.conf 站点配置: /etc/nginx/conf.d/*.conf/etc/nginx/sites-enabled/*

├── main          # 全局:worker 进程、日志、pid
│   ├── events    # 连接处理模型
│   └── http      # HTTP 协议相关
│       ├── upstream    # 后端服务器组
│       ├── server      # 虚拟主机(站点)
│       │   └── location  # URL 路径匹配
│       └── map         # 变量映射

核心概念

概念

说明

指令

以分号结尾的配置行,如 worker_processes auto;

用花括号包裹的指令集合,如 http { ... }

继承

子块继承父块的配置,子块可覆盖

include

拆分配置文件,避免单文件过大

快速操作

# 测试配置语法
nginx -t

# 重新加载(不中断连接)
nginx -s reload

# 查看编译参数和模块
nginx -V

# 查看生效的完整配置
nginx -T

二、虚拟主机配置

2.1 静态站点

server {
    listen       80;
    server_name  example.com www.example.com;

    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

2.2 匹配规则与优先级

符号

含义

优先级

=

精确匹配

最高

^~

前缀匹配(停止搜索正则)

~

正则匹配(区分大小写)

~*

正则匹配(不区分大小写)

/

通用前缀匹配(最长前缀)

匹配优先级= > ^~ > ~ / ~* > /


三、反向代理与负载均衡

3.1 基础反向代理

upstream backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://backend;

        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_send_timeout    30s;
        proxy_read_timeout    30s;
    }
}

3.2 负载均衡策略

策略

配置

适用场景

轮询(默认)

无特殊指令

通用场景

加权轮询

server 10.0.0.1:3000 weight=3;

服务器性能不均

IP Hash

ip_hash;

会话保持

最少连接

least_conn;

长连接场景

健康检查

server 10.0.0.1:3000 max_fails=3 fail_timeout=30s;

生产必备

备用节点

server 10.0.0.3:3000 backup;

故障转移

3.3 WebSocket 代理

location /ws {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;
}

四、HTTPS 与安全加固

4.1 基础 HTTPS

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;

    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;
    ssl_prefer_server_ciphers off;

    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    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;
}

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

4.2 安全 Headers

add_header X-Frame-Options       "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection      "1; mode=block" always;
add_header Referrer-Policy        "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

4.3 敏感路径防护

# 禁止访问隐藏文件(.git、.env 等)
location ~ /\. {
    deny all;
    return 404;
}

# 禁止访问备份文件
location ~* \.(bak|sql|log|conf)$ {
    deny all;
}

# 限制特定 IP 访问管理后台
location /admin/ {
    allow 10.0.0.0/8;
    allow 192.168.0.0/16;
    deny all;
    proxy_pass http://backend;
}

五、性能调优

5.1 Worker 进程与连接

worker_processes auto;
worker_rlimit_nofile 65535;

events {
    use epoll;
    worker_connections 10240;
    multi_accept on;
}

5.2 HTTP 层优化

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 30s;
    keepalive_requests 100;

    client_max_body_size 50m;
    client_body_buffer_size 128k;

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_types
        text/plain
        text/css
        text/javascript
        application/json
        application/javascript
        application/xml
        application/xml+rss
        image/svg+xml;
}

5.3 静态资源优化

# 图片等静态资源 — 长期缓存
location ~* \.(jpg|jpeg|png|gif|ico|webp|avif)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
    access_log off;
}

# CSS/JS/字体
location ~* \.(css|js|woff2?|ttf|eot)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
    access_log off;
}

# HTML — 每次验证
location ~* \.(html|htm)$ {
    add_header Cache-Control "no-cache, must-revalidate";
}

六、缓存策略

6.1 代理缓存

http {
    proxy_cache_path /var/cache/nginx
        levels=1:2
        keys_zone=app_cache:10m
        max_size=1g
        inactive=60m
        use_temp_path=off;
}

server {
    location / {
        proxy_pass http://backend;

        proxy_cache app_cache;
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 404      1m;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
        proxy_cache_lock on;
        proxy_cache_lock_timeout 5s;

        add_header X-Cache-Status $upstream_cache_status;
    }
}

$upstream_cache_status 值说明MISS -> HIT -> EXPIRED -> STALE -> UPDATING -> BYPASS

6.2 按条件缓存

# 不缓存 POST 请求
proxy_cache_methods GET HEAD;

# 不缓存包含特定 Cookie 的请求
proxy_cache_bypass $cookie_session;
proxy_no_cache     $cookie_session;

# 按 URL 参数跳过缓存
proxy_cache_bypass $arg_nocache;

七、日志与监控

7.1 自定义日志格式

log_format main '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" '
                '$request_time $upstream_response_time';

log_format json escape=json '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"method":"$request_method",'
    '"uri":"$request_uri",'
    '"status":$status,'
    '"body_bytes":$body_bytes_sent,'
    '"request_time":$request_time,'
    '"upstream_time":"$upstream_response_time"'
'}';

7.2 状态监控

location /nginx_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}

7.3 日志切割

# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

八、常见问题排查

8.1 502 Bad Gateway

curl -I http://127.0.0.1:3000
tail -f /var/log/nginx/error.log

常见原因:

  • 后端服务挂了 -> 重启后端

  • proxy_pass 地址写错 -> 核对 upstream

  • 连接超时太短 -> 增大 proxy_connect_timeout

  • 文件描述符耗尽 -> 调大 worker_rlimit_nofile

8.2 413 Request Entity Too Large

client_max_body_size 100m;  # 默认 1m,按需调大

8.3 504 Gateway Timeout

proxy_read_timeout 120s;    # 默认 60s
proxy_send_timeout 120s;

8.4 配置不生效

nginx -t        # 检查语法
nginx -T | grep "你的指令"   # 查看实际加载的配置
ps aux | grep nginx          # 确认进程已更新

8.5 跨域问题

location /api/ {
    add_header Access-Control-Allow-Origin * always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;

    if ($request_method = 'OPTIONS') {
        return 204;
    }

    proxy_pass http://backend;
}

九、生产配置模板

主配置 /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;

events {
    use epoll;
    worker_connections 10240;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    types_hash_max_size 2048;
    server_tokens off;

    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    keepalive_timeout 30s;
    keepalive_requests 100;
    client_max_body_size 50m;
    client_body_buffer_size 128k;

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_types text/plain text/css text/javascript application/json
               application/javascript application/xml image/svg+xml;

    log_format json escape=json '{'
        '"time":"$time_iso8601",'
        '"remote_addr":"$remote_addr",'
        '"method":"$request_method",'
        '"uri":"$request_uri",'
        '"status":$status,'
        '"body_bytes":$body_bytes_sent,'
        '"request_time":$request_time,'
        '"upstream_time":"$upstream_response_time"'
    '}';

    access_log /var/log/nginx/access.log json buffer=32k flush=5s;
    error_log  /var/log/nginx/error.log warn;

    proxy_cache_path /var/cache/nginx
        levels=1:2
        keys_zone=app_cache:10m
        max_size=1g
        inactive=60m
        use_temp_path=off;

    include /etc/nginx/conf.d/*.conf;
}

站点配置 /etc/nginx/conf.d/example.conf

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

server {
    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;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;

    add_header X-Frame-Options        "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    access_log /var/log/nginx/example.access.log json buffer=32k flush=5s;
    error_log  /var/log/nginx/example.error.log warn;

    location ~* \.(jpg|jpeg|png|gif|ico|webp|css|js|woff2?)$ {
        root /var/www/example.com;
        expires 365d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    location /api/ {
        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_connect_timeout 5s;
        proxy_read_timeout 60s;
        proxy_cache app_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_use_stale error timeout updating;
        add_header X-Cache-Status $upstream_cache_status;
    }

    location / {
        root /var/www/example.com/dist;
        try_files $uri $uri/ /index.html;
    }

    location ~ /\. {
        deny all;
        return 404;
    }
}

附:上线检查清单

  • nginx -t 配置语法无报错

  • server_tokens off 已关闭版本暴露

  • HTTPS 已启用,HTTP 已跳转

  • TLS 仅启用 1.2+,HSTS 已配置

  • 安全 Headers 齐全(X-Frame-Options 等)

  • 隐藏文件(.git、.env)已禁止访问

  • client_max_body_size 按业务设置合理值

  • gzip 已开启,排除已压缩格式

  • 静态资源已设置长期缓存 + immutable

  • 日志格式包含 request_time 和 upstream_response_time

  • error_log 级别为 warn(生产不要用 debug)

  • 代理超时已按业务场景调整


本文是「服务器运维笔记」系列第 2 篇。