FORMA

配置文件结构与语法

下面我们深入到 Nginx 的配置核心——配置文件的结构、语法和变量系统。这一部分是你驾驭 Nginx 的“语法手册”。

一、分层结构:从全局到局部

Nginx 的配置文件采用块指令嵌套的树形结构,理解从外到内的层次是阅读和编写配置的基础。

nginx
# 1. 全局块 (main context)
...                      # 影响服务器整体运行的指令

events {                 # 2. events 块
    ...                  # 控制连接处理方式
}

http {                   # 3. http 块
    ...                  # HTTP 模块的全局配置
    
    server {             # 4. server 块 (虚拟主机)
        ...              
        
        location / {     # 5. location 块 (URI 匹配)
            ...
        }
        
        if (条件) {      # 6. if 块 (慎用)
            ...
        }
    }
}
  • 全局块(main):最外层,包含 userworker_processeserror_logpid 等。这些指令不隶属于任何模块块。
  • events 块:专门配置连接处理,最关键的指令是 worker_connections
  • http 块:所有 HTTP 核心功能的总容器,可包含多个 server 块。这里配置 upstreamaccess_log 格式、gzipproxy_cache 等公用功能。
  • server 块:定义一个虚拟主机,基于监听端口和域名区分。
  • location 块:根据请求 URI 匹配特定路径,执行最终的处理逻辑。
  • if 块:放置在 serverlocation 内部,用于条件判断。但它的工作模型与声明式配置不同,容易引发“诡异”行为,非必要不使用,优先用 try_filesreturnrewritemap 替代

二、指令与上下文

1. 指令语法

每行一个指令,以分号结尾。格式为:

nginx
指令名 参数1 参数2 ...;

例如:

nginx
worker_connections  1024;           # 简单指令
listen              80 default_server;  # 带多个值
proxy_set_header    Host $host;     # 可引用变量

块指令用大括号包裹,内部可包含多条指令,如 server { ... }

2. 上下文

每个指令都有其合法上下文,即它只能出现在特定的块中。这是最易出错的地方,必须掌握规则:

上下文特点与常见指令
mainuser, worker_processes, error_log, pid, include
events仅能出现在 events{} 中,如 worker_connections, use, multi_accept
httpserver, upstream, map, access_log, gzip
serverlisten, server_name, root, index, try_files,以及 location, if
location大部分具体处理指令:proxy_pass, fastcgi_pass, rewrite, return, add_header,也可嵌套 locationif
if只能出现在 serverlocation 中,可使用 set, return, rewrite,但不能包含 try_files, proxy_pass 等(可能导致意外)

典型错误示例:在 location 里写 worker_connections 或者把 server 块直接放在 events 后面——这些都会导致 nginx -t 测试失败。合理的使用方式是心中始终有一张“指令-上下文”映射表,不清楚时查阅官方文档。


三、include 机制与配置拆分

include 能将公共配置分片,便于维护。

1. 基本用法

nginx
include /etc/nginx/mime.types;        # 包含单个文件
include /etc/nginx/conf.d/*.conf;     # 包含目录下所有 .conf 文件
include /etc/nginx/sites-enabled/*;   # 包含目录下所有文件(通常是符号链接)

被 include 的文件内容会原地展开,遵守同样的上下文规则。所以你不能在 http 外部 include 一个包含 server 块的配置文件。

2. sites-available / sites-enabled 模式

这是 Debian/Ubuntu 系列发行版推荐的管理方式,也在许多自定义部署中被采用。

  • 目录结构:
    • /etc/nginx/sites-available/:存放所有站点配置,无论启用与否。
    • /etc/nginx/sites-enabled/:存放指向 sites-available 中文件的符号链接,只有被链接的站点才生效。
  • 主配置引入:/etc/nginx/nginx.confhttp 块末尾会有一行:
    nginx
    include /etc/nginx/sites-enabled/*;
    
  • 操作方式:
    bash
    # 创建一个可用站点配置
    vim /etc/nginx/sites-available/example.conf
    # 启用该站点
    ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/
    # 禁用只需删除符号链接
    rm /etc/nginx/sites-enabled/example.conf
    # 重载配置
    nginx -s reload
    

这种模式使站点管理非常清晰,且不会因为移动文件而丢失配置,非常适合多站点环境。


四、Nginx 变量体系

变量是 Nginx 灵活性的灵魂,它们贯穿于日志记录、URL 重写、请求头传递等各个方面。

1. 内置变量(可直接使用)

变量名含义与注意事项
$uri当前请求的 URI,经过解码,且可能被 rewrite 改变过,不包含参数
$request_uri原始请求 URI,未经解码,且永远不变,包含参数(如 /page?foo=bar
$host请求头中的 Host 字段,若无则为虚拟主机名;最适合做主机判断
$http_host原始请求头中的 Host,其值格式完全遵照客户端发送的内容
$remote_addr客户端 IP 地址
$proxy_add_x_forwarded_for记录请求经过的代理链路,追加客户端 IP,防止覆盖
$argsURL 中的参数字符串(不含问号)
$query_string$args
$scheme请求协议(http 或 https)
$request_method请求方法(GET、POST 等)
$server_name当前匹配的 server_name 值
$document_root当前请求的 root 指令的最终值
$uri注意:若 URL 重写发生,$uri 会变成重写后的路径

对比 $uri$request_uri 的经典差异:

  • 请求:/user/login?next=/admin
  • $uri 可能是 /user/login(经过 rewrite 可能变成 /app.php
  • $request_uri 永远是 /user/login?next=/admin

2. 自定义变量

  • set 指令
    serverlocationif 块内向变量动态赋值。
    nginx
    set $mobile_label "desktop";
    if ($http_user_agent ~* "(Android|iPhone)") {
        set $mobile_label "mobile";
    }
    

    变量值对后续的所有操作立即可见。
  • map 指令
    http 块中创建静态映射表,根据一个变量的值生成另一个变量,效率远高于 if
    nginx
    map $host $backend {
        default          backend_default;
        api.example.com  backend_api;
        admin.example.com backend_admin;
    }
    

    之后可直接使用 $backend 变量,例如 proxy_pass http://$backend;

3. 变量的实际应用

  • 日志定制
    定义详细的访问日志格式,排查问题必备。
    nginx
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';
    access_log /var/log/nginx/access.log main;
    
  • URL 改写(rewrite)
    根据条件做出重定向或内部跳转。
    nginx
    rewrite ^/old-path/(.*)$ /new-path/$1 permanent;   # 使用变量 $1 捕获分组
    if ($scheme = http) {
        rewrite ^ https://$host$request_uri? permanent; # 强制 HTTPS
    }
    
  • 反向代理头传递
    将客户端真实信息透传给后端。
    nginx
    location / {
        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_pass http://backend;
    }
    
  • 动态路由
    例如根据 Cookie 或地区匹配合适的后端:
    nginx
    map $cookie_region $upstream {
        default us_backend;
        EU       eu_backend;
        ASIA     asia_backend;
    }
    

掌握配置文件的分层结构、指令上下文规则、include 拆分模式以及变量系统,你就已经具备了读懂任意 Nginx 配置并按照需求自由组合的能力。后面的日志、优化、安全等功能,都是在这一骨架之上添加血肉。

参考文献

资料说明
nginx 文档官方
运维导读学习路径