Nginx

Nginx 配置常用参数详解

原创2026-08-07艾思特码记约 13 分钟阅读
Nginx 配置常用参数详解


写 Nginx 配置,最头疼的不是语法,而是 “我的请求到底走到了哪一步”。看了几篇博客,抄了几段配置,上线就挂。

今天把 Nginx 配置文件的核心参数从头捋一遍。从 server 块的五个核心指令、location 匹配优先级、try_files 万能公式,到 if 指令的注意事项和 proxy_pass 的反斜杠陷阱。

一、server 块的五个核心指令

一个 server 块,记住这五个就够了:

server {
    listen       80;                    # 监听端口
    server_name  example.com;           # 域名匹配
    root         /var/www;              # 文件根目录
    index        index.html;            # 默认首页
    location { }                        # 路由规则(核心)
}

listen 支持多个端口、IP 绑定、SSL:

listen 80;
listen 443 ssl;
listen 8081 default_server;            # 兜底 server

server_name 支持通配和正则:

server_name  example.com  *.example.com  ~^www\.(?.+)\.example\.com$;


二、location 匹配优先级

这是最容易搞混的地方。优先级从高到低:

写法含义优先级
`location = /page`精确匹配最高
`location ^~ /img/`前缀匹配,不检查正则次高
`location ~ \.jpg$`正则匹配(区分大小写)
`location ~* \.jpg$`正则匹配(不区分大小写)
`location /abc/`普通前缀匹配

关键规则

1. = 优先于一切

location = / { return 200 "exact\n"; }      # / → 命中
location / { return 200 "default\n"; }       # /anything → 命中

2. ^~ 赢了所有正则

location ^~ /img/ { return 200 "prefix\n"; }       # /img/logo.png → 命中
location ~ \.png$ { return 200 "regex\n"; }         # 不会命中

3. 多个正则只取第一个

location ~ /a { return 200 "a\n"; }         # 命中
location ~ /ab { return 200 "ab\n"; }       # 永远不会命中

记忆口诀:等号最贵,波浪第二,正则取第一个,前缀排最后。



三、`try_files` — 万能公式

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

这是 WordPress / Laravel / 所有 PHP 框架的伪静态标配。

`try_files` 的工作原理

  1. **`$uri`** → 检查本地有没有这个文件(如 `/robots.txt`)
  2. **`$uri/`** → 没有的话检查本地有没有这个目录(如 `/about/`)
  3. **`/index.php?$query_string`** → 都没找到,把请求交给 `index.php`,把原始 query string 透传过去

最后一项必须是 `=404` 或有效路径

# 错误写法,最后一项没有 =404
location / {
    try_files $uri $uri/ /index.php?$args;
}

如果 /index.php 不存在(比如纯静态站),请求会进入无限递归,最终 500。

# 正确写法
location / {
    try_files $uri $uri/ /index.php?$args =404;
}


四、`if` 的注意事项

Nginx 官方文档有句话:"if is evil"。不是不能用,是要知道它的行为。

`if` 的匹配是顺序执行的

# 想排除 /admin,但不行
location / {
    if ($uri ~ "^/admin") {
        return 403;
    }
    root /var/www;
}

这段代码 不会生效——if 块里的 root 指令会被提升到 http 块作用域。

正确用法:`if` 只用于 return / rewrite / set

# 正确:set 变量
if ($http_user_agent ~* "bot|spider") {
    set $sp_go 1;
}

# 正确:return 状态码
if ($host = "old.example.com") {
    return 301 https://new.example.com$request_uri;
}

# 正确:rewrite
if ($sp_go = 1) {
    rewrite ^ /__sp_proxy$request_uri last;
}

实战:爬虫代理 + WordPress 白名单

这是我正在用的一个真实配置,把蜘蛛流量代理到主站,真人走本地 WordPress,同时不拦截 WordPress API 和后台:

set $sp_go 0;

# 蜘蛛任意路径 → 代理
if ($http_user_agent ~* "bot|spider") {
    set $sp_go 1;
}

# 真人 + 本地无文件 → 代理
if (!-e $request_filename) {
    set $sp_go 1;
}

# WordPress 路由走本地 PHP,不走代理
# 注意:这段必须放在上面两个 if 之后,后设覆盖先设
if ($uri ~ "^/(wp-json|wp-admin|wp-content|wp-includes)") {
    set $sp_go 0;
}

# 最终判断
if ($sp_go = 1) {
    rewrite ^ /__sp_proxy$request_uri last;
}

# 代理 location
location ^~ /__sp_proxy/ {
    rewrite ^/__sp_proxy/(.*)$ /$1 break;
    proxy_pass http://brandhd.com;
    proxy_set_header Host brandhd.com;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_redirect off;
    proxy_connect_timeout 15s;
    proxy_send_timeout 30s;
    proxy_read_timeout 60s;
}

核心逻辑: Nginx 的 if 按顺序执行,最后一个 set 决定最终值。WordPress 白名单的 set $sp_go 0 覆盖前面的 set $sp_go 1,实现"优先走代理,但 WordPress 路由例外"。



五、`proxy_pass` 的反斜杠陷阱

这是最容易踩的坑,一个 / 之差,请求路径完全不同。

# 尾部有 / → 去掉匹配部分
location /api/ {
    proxy_pass http://127.0.0.1:8080/;
    # /api/user → upstream 收到 /user
}

# 尾部无 / → 完整传递
location /api/ {
    proxy_pass http://127.0.0.1:8080;
    # /api/user → upstream 收到 /api/user
}

对比

配置请求upstream 收到
`proxy_pass .../;``/api/user``/user`
`proxy_pass ...;``/api/user``/api/user`

记住一个原则:proxy_pass 末尾有没有斜杠,决定了 location 匹配的部分是否被去掉。



六、`root` vs `alias`

另一个经典混淆:

# root:拼接
location /img/ {
    root /data;
    # /img/logo.png → 读 /data/img/logo.png
}

# alias:替换
location /img/ {
    alias /data/images/;
    # /img/logo.png → 读 /data/images/logo.png
}

alias 只能用在 location 块,不能用在 if 块。



七、常用内置变量速查

所有 $ 开头的变量都是 Nginx 内置的,不需要定义:

变量含义例子
`$uri`当前 URI(不含参数)`/page?id=1` → `/page`
`$request_uri`完整原始 URI`/page?id=1` → `/page?id=1`
`$query_string`查询参数部分`id=1`
`$scheme`协议`https`
`$http_host`请求头 Host`example.com`
`$remote_addr`客户端 IP`1.2.3.4`
`$request_filename``root` + `$uri` 拼出的完整路径`/data/page.html`
`$request_method`请求方法`GET`
`$status`响应状态码`200`
`$time_local`本地时间`06/Aug/2026:15:00:00 +0800`

完整变量列表(70+ 个):Nginx 官方文档



八、其他常用指令

access_log / error_log

# 关闭访问日志(大流量站点省磁盘)
access_log off;

# 写入指定文件
access_log /var/log/nginx/access.log;
error_log  /var/log/nginx/error.log warn;

expires 静态资源缓存

location ~* \.(jpg|png|css|js|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

gzip 压缩

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

限制并发

# 在 http 块定义
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# 在 server/location 块使用
limit_req zone=api burst=20 nodelay;


写在最后

Nginx 配置说到底就一个核心:请求来了,它走到哪个 location,然后发生了什么。

server → location → try_files/proxy_pass/rewrite 这条主干搞熟,其他都是加调料。上面这些参数,够日常运维 90% 的场景了。