2.1 配置语言的三个基本单位
Nginx 配置由三种东西组成:指令、块(block/context)、注释。
- 指令(Directive)
- 一条以分号结尾的语句,形如
指令名 参数;。例如worker_processes auto;。分为"简单指令"(单行)和"块指令"(带{ })。 - 块 / 上下文(Block / Context)
- 用
{ }包裹的一组指令,如http { ... }。块可以嵌套,形成层级;内层继承外层的配置。 - 指令继承(Inheritance)
- 子块自动继承父块的指令值,除非子块自己重新声明覆盖。这让你能在 http 层设默认、在 server/location 层微调。
- include
- 把另一个文件的内容原地插入当前位置,用于把庞大的配置拆成多个小文件。支持通配符
include conf.d/*.conf;。 - 变量(Variable)
- 以
$开头的运行时值,如$host、$uri、$remote_addr。可用于日志、if 判断、代理头传递等。 - 平滑重载(Graceful Reload)
- Nginx 收到 reload 信号后,master 加载新配置、启动新 worker,旧 worker 处理完当前连接后退出,全程不断开正在服务的连接。
2.2 context 层级全景
配置文件由外到内是嵌套的上下文。记住这张"树",你就不会在错误的层级写错误的指令:
# nginx.conf 的骨架
# --- main context(文件最外层,无大括号)---
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events { # --- events:连接处理层 ---
worker_connections 1024;
multi_accept on;
}
http { # --- http:所有 HTTP 相关 ---
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream backend { # --- upstream:后端组 ---
server 127.0.0.1:3000;
}
server { # --- server:一个虚拟主机 ---
listen 80;
server_name example.com;
location / { # --- location:一条 URL 规则 ---
root /var/www/html;
}
}
}
| Context | 职责 | 常见指令 |
|---|---|---|
| main | 进程级全局设置 | user, worker_processes, error_log, pid |
| events | 连接处理机制 | worker_connections, use, multi_accept |
| http | HTTP 全局默认 | include, sendfile, gzip, log_format |
| upstream | 定义后端服务器组 | server, least_conn, keepalive |
| server | 一个虚拟主机 | listen, server_name, ssl_certificate |
| location | 匹配 URI 的处理规则 | root, alias, proxy_pass, try_files |
2.3 main context:进程与全局
# worker 进程数:auto = CPU 核心数,最常用
worker_processes auto;
# 每个 worker 能打开的文件描述符上限
worker_rlimit_nofile 65535;
# worker 运行的用户/组(降权,安全)
user www-data;
# 全局错误日志与级别:debug|info|notice|warn|error|crit
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
理论最大并发连接 ≈ worker_processes × worker_connections。8 核 × 1024 = 8192。做反向代理时,一个客户端连接还要占一个到后端的连接,实际有效值要打对折。高并发场景把 worker_connections 提到 8192 甚至更高,同时确保 worker_rlimit_nofile 够大。
2.4 http context:定义默认行为
http {
# 引入 MIME 类型映射(决定 Content-Type)
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"';
access_log /var/log/nginx/access.log main;
# 静态文件零拷贝发送
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
# 把站点配置拆到独立文件
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
2.5 用 include 拆分配置
把所有站点都堆在一个 nginx.conf 里会变得难以维护。惯用做法是主配置只放全局设置,每个站点单独一个文件:
# /etc/nginx/conf.d/blog.conf —— 独立站点文件
server {
listen 80;
server_name blog.example.com;
root /var/www/blog;
# 复用公共片段:安全头、gzip 等
include /etc/nginx/snippets/security-headers.conf;
location / {
try_files $uri $uri/ =404;
}
}
include 出现在哪个 context,被引入文件里的指令就必须在那个 context 合法。在 http 层 include 的文件应放 server{};在 server 层 include 的文件应放 location{} 或简单指令。放错层级会报 "directive is not allowed here"。
2.6 常用内置变量
| 变量 | 含义 |
|---|---|
$host | 请求的主机名(Host 头,或 server_name) |
$uri | 规范化后的当前 URI(不含查询串) |
$request_uri | 原始完整请求 URI(含查询串) |
$args | 查询字符串(问号后面的部分) |
$remote_addr | 客户端 IP |
$scheme | 协议:http 或 https |
$request_method | 请求方法:GET/POST/... |
$http_user_agent | 请求头 User-Agent(任意 $http_xxx) |
# 变量用于条件重定向:把所有非 www 跳到 www
server {
listen 80;
server_name example.com;
return 301 $scheme://www.example.com$request_uri;
}
2.7 reload 是怎么做到不断线的
当你执行 nginx -s reload,发生的事情如下:
- master 进程重新读取并校验新配置(校验失败则保留旧配置,reload 无效)。
- 校验通过后,master 用新配置启动一批新 worker。
- master 向旧 worker 发信号,让它们停止接受新连接。
- 旧 worker 把手头正在处理的连接跑完后,自行退出。
整个过程新旧 worker 短暂并存,正在传输的请求不会被打断——这就是"平滑"。因此生产环境改配置几乎总是用 reload 而非 restart。
某些改动(如修改 worker_processes、切换事件模型)reload 不一定完全生效,需要 restart。此外若新配置绑定了一个已被占用的端口,reload 会失败。生产变更前务必 nginx -t。
2.8 小结与下一步
- 配置 = 指令 + 块 + 注释;块按 main → events → http → server → location 层层嵌套,内层继承外层。
- main 管进程,events 管连接,http 定默认,server 是虚拟主机,location 是 URL 规则。
- 用 include 把站点拆成独立文件,配合 snippets 复用公共片段。
- 内置变量(
$host/$uri/$remote_addr...)是配置的"运行时数据"。 - 下一章深入 server 与 location——虚拟主机匹配与最让人困惑的 location 优先级。