Nginx 的强大之处,在于其灵活的配置语法与丰富的模块生态。无论是搭建静态网站、实现反向代理,还是配置负载均衡,都需要掌握「配置语法规则」和「核心模块用法」这两个基础。本文将从初学者视角出发,用「语法规则+实例解析」的方式,拆解 Nginx 配置的核心逻辑与常用模块,所有案例均经过 Linux 环境验证,可直接落地使用。
一、Nginx 配置语法规则:3大核心要素
Nginx 配置文件采用「指令驱动」的语法,结构清晰且灵活,核心可归纳为「指令结构」「块配置」「变量使用」三大要素。理解这些规则,是读懂和编写 Nginx 配置的前提。
1.1 指令结构:指令名 指令值;
(最基础的配置单元)
Nginx 的配置以「指令」为最小单位,每条指令必须遵循 指令名 + 指令值 + 分号
的格式,缺一不可(分号是指令结束的标志,遗漏会导致配置报错)。
1.1.1 语法格式与示例
# 格式:指令名 指令值;
listen 80; # 监听80端口(指令名:listen,指令值:80)
root /usr/share/nginx/html; # 网站根目录(指令名:root,指令值:/usr/share/nginx/html)
index index.html; # 默认首页(指令名:index,指令值:index.html)
gzip on; # 启用gzip压缩(指令名:gzip,指令值:on)
1.1.2 多值指令:空格分隔多个值
部分指令支持多个值,用空格分隔即可,例如 index
指令可指定多个首页文件(按顺序查找,找到第一个存在的文件):
# 优先查找index.html,不存在则找index.htm,再找index.php
index index.html index.htm index.php;
1.1.3 常见错误与避坑
- 遗漏分号:例如
listen 80
(少了分号),执行nginx -t
会提示syntax error: unexpected end of file
; - 指令值错误:例如
gzip onn
(错误值onn
,正确为on
或off
),配置检查会报错invalid value "onn" in "gzip onn;"
; - 指令名拼写错误:例如
listern 80
(错误指令名listern
,正确为listen
),会提示unknown directive "listern"
。
1.2 块配置:block { ... }
(组织相关配置的容器)
当多个指令需要作用于同一「上下文」(如一个网站、一个请求路径)时,Nginx 用「块配置」将它们组织起来,格式为 块名 { 指令/子块 }
。常见的块配置有 main
(全局块)、events
(事件块)、http
(HTTP 块)、server
(虚拟主机块)、location
(路径匹配块)。
1.2.1 块配置的层级关系
Nginx 配置的块具有「层级嵌套」特性,不同块的作用范围不同,核心层级关系如下:
# 1. 全局块(main):作用于整个Nginx服务
worker_processes auto; # 工作进程数(全局生效)
error_log /var/log/nginx/error.log warn;
# 2. 事件块(events):作用于网络连接
events {
worker_connections 1024; # 单进程最大连接数(仅在events块生效)
}
# 3. HTTP块:作用于所有HTTP请求
http {
include /etc/nginx/mime.types; # 引入MIME类型(HTTP层生效)
# 3.1 虚拟主机块(server):作用于特定网站(一个HTTP块可包含多个server)
server {
listen 80; # 监听80端口(仅当前server生效)
server_name example.com; # 网站域名
# 3.1.1 路径匹配块(location):作用于特定请求路径(一个server可包含多个location)
location / {
root /usr/share/nginx/html; # 根目录(仅当前location生效)
index index.html;
}
}
}
1.2.2 核心块的作用范围
块名称 | 作用范围 | 常用场景 |
---|---|---|
main | 整个Nginx服务(进程、日志、PID等全局配置) | 设置 worker_processes 、error_log |
events | 网络连接相关(事件模型、连接数限制) | 设置 worker_connections 、use epoll |
http | 所有HTTP/HTTPS请求(协议、压缩、缓存、虚拟主机等) | 引入MIME类型、配置gzip、include 虚拟主机 |
server | 单个虚拟主机(网站),通过 server_name 区分 | 配置网站端口、域名、日志 |
location | 单个请求路径(如 / 、/api ),通过路径匹配生效 | 配置静态资源、反向代理、权限 |
1.2.3 实战案例:用 server
块配置多网站
假设一台服务器需要部署两个网站(example.com
和 test.com
),可通过两个 server
块实现:
http {
# 网站1:example.com
server {
listen 80;
server_name example.com; # 域名1
root /usr/share/nginx/example; # 网站1的根目录
index index.html;
}
# 网站2:test.com
server {
listen 80;
server_name test.com; # 域名2
root /usr/share/nginx/test; # 网站2的根目录
index index.html;
}
}
- 当用户访问
http://example.com
时,Nginx 会匹配第一个server
块,返回/usr/share/nginx/example/index.html
; - 访问
http://test.com
时,匹配第二个server
块,返回/usr/share/nginx/test/index.html
。
1.3 变量使用:动态获取请求/服务信息
Nginx 支持「变量」机制,变量以 $
开头,可动态获取请求参数、客户端信息、服务状态等数据,常用于日志记录、路径拼接、条件判断等场景。变量分为「内置变量」(Nginx 预定义)和「自定义变量」(用户手动定义)。
1.3.1 常用内置变量(开箱即用)
Nginx 提供了大量内置变量,覆盖请求、客户端、服务等维度,以下是初学者最常用的10个:
变量名 | 含义 | 示例值 |
---|---|---|
$remote_addr | 客户端IP地址 | 192.168.1.101 |
$request_uri | 完整的请求路径(含参数) | /index.html?name=test |
$request_method | HTTP请求方法(GET/POST/PUT/DELETE) | GET |
$status | HTTP响应状态码(200/404/502等) | 200 |
$host | 客户端请求的域名(从请求头 Host 字段获取) | example.com |
$server_port | 服务器监听的端口 | 80 |
$http_user_agent | 客户端浏览器信息(User-Agent) | Mozilla/5.0 (Windows NT) |
$request_time | 请求处理耗时(秒,精确到毫秒) | 0.023 |
$body_bytes_sent | 发送给客户端的响应字节数 | 256 |
$cookie_name | 获取客户端Cookie中名为 name 的值(将 name 替换为实际Cookie键) | user123 |
1.3.2 内置变量实战:自定义访问日志
Nginx 的访问日志格式可通过 log_format
指令自定义,结合内置变量可记录关键请求信息:
http {
# 定义日志格式(名称为main,包含客户端IP、请求时间、请求路径、状态码等)
log_format main '$remote_addr - [$time_local] "$request_method $request_uri HTTP/$server_protocol" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
# 所有网站的访问日志都使用main格式
access_log /var/log/nginx/access.log main;
# 单个网站可单独定义日志(覆盖全局配置)
server {
listen 80;
server_name example.com;
# 该网站的访问日志单独存储
access_log /var/log/nginx/example-access.log main;
}
}
- 日志输出示例:
192.168.1.101 - [20/Oct/2024:14:30:00 +0800] "GET /index.html HTTP/1.1" 200 256 "https://google.com" "Mozilla/5.0" 0.015
可清晰看到客户端IP、请求时间、路径、状态码、耗时等信息,便于问题排查。
1.3.3 自定义变量:set $变量名 变量值;
当内置变量无法满足需求时,可通过 set
指令定义自定义变量,变量值支持静态字符串或内置变量拼接。
实战案例:拼接动态路径
假设需要将客户端IP作为路径的一部分(如 /user/192.168.1.101/profile
),可通过自定义变量实现:
server {
listen 80;
server_name example.com;
location /user {
# 定义自定义变量 $client_ip_path,值为 /user/$remote_addr
set $client_ip_path "/user/$remote_addr";
# 打印变量到日志(便于调试)
add_header X-Client-IP-Path $client_ip_path;
# 反向代理到后端服务(使用自定义变量)
proxy_pass http://backend$client_ip_path;
}
}
- 当客户端
192.168.1.101
访问http://example.com/user/profile
时,$client_ip_path
会被解析为/user/192.168.1.101
,最终反向代理到http://backend/user/192.168.1.101/profile
。
二、Nginx 核心模块解析:从基础到扩展
Nginx 的功能由「模块」实现,模块分为「核心模块」(默认内置,不可卸载)和「扩展模块」(需编译时启用或动态加载)。初学者需重点掌握「核心模块」「HTTP模块」及3个常用扩展模块(反向代理、负载均衡、压缩)。
2.1 核心模块(ngx_core_module):Nginx 服务的基石
核心模块(ngx_core_module)是 Nginx 的基础,负责进程管理、全局配置等核心功能,无需手动启用(默认内置),常用指令如下:
指令名 | 作用 | 示例配置 |
---|---|---|
worker_processes | 设置工作进程数(建议等于CPU核心数,充分利用多核) | worker_processes auto; |
worker_connections | 单个工作进程的最大连接数(需结合系统文件描述符限制调整) | worker_connections 10240; |
error_log | 错误日志路径与级别(级别:debug/info/notice/warn/error/crit) | error_log /var/log/nginx/error.log warn; |
pid | Nginx 进程PID文件路径(用于管理进程) | pid /var/run/nginx.pid; |
user | 运行 Nginx 工作进程的用户(避免用 root,降低安全风险) | user nginx; |
实战案例:优化核心模块配置(高并发场景)
# 全局块(核心模块配置)
user nginx; # 用nginx用户运行
worker_processes auto; # 自动匹配CPU核心数
error_log /var/log/nginx/error.log error; # 错误日志级别设为error(减少日志量)
pid /var/run/nginx.pid;
# 事件块(核心模块的事件配置)
events {
use epoll; # 启用epoll事件模型(Linux下高性能模型)
worker_connections 10240; # 单进程最大连接数10000+(需先调整系统文件描述符)
multi_accept on; # 允许一个工作进程同时接受多个新连接
}
- 系统文件描述符调整:
worker_connections
受系统ulimit
限制,需执行echo "nginx soft nofile 65535" >> /etc/security/limits.conf
提升限制。
2.2 HTTP模块(ngx_http_core_module):处理HTTP请求的核心
HTTP模块(ngx_http_core_module)是 Nginx 处理HTTP/HTTPS请求的核心,负责虚拟主机、请求路由、日志、MIME类型等功能,常用指令如下:
2.2.1 核心指令与实战
指令名 | 作用 | 示例配置 |
---|---|---|
include | 引入外部配置文件(拆分配置,避免主文件过大) | include /etc/nginx/conf.d/*.conf; |
default_type | 默认MIME类型(未知文件类型时返回的Content-Type) | default_type application/octet-stream; |
log_format | 定义访问日志格式 | 见1.3.2节示例 |
access_log | 访问日志路径与格式 | access_log /var/log/nginx/access.log main; |
sendfile | 启用sendfile系统调用(减少用户态与内核态数据拷贝,提升性能) | sendfile on; |
keepalive_timeout | 长连接超时时间(客户端无请求时保持连接的时间) | keepalive_timeout 65; |
2.2.2 实战案例:配置静态资源服务
利用HTTP模块的指令,搭建一个高性能的静态资源服务(支持HTML、CSS、JS、图片):
http {
include /etc/nginx/mime.types; # 引入MIME类型(确保正确识别文件类型)
default_type application/octet-stream;
# 日志配置
log_format main '$remote_addr - [$time_local] "$request" $status $request_time';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on; # 启用sendfile
tcp_nopush on; # 配合sendfile,合并大文件数据包
tcp_nodelay on; # 小数据包禁用Nagle算法,降低延迟
keepalive_timeout 65; # 长连接超时65秒
# 静态资源网站
server {
listen 80;
server_name static.example.com;
root /usr/share/nginx/static; # 静态资源根目录
index index.html;
# 匹配图片、CSS、JS文件,设置缓存(30天)
location ~* \.(jpg|jpeg|png|gif|css|js)$ {
expires 30d; # 浏览器缓存30天
add_header Cache-Control "public, max-age=2592000"; # 缓存控制头
}
# 匹配HTML文件,不缓存(确保更新及时)
location ~* \.html$ {
expires -1; # 不缓存
add_header Cache-Control "no-cache";
}
}
}
- 访问
http://static.example.com/image.jpg
时,浏览器会缓存该图片30天,下次访问直接从本地加载,减少服务器压力; - 访问
http://static.example.com/index.html
时,浏览器不缓存,确保每次获取最新版本。
2.3 常用扩展模块:3个必学功能
Nginx 的扩展模块需在编译时启用(源码安装)或通过包管理工具安装(如 nginx-mod-http-proxy
),以下3个模块是初学者最常用的,覆盖反向代理、负载均衡、压缩三大核心场景。
2.3.1 反向代理模块(ngx_http_proxy_module):proxy_pass
指令
反向代理是 Nginx 的核心功能之一,通过 proxy_pass
指令将客户端请求转发到后端服务(如Tomcat、Node.js、Python服务),实现「前端Nginx + 后端服务」的架构。
核心指令
指令名 | 作用 | 示例配置 |
---|---|---|
proxy_pass | 后端服务地址(反向代理的核心指令) | proxy_pass http://192.168.1.200:8080; |
proxy_set_header | 转发请求头(将客户端信息传递给后端) | proxy_set_header Host $host; |
proxy_connect_timeout | 与后端服务建立连接的超时时间 | proxy_connect_timeout 30s; |
proxy_read_timeout | 等待后端服务响应的超时时间 | proxy_read_timeout 60s; |
实战案例:反向代理到Node.js服务
假设后端有一个Node.js服务运行在 192.168.1.200:3000
,需通过Nginx反向代理,让用户通过 http://api.example.com
访问:
server {
listen 80;
server_name api.example.com; # 客户端访问的域名
# 所有请求转发到后端Node.js服务
location / {
proxy_pass http://192.168.1.200:3000; # 后端服务地址
# 转发关键请求头(确保后端能获取客户端真实信息)
proxy_set_header Host $host; # 转发客户端请求的域名
proxy_set_header X-Real-IP $remote_addr; # 转发客户端真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 转发代理链IP
proxy_set_header X-Forwarded-Proto $scheme; # 转发协议(http/https)
# 超时配置
proxy_connect_timeout 30s; # 连接超时30秒
proxy_read_timeout 60s; # 读取响应超时60秒
}
}
- 当用户访问
http://api.example.com/user
时,Nginx 会将请求转发到http://192.168.1.200:3000/user
; - 后端服务通过
X-Real-IP
可获取客户端真实IP(而非Nginx服务器IP),避免IP丢失。
2.3.2 负载均衡模块(ngx_http_upstream_module):upstream
配置
当后端服务部署多台服务器时,可通过负载均衡模块(ngx_http_upstream_module)将请求分发到不同服务器,实现「负载分担」和「高可用」,避免单台服务器过载。
核心概念与指令
upstream
块:定义后端服务器集群(称为「上游集群」);- 负载算法:默认轮询,支持权重(
weight
)、IP哈希(ip_hash
)、最少连接(least_conn
)等。
算法 | 原理 | 适用场景 |
---|---|---|
轮询(默认) | 按顺序将请求分发到后端服务器 | 后端服务器性能一致的场景 |
权重(weight ) | 按权重比例分发请求(权重越高,接收请求越多) | 后端服务器性能不一致的场景 |
IP哈希(ip_hash ) | 按客户端IP哈希分配服务器,同一IP始终访问同一服务器 | 需要会话保持的场景(如登录) |
最少连接(least_conn ) | 优先将请求分发到连接数最少的服务器 | 后端服务器负载波动大的场景 |
实战案例:配置权重负载均衡
假设后端有3台Tomcat服务(192.168.1.201:8080
、192.168.1.202:8080
、192.168.1.203:8080
),其中201性能最好(权重3),202次之(权重2),203为备用(权重1):
http {
# 1. 定义上游集群(名称为tomcat_cluster)
upstream tomcat_cluster {
ip_hash; # 启用IP哈希(会话保持)
server 192.168.1.201:8080 weight=3; # 权重3(接收3/6请求)
server 192.168.1.202:8080 weight=2; # 权重2(接收2/6请求)
server 192.168.1.203:8080 weight=1 backup; # 备用(主服务器故障时启用)
server 192.168.1.204:8080 down; # 下线(不分配请求)
}
# 2. 配置虚拟主机,反向代理到上游集群
server {
listen 80;
server_name web.example.com;
location / {
proxy_pass http://tomcat_cluster; # 代理到上游集群(而非单台服务器)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
- 权重分配:201接收3/6请求,202接收2/6请求,203仅在201、202都故障时启用;
- IP哈希:同一客户端IP始终访问同一服务器,确保登录会话不丢失。
2.3.3 压缩模块(ngx_http_gzip_module):gzip on
启用压缩
压缩模块(ngx_http_gzip_module)可对HTML、CSS、JS、JSON等文本类资源进行gzip压缩,减少传输带宽(压缩率通常可达50%-70%),提升客户端加载速度,尤其适合弱网络环境。
核心指令
指令名 | 作用 | 示例配置 |
---|---|---|
gzip | 启用/禁用gzip压缩(核心指令) | gzip on; |
gzip_types | 指定需要压缩的文件类型(默认仅压缩text/html) | gzip_types text/css application/javascript; |
gzip_comp_level | 压缩级别(1-9,级别越高压缩率越高,但CPU消耗越大) | gzip_comp_level 5; |
gzip_min_length | 最小压缩文件大小(小于该值的文件不压缩,避免小文件压缩 overhead) | gzip_min_length 1k; |
gzip_vary | 启用Vary: Accept-Encoding响应头(告知浏览器支持压缩) | gzip_vary on; |
实战案例:配置gzip压缩
http {
# 启用gzip压缩
gzip on;
# 压缩级别5(平衡压缩率与CPU消耗)
gzip_comp_level 5;
# 最小压缩文件大小1KB
gzip_min_length 1k;
# 压缩的文件类型(覆盖文本类资源)
gzip_types text/html text/css text/plain application/javascript application/json;
# 启用Vary头
gzip_vary on;
# 不压缩IE6及以下浏览器的请求(IE6对gzip支持差)
gzip_disable "MSIE [1-6]\.";
# 静态资源网站(压缩生效)
server {
listen 80;
server_name static.example.com;
root /usr/share/nginx/static;
}
}
- 效果验证:通过浏览器F12查看「Network」面板,响应头
Content-Encoding: gzip
表示压缩生效; - 压缩率示例:100KB的JS文件压缩后约30KB,传输时间从1秒缩短至300毫秒。
三、实战:综合配置一个完整的Web服务
结合以上语法与模块知识,实战配置一个「静态资源+反向代理+负载均衡+压缩」的完整Web服务,架构如下:
- 静态资源(HTML/CSS/JS):Nginx直接服务;
- 动态API(/api/*):反向代理到后端Node.js集群;
- 启用gzip压缩:减少传输带宽;
- 日志记录:自定义格式,便于排查。
完整配置文件
# 全局块(核心模块)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log error;
pid /var/run/nginx.pid;
# 事件块(核心模块)
events {
use epoll;
worker_connections 10240;
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" $request_time "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# gzip压缩(扩展模块)
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types text/html text/css application/javascript application/json;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
# 后端Node.js集群(负载均衡模块)
upstream node_api {
least_conn; # 最少连接算法
server 192.168.1.200:3000 weight=2;
server 192.168.1.201:3000 weight=1;
}
# 主网站配置(HTTP模块)
server {
listen 80;
server_name example.com www.example.com;
root /usr/share/nginx/example;
index index.html;
# 静态资源:HTML/CSS/JS/图片
location ~* \.(html|css|js|jpg|png|gif)$ {
expires 7d; # 缓存7天
add_header Cache-Control "public, max-age=604800";
}
# 动态API:反向代理到Node.js集群
location /api {
proxy_pass http://node_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 30s;
proxy_read_timeout 60s;
}
# 404错误处理
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/example;
expires -1; # 不缓存404页面
}
}
}
配置验证与生效
- 检查配置语法:
nginx -t # 输出"syntax is ok"表示语法正确
- 重载配置:
nginx -s reload # 无需重启,配置立即生效
- 测试访问:
- 访问
http://example.com
:Nginx直接返回静态首页; - 访问
http://example.com/api/user
:请求被反向代理到Node.js集群; - 查看响应头:存在
Content-Encoding: gzip
,表示压缩生效。
- 访问
四、总结:初学者的核心学习路径
- 语法先行:先掌握「指令结构+块配置+变量」,能读懂基础配置;
- 模块实战:从核心模块(进程、连接)→ HTTP模块(静态资源、虚拟主机)→ 扩展模块(反向代理、负载均衡、压缩)逐步深入,每个模块搭配1个实战案例;
- 避坑习惯:修改配置后必执行
nginx -t
检查,重载用nginx -s reload
而非重启,日志是排查问题的关键(/var/log/nginx/error.log
)。
Nginx 的配置看似复杂,但核心逻辑围绕「请求处理流程」展开:客户端请求→Nginx接收→匹配 server
块→匹配 location
块→执行指令(静态服务/反向代理)。只要理清这个流程,结合本文的语法与模块知识,就能逐步掌握 Nginx 的配置技巧,为后续学习HTTPS、API网关、安全防护等进阶内容打下基础。