Nginx服务器配置详解

结论: Nginx 的配置本质是一棵"块嵌套树"——main 包含 events 与 http,http 包含若干 server,server 包含若干 location。指令只在特定作用域生效(如 worker_processes 只在 main,server_name 只在 server),子块未显式声明时继承父块值,数组型指令(如 proxy_set_header)则不继承而是完全覆盖。改完配置务必 nginx -t 校验再用 nginx -s reload 热加载,而不是重启。

引言:为什么照抄的配置常常不生效?

网上 Nginx 配置片段一抓一大把,但很多人照抄后发现"不生效":加了 client_max_body_size 还是报 413;在 location 里写了 proxy_set_header,server 里配的几条头全丢了;try_files 写对了却 404。

原因几乎都指向同一件事——不理解 Nginx 配置的作用域与继承规则。Nginx 不是"配置文件里写了就全局生效",每条指令都有严格的上下文(context),放错位置会直接报错 directive is not allowed here,或者更糟:静默地不生效。

本篇把 Nginx 配置的骨架、作用域、匹配优先级、变量、日志和调优参数一次讲透,目标是让你看完能自己写出配置,而不是拼凑片段。

一、配置文件结构树:先看清骨架

Nginx 主配置默认在 /etc/nginx/nginx.conf,通过 include 引入其他文件。以 Ubuntu 24.04 上的 Nginx 1.26(截至 2026 年主流稳定版)为例,完整结构如下:

text
/etc/nginx/
├── nginx.conf                 # 主配置:main + events + http
├── mime.types                 # 文件扩展名与 Content-Type 映射
├── fastcgi_params             # FastCGI 默认参数(PHP 用)
├── proxy_params               # 反向代理默认参数
├── sites-available/           # 可用站点配置(Debian 系约定)
│   ├── default
│   └── example.com.conf
├── sites-enabled/             # 已启用站点(通常是指向 available 的软链接)
│   └── default -> ../sites-available/default
└── conf.d/                    # 额外配置片段,nginx.conf 中 include 进来
    └── gzip.conf

对应的逻辑块结构:

nginx
# ===== main 块(全局)=====
user  www-data;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid        /run/nginx.pid;

# ===== events 块:连接处理模型 =====
events {
    worker_connections  10240;
    use                 epoll;
    multi_accept        on;
}

# ===== http 块:所有 HTTP 相关配置 =====
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      'rt=$request_time urt=$upstream_response_time';
    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
    keepalive_timeout  65;
    server_tokens   off;

    gzip  on;
    gzip_types  text/plain text/css application/json application/javascript;

    # ===== upstream 块:定义后端服务器组 =====
    upstream backend {
        server 127.0.0.1:8080 weight=3 max_fails=3 fail_timeout=30s;
        server 127.0.0.1:8081 weight=1 backup;
        keepalive 32;
    }

    # ===== server 块:一个虚拟主机 =====
    server {
        listen       80;
        server_name  example.com www.example.com;
        root         /var/www/example;
        index        index.html index.htm;

        # ===== location 块:按 URI 匹配 =====
        location / {
            try_files $uri $uri/ =404;
        }

        location /api/ {
            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_connect_timeout 5s;
            proxy_read_timeout    60s;
        }

        location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
            expires 30d;
            access_log off;
        }
    }

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

要点清单:

  • main 块里没有 {} 包裹的指令就是全局指令,最外层。
  • events 和 http 只能在 main 下各出现一次(除非用 include 拆文件)。
  • server 必须在 http 内;location 必须在 server(或 location)内。
  • upstream 在 http 内,但不在 server 内。
  • Debian/Ubuntu 用 sites-available + sites-enabled 软链接管理站点;RHEL 系通常只用 conf.d/*.conf。两种约定本质相同,不要混用导致重复定义。

二、指令作用域对照表:写错位置是最常见错误

每条 Nginx 指令都有固定的允许上下文(context),放错会报 nginx: [emerg] "xxx" directive is not allowed here。下表列出高频指令的作用域。

指令maineventshttpserverlocation说明
worker_processes✅❌❌❌❌工作进程数,auto 为等于 CPU 核数
worker_connections❌✅❌❌❌单进程最大连接数
use epoll❌✅❌❌❌Linux 下默认 epoll,一般无需写
error_log✅❌✅✅✅作用域越小优先级越高
access_log❌❌✅✅✅可在 location 中 off 关闭
log_format❌❌✅❌❌只能在 http,这是最容易犯错的一条
include✅✅✅✅✅任意位置
server_name❌❌❌✅❌只能在 server 块
listen❌❌❌✅❌只能在 server 块
root / alias❌❌✅✅✅location 中常用
index❌❌✅✅✅—
try_files❌❌❌✅✅不能写在 http
proxy_pass❌❌❌✅✅location 中最常见
proxy_set_header❌❌✅✅✅数组型指令,子块会覆盖父块
client_max_body_size❌❌✅✅✅默认 1m,上传大文件必须调
gzip / gzip_types❌❌✅✅✅—
expires❌❌✅✅✅缓存控制头
upstream {}❌❌✅❌❌定义后端组
ssl_certificate❌❌✅✅❌—
if❌❌✅✅✅仅在某些模块上下文中安全,慎用

三、继承与覆盖规则:为什么子块里的配置"丢了父块的"

Nginx 的继承规则分两类,理解这一点能解决一半的配置困惑:

  • 普通(标量)指令:子块未声明时继承父块的值;子块声明则覆盖。例如 http 里 client_max_body_size 10m,server 不写就是 10m,写了就用自己的值。
  • 数组型指令(如 proxy_set_header、add_header、fastcgi_param、access_log 某些形式):子块一旦声明,完全替换父块的所有值,不合并。这是最经典的坑——server 里配了 3 条 proxy_set_header,location 里只写 1 条,结果那 3 条全没了。
nginx
http {
    add_header X-Frame-Options SAMEORIGIN;      # http 级别
    server {
        # 未声明 add_header → 继承 http 的 X-Frame-Options
        location /a/ {
            add_header X-Custom "1";            # 声明了 → X-Frame-Options 不再生效!
        }
    }
}

规避方法:在需要的每个子块里重复写全部头,或用 include 引入统一的头文件片段。

其他继承相关要点:

  • root 在 location 中若使用相对路径,是相对 server 的 root 拼接,容易出错,location 中建议写绝对路径。
  • error_log 和 access_log 是"就近覆盖"——定义了就用最内层的。
  • location 嵌套时,内层 location 完全独立继承 server 级配置,而不是继承外层 location。

四、location 匹配优先级:一张表定胜负

location 的匹配顺序是 Nginx 面试和排错的高频考点,规则是固定的:

  1. 先匹配精确匹配 location = /path,命中立即结束。
  2. 再匹配前缀匹配,记住"最长"的那个;若最长的前缀带 ^~,立即使用并结束。
  3. 若最长前缀没有 ^~,则按顺序尝试正则匹配(~ 大小写敏感、~* 不敏感),第一个命中的正则胜出。
  4. 正则都没命中,则使用第 2 步记住的最长前缀。
写法类型优先级示例与说明
location = /login精确匹配最高(命中即结束)只匹配 /login,不匹配 /login/
location ^~ /static/前缀匹配(禁止正则)次高匹配 /static/ 开头,且不再试正则
location ~ \.php$正则(大小写敏感)第三按配置中出现顺序匹配
`location ~* \.(png\jpg)$`正则(大小写不敏感)第三同上
location /api/普通前缀较长者优先无正则命中时使用
location /默认兜底最低所有请求最终都能落到这里

要点清单:

  • 正则 location 的顺序有意义,写在前面的先匹配;把具体规则写前面,通用规则写后面。
  • ^~ 是提升静态资源性能的常用手段,避免每个静态请求都跑一遍正则。
  • location /api/ 与 proxy_pass 结尾是否带 / 会导致 URI 拼接差异,见下文 FAQ。

五、rewrite、变量与日志格式

5.1 rewrite 与重定向

rewrite 用于改写 URI,return 用于直接返回状态码——能用 return 就不用 rewrite。

nginx
# 全站 HTTP 跳 HTTPS(推荐用 return,性能更好、语义清晰)
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

# rewrite 三要素:regex  replacement  flag
# flag: last(重新走 location 匹配) / break(停止 rewrite) / redirect(302) / permanent(301)
location /old/ {
    rewrite ^/old/(.*)$ /new/$1 permanent;
}

# 前端路由 SPA 的 history 模式兜底
location / {
    try_files $uri $uri/ /index.html;
}

常见 flag 对比:

flag行为典型用途
last改写后重新进入 location 匹配阶段内部重写,继续走 PHP 解析等
break改写后停止 rewrite 指令,仍在当前 location 处理静态文件重写
redirect返回 302 临时重定向临时跳转
permanent返回 301 永久重定向域名变更、HTTPS 强制跳转

5.2 常用内置变量

变量含义常见用途
$host请求头 Host(优先)或 server_name日志、proxy_set_header
$request_uri完整原始 URI 含查询串(不改)301 跳转保留参数
$uri当前规范化后的 URI(可能被改写)try_files
$remote_addr客户端 IP(直连时)日志、限流 key
$proxy_add_x_forwarded_for追加客户端 IP 到 XFF 链反代透传真实 IP
$request_method请求方法 GET/POST 等条件判断
$request_time请求总耗时(秒,毫秒精度)慢请求排查
$upstream_response_time上游响应耗时定位后端瓶颈
$status响应状态码日志、条件
$http_user_agentUA日志、爬虫识别
$args / $query_string查询串条件判断、重写

5.3 日志格式定制

nginx
# 只能写在 http 块中
log_format  detailed  escape=json  '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"request":"$request",'
    '"status":$status,'
    '"bytes":$body_bytes_sent,'
    '"referer":"$http_referer",'
    '"ua":"$http_user_agent",'
    '"request_time":$request_time,'
    '"upstream_time":"$upstream_response_time",'
    '"upstream_addr":"$upstream_addr"'
'}';

access_log  /var/log/nginx/access.log  detailed  buffer=64k flush=5s;

# 按状态码过滤:只记录 5xx 到单独文件(map 需在 http 块)
map $status $loggable {
    ~^5  1;
    default 0;
}
access_log /var/log/nginx/error-only.log detailed if=$loggable;

排查要点:$request_time 大而 $upstream_response_time 小,说明慢在 Nginx 自身或客户端网络;两者都大,说明慢在后端。

六、性能优化参数表与配置校验

Nginx 调优的核心参数集中在 events + http 两层,下表给出生产常用值。

参数作用域建议值作用与注意
worker_processesmainauto(等于 CPU 核数)超过核数不会更快,反而增加调度开销
worker_connectionsevents10240~65535最大并发 ≈ worker_processes × worker_connections / 2(反代时除以 4)
worker_rlimit_nofilemain65535必须 ≥ worker_connections,同时调系统 ulimit -n
use epolleventsepoll(Linux 默认)高并发下效率远高于 select
multi_accepteventson一次 accept 多个连接
sendfilehttp/server/locationon零拷贝发送静态文件
tcp_nopushhttpon与 sendfile 配合,减少小包
tcp_nodelayhttponkeepalive 下降低延迟
keepalive_timeouthttp60~75s太长会占用连接资源
keepalive_requestshttp1000~10000单连接最大请求数
client_max_body_sizehttp/server/location10m~100m默认仅 1m,上传必改
client_body_buffer_sizehttp128k~1m超过则写临时文件
gzip / gzip_comp_levelhttpon / 1~4压缩级别超过 4,CPU 换压缩率不划算
proxy_bufferinghttp/server/locationon(大文件下载关)关闭会导致后端连接长时间占用
proxy_read_timeoutlocation60s(长轮询按需调大)太短会 504
open_file_cachehttpmax=10000 inactive=60s缓存文件描述符,静态站提升明显
server_tokenshttpoff隐藏版本号,安全加固

配置校验与热加载(每次改配置的标准动作):

bash
# 1. 语法校验,-t 会输出配置文件路径与是否 OK
sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 2. 校验指定的非默认配置文件(-c 指定主配置)
sudo nginx -t -c /etc/nginx/nginx.conf

# 3. 热加载:master 进程重新读配置,平滑替换 worker,不断连接
sudo nginx -s reload
# 等价:sudo systemctl reload nginx

# 4. 其他信号
sudo nginx -s reopen    # 重新打开日志文件(日志切割后)
sudo nginx -s quit      # 优雅停止(处理完当前请求)
sudo nginx -s stop      # 立即停止

# 5. 修改配置后忘记 reload 是最常见的"改了没生效"原因