目录
配置文件
1、nginx.conf
2、lab.conf:定义后端服务器组
配置文件
两个配置文件的关系可以把它们理解成:
- nginx.conf:公司的“总规章制度”
- lab.conf:某个具体网站的“工作规则”
加载关系:
nginx.conf └── http └── include /etc/nginx/conf.d/*.conf └── lab.conf ├── upstream └── server └── location
nginx.conf 最后一行加载了 conf.d 目录中的配置,所以 lab.conf 实际上会被插入 http 块内。
1、nginx.conf
(1)详解
文件位置:conf/nginx.conf
① Worker 进程数量
worker_processes auto;
Nginx 通常有两类进程:
Master 主进程 ├── Worker 1 ├── Worker 2 ├── Worker 3 └── Worker 4
a. Master 进程
负责:
- 读取配置
- 创建 Worker
- 接收 reload/stop 信号
- 平滑更新配置
b. Worker 进程
负责:
- 接收请求
- 返回静态文件
- 转发请求
- 写日志
auto 表示让 Nginx 根据 CPU 数量自动决定 Worker 数量。
在 WSL 中,可以查看:podman exec nginx-lab ps
② 错误日志
error_log /var/log/nginx/error.log warn;
含义是:
- 错误日志路径:/var/log/nginx/error.log
- 日志级别:warn
常见日志级别由详细到严重,大致为:
debug → info → notice → warn → error → crit → alert → emerg
使用 warn 时,会记录警告以及更严重的问题。
例如:
- 后端连接失败
- 后端响应超时
- 请求被限流
- 文件不存在
- 配置或运行异常
项目把容器里的日志目录映射到了本机:
- 容器:/var/log/nginx/
- 本机:~/nginx-podman-lab/logs/
所以可以直接查看:tail -f ~/nginx-podman-lab/logs/error.log
③ PID 文件
pid /var/run/nginx.pid;
PID 是进程编号。
Nginx 把 Master 进程编号写到这个文件中,例如:26
当执行:nginx -s reload
Nginx 会通过 PID 找到 Master 进程,然后向它发送重新加载配置的信号。
一般不需要手动修改这一项。
④ events 块
events {
worker_connections 1024;
multi_accept on;
}
这里管理网络连接。
a. worker_connections 1024
表示每个 Worker 最多可以同时打开大约 1024 个连接。
假设有 4 个 Worker,理论连接上限大致为:
4 × 1024 = 4096
但不能简单地将它当成“最多 4096 个用户”,因为一次反向代理通常涉及两个连接:
用户 ←连接1→ Nginx ←连接2→ 后端
实际容量还会受到以下因素限制:
- Linux 文件描述符上限
- CPU
- 内存
- 后端处理能力
- 长连接数量
本实验中的 1024 足够使用。
b. multi_accept on
当有很多新连接同时到来时,允许 Worker 一次接受多个连接。
大白话:
门口同时来了很多顾客,接待员可以连续接待,不必每次只领一个人。
生产环境中是否开启需要结合负载测试,本实验主要用于展示。
(2)http 块详细讲解
http {
…
}
所有普通 HTTP/HTTPS 网站配置通常都放在这里。
① 文件类型表
include /etc/nginx/mime.types;
default_type application/octet-stream;
a. mime.types
它告诉浏览器不同文件是什么类型:
.html → text/html
.css → text/css
.js → application/javascript
.png → image/png
如果没有正确类型,浏览器可能无法正常解析文件。
b. default_type
如果 Nginx 不认识某个文件扩展名,就使用:application/octet-stream
它表示:
这是一个普通二进制文件,具体类型不确定。
② 隐藏 Nginx 版本
server_tokens off;
默认错误页面或响应头可能显示:nginx/1.27.5
关闭后通常只显示:nginx
这样可以减少版本信息暴露。
但它只是基础安全设置,不代表服务器因此就绝对安全。
③ 高效发送文件
sendfile on;
tcp_nopush on;
a. sendfile on
普通发送文件过程可能是:磁盘 → 程序内存 → 网络
开启 sendfile 后,Linux 可以更高效地把文件数据交给网络层,减少不必要的数据复制。
适合:
- HTML
- CSS
- JavaScript
- 图片
- 下载文件
b. tcp_nopush on
配合 sendfile 使用,尽量把数据凑成较完整的数据包后再发送。
大白话:
送货时尽量装满一车再发,而不是一个小包裹就发一辆车。
④ 客户端长连接
keepalive_timeout 65;
浏览器访问网页时,通常需要请求多个文件:
index.html
style.css
app.js
图片
如果没有长连接,每个文件可能都需要重新建立 TCP 连接。
开启 Keepalive 后:
建立一次连接
├── 请求 index.html
├── 请求 style.css
├── 请求 app.js
└── 暂时保留连接
65 表示连接空闲约 65 秒后关闭。
注意:这是客户端到 Nginx 的长连接设置,不是 Nginx 到后端的连接池。
⑤ 上传大小限制
client_max_body_size 10m;
客户端请求体最大为 10MB。
主要影响:
- 文件上传
- 大型 JSON
- 表单提交
超过限制时,Nginx 通常返回:413 Request Entity Too Large
这是 http 级别的默认值,也可以在特定 server 或 location 中覆盖。
(3)Gzip 压缩
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript application/xml text/xml;
① gzip on
开启响应压缩。
例如原本一个 CSS 文件有 100KB,压缩后可能只有 20KB。
过程如下:
Nginx 原始内容
↓ gzip 压缩
较小的数据
↓ 网络传输
浏览器自动解压
② gzip_comp_level 5
压缩等级为 5。
范围通常是 1~9:
- 等级越高:文件可能越小
- 等级越高:消耗的 CPU 越多
5 是比较平衡的实验值。
③ gzip_min_length 256
小于 256 字节的内容不压缩。
因为特别小的内容压缩收益很低,反而增加处理成本。
④ gzip_types
指定需要压缩的响应类型:
text/plain
text/css
application/json
application/javascript
application/xml
text/xml
图片一般不用再 gzip,因为 PNG、JPEG 等通常已经压缩。
验证是否压缩:
curl -I \\
-H 'Accept-Encoding: gzip' \\
http://127.0.0.1:18080/assets/style.css
如果生效,响应中可以看到:Content-Encoding: gzip
(4)限流区域
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
这只是定义限流规则和存储区域,还没有真正应用到请求。
a. $binary_remote_addr
表示客户端 IP 的二进制形式。
Nginx 按 IP 分别计数:
IP 192.168.1.10 → 自己的计数
IP 192.168.1.11 → 自己的计数
使用二进制形式是为了节省内存。
b. zone=api_limit:10m
创建一个名为 api_limit 的共享内存区域,大小为 10MB。
Worker 进程会在这里共同记录:哪个 IP 最近发了多少请求
这里的 10m 不是“允许 10MB 流量”,而是用于保存限流状态的内存大小。
c. rate=5r/s
每个 IP 平均每秒允许 5 个请求。
真正使用这个规则的位置在 lab.conf:
limit_req zone=api_limit burst=10 nodelay;
可以理解成:
limit_req_zone → 创建限流器
limit_req → 在某个接口上启用限流器
(5)访问日志格式
log_format lab '$remote_addr – [$time_local] "$request" '
'status=$status '
'rt=$request_time '
'urt=$upstream_response_time '
'upstream=$upstream_addr '
'us=$upstream_status '
'ref="$http_referer" '
'ua="$http_user_agent"';
这里定义了一个名为 lab 的日志格式。
① $remote_addr
客户端 IP。
在 Podman实验里,可能看到容器网络地址。
② $time_local
Nginx 收到请求的时间。
③ $request
完整请求行,例如:GET /api/info HTTP/1.1
④ $status
Nginx 最终返回的状态码:
200 正常
404 地址不存在
413 上传过大
502 后端异常
503 限流或暂不可用
504 后端响应超时
⑤ $request_time
从 Nginx 收到请求,到发送完响应的总时间。
日志里写成:rt=0.015
表示整个请求用了 0.015 秒。
⑥ $upstream_response_time
后端响应耗时:urt=0.012
如果请求是静态文件,没有经过后端,通常显示 -。
⑦ $upstream_addr
请求交给了哪个后端:upstream=10.89.0.2:8000
⑧ $upstream_status
后端返回给 Nginx 的状态码。
例如:us=200
注意:
- $status:Nginx 最终返回给用户的状态
- $upstream_status:后端返回给 Nginx 的状态
二者不一定相同。
⑨ $http_referer
用户从哪个页面进入当前地址。
⑩ $http_user_agent
客户端信息,例如浏览器或 curl。
(6)启用访问日志
access_log /var/log/nginx/access.log lab;
含义:
- 日志写入 /var/log/nginx/access.log
- 使用刚才定义的 lab 格式
查看:tail -f ~/nginx-podman-lab/logs/access.log
(7)加载网站配置
include /etc/nginx/conf.d/*.conf;
加载 conf.d 目录下所有 .conf 文件。
本实验通过 Podman 挂载后,加载的是:conf/conf.d/lab.conf
这种拆分方式可以让一个 Nginx 管理多个网站:
conf.d/
├── app.conf
├── api.conf
├── admin.conf
└── lab.conf
2、lab.conf:定义后端服务器组
upstream app_backend {
least_conn;
keepalive 16;
server backend-a:8000 weight=3 max_fails=2 fail_timeout=10s;
server backend-b:8000 weight=1 max_fails=2 fail_timeout=10s;
}
upstream 表示一组后端服务器。
名字是:app_backend
后面可以通过下面的写法使用它:proxy_pass http://app_backend;
(1)backend-a 和 backend-b
它们是 Podman 容器名称。
三个容器加入了相同网络:nginx-lab-net
Podman 内部 DNS 会把:
backend-a → A 容器的内部 IP
backend-b → B 容器的内部 IP
所以 Nginx 不需要写死 IP。
(2)least_conn
least_conn;
表示优先把新请求交给当前连接较少的后端。
例如:
A 当前有 10 个连接
B 当前有 2 个连接
新请求通常更倾向于交给 B。
如果不写负载均衡算法,默认使用轮询。
(3)keepalive 16
keepalive 16;
让每个 Worker 最多保留一定数量的空闲上游长连接。
没有连接池时:每次请求 → 新建后端连接 → 请求结束 → 关闭
使用连接池后:建立连接 → 请求结束 → 暂时保留 → 后续请求复用
好处:
- 减少 TCP 建连成本
- 降低后端压力
- 提高性能
这里还需要在反代位置使用:
proxy_http_version 1.1;
proxy_set_header Connection "";
否则连接复用可能无法按预期工作。
(4)后端定义
server backend-a:8000 weight=3 max_fails=2 fail_timeout=10s;
server backend-b:8000 weight=1 max_fails=2 fail_timeout=10s;
① weight
A 权重 3,B 权重 1。
大体上表示 A 承担更多流量,但因为这里同时使用了 least_conn,实际选择还会考虑当前连接数,并不能机械理解成每四个请求一定是 A、A、A、B。
② max_fails=2
如果在指定时间内连续发生一定数量的失败,Nginx 会暂时认为该节点不可用。
③ fail_timeout=10s
它有两个相关作用:
- 统计失败的时间窗口
- 达到失败次数后,暂时避开该节点约 10 秒
这属于被动健康检查:
先有真实请求失败
↓
Nginx 记录失败
↓
达到 max_fails
↓
暂时少选或不选该后端
它不是主动定时访问 /health 的健康检查。
(5)server:定义一个网站
server {
listen 80;
server_name localhost lab.local;
}
① listen 80
Nginx 容器内部监听 80 端口。
Podman做了端口映射:电脑 18080 → Nginx 容器 80
所以浏览器访问:http://127.0.0.1:18080
最终会到达容器的 80 端口。
② server_name
server_name localhost lab.local;
表示这个网站希望处理的域名是:
localhost
lab.local
本实验只有一个 server,因此使用 127.0.0.1 通常也会落到这里。
企业中可能有多个 server:
server_name api.company.com;
server_name admin.company.com;
server_name www.company.com;
Nginx 根据请求中的 Host 选择对应网站。
(6)健康检查 /healthz
location = /healthz {
access_log off;
default_type text/plain;
return 200 "ok\\n";
}
① location = /healthz
location 根据 URL 路径决定如何处理请求。
= 表示精确匹配:
/healthz → 匹配
/healthz/ → 不匹配
/healthz/test → 不匹配
精确匹配优先级非常高。
② access_log off
健康检查通常每几秒执行一次,如果全部记录,访问日志会出现大量无价值内容,所以这里关闭访问日志。
错误仍然可以进入错误日志。
③ default_type text/plain
告诉客户端返回内容是普通文本。
④ return 200 "ok\\n"
Nginx 直接返回:
HTTP 状态码:200
内容:ok
请求不会经过后端。
(7)静态网站
root /usr/share/nginx/html;
index index.html;
① root
设置静态文件根目录。
Podman把项目的 html 目录挂载到了:/usr/share/nginx/html
因此:
请求 /app.js
→ /usr/share/nginx/html/app.js
请求 /assets/style.css
→ /usr/share/nginx/html/assets/style.css
② index index.html
访问目录 / 时,默认查找:index.html
(8)try_files 和 SPA
location / {
try_files $uri $uri/ /index.html;
}
location / 是最宽泛的前缀匹配,大多数请求都能匹配它。
try_files 按顺序尝试:
例如请求:/assets/style.css
Nginx 查到文件后直接返回。
请求:/user/profile
磁盘没有这个文件,于是返回:/index.html
这适合 Vue、React 等单页应用,因为 /user/profile 可能是前端路由,不是真实文件。
(9)静态资源缓存
location /assets/ {
expires 7d;
add_header Cache-Control "public";
access_log off;
}
这个规则匹配:
- /assets/style.css
- /assets/logo.png
① expires 7d
告诉浏览器资源可以缓存 7 天。
这样用户第二次访问时,可以直接使用本地缓存,减少请求。
② Cache-Control "public"
表示该资源允许被浏览器、CDN 等公共缓存保存。
③ access_log off
静态资源请求很多,实验中关闭日志以减少干扰。
生产环境是否关闭,要根据审计和排障需求决定。
(10)核心反向代理 /api/
location /api/ {
limit_req zone=api_limit burst=10 nodelay;
proxy_pass http://app_backend/;
…
}
它匹配:
- /api/info
- /api/health
- /api/slow
① 启用限流
limit_req zone=api_limit burst=10 nodelay;
使用 nginx.conf 中定义的:api_limit
a. burst=10
允许短时间额外突发约 10 个请求。
可以理解成:
- 正常速度:每秒 5 个
- 临时允许一个小队列/桶承受突发
- 超出后拒绝请求
b. nodelay
突发额度内的请求立即处理,不让它们排队慢慢等待。
超过额度后,本实验通常返回 503。
② proxy_pass 尾斜杠
proxy_pass http://app_backend/;
这里末尾有 /。
请求:/api/info
转发给后端时变成:/info
也就是 /api/ 前缀被替换成 /。
这是本配置中非常重要的知识点。
③ 上游使用 HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
默认情况下,上游连接可能不按预期保持。
使用 HTTP/1.1 并清空 Connection 请求头,有助于复用前面 upstream 中配置的 Keepalive 连接。
这里的空字符串表示:
不要把这个请求头传给后端。
(11)反向代理请求头
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;
① Host $host
告诉后端,用户访问的主机名是什么。
例如:lab.local
② X-Real-IP $remote_addr
告诉后端,Nginx 看到的客户端 IP 是什么。
③ X-Forwarded-For
记录代理链路中的客户端 IP。
例如:用户 → CDN → Nginx → 后端
它可能类似:203.0.113.10, 10.0.0.5
$proxy_add_x_forwarded_for 会保留已有内容,再追加当前客户端地址。
④ X-Forwarded-Proto $scheme
告诉后端用户原本使用的协议:http
如果以后增加 HTTPS,它可能是:https
后端生成跳转地址、Cookie 或外部链接时经常需要它。
(12)反向代理超时
proxy_connect_timeout 3s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
① proxy_connect_timeout
Nginx 连接后端最多等待 3 秒。
例如后端端口无法连接,等待超过时间后放弃。
② proxy_send_timeout
Nginx 向后端发送请求数据时,连续写数据的等待超时。
它并不是整个请求的绝对总时长。
③ proxy_read_timeout
Nginx 等待后端返回数据的间隔超时。
如果后端在指定时间内一直没有返回新数据,Nginx 会终止请求。
普通 API 使用 30 秒只是实验值,生产中应该根据业务特点设置。
(13)故意制造 504 的 /timeout/
location /timeout/ {
proxy_pass http://app_backend/;
…
proxy_connect_timeout 1s;
proxy_read_timeout 1s;
}
访问:/timeout/slow
因为 proxy_pass 带尾斜杠,后端收到:/slow
后端程序故意等待约 5 秒,但 Nginx 只允许连续等待 1 秒:
后端等待 5 秒、Nginx 只等 1 秒 → 504 Gateway Timeout
这里主要用来学习如何观察超时和错误日志,不能直接照搬到生产配置。
(14)/raw/ 演示尾斜杠区别
location /raw/ {
proxy_pass http://app_backend;
}
注意这里没有尾斜杠。
访问:/raw/info
后端收到的仍然是:/raw/info
而不是 /info。
后端没有 /raw/info 接口,所以返回 404。
对比:
/api/info + proxy_pass …/ → 后端收到 /info
/raw/info + proxy_pass … → 后端收到 /raw/info
(15)精确匹配 /whoami
location = /whoami {
default_type application/json;
return 200 '{"via":"nginx-exact-location","hint":"location = has highest priority"}\\n';
}
访问:/whoami
Nginx 直接返回 JSON,不访问后端,也不查找静态文件。
它用于演示:location = /whoami 比普通的 location / 优先级更高。
但访问 /whoami/test 不会匹配精确规则,而会进入 location /。
(16)完整请求流程
① 请求首页
GET /
→ server 监听 80
→ 匹配 location /
→ try_files 找到 index.html
→ Nginx 返回静态网页
② 请求 CSS
GET /assets/style.css
→ 匹配 location /assets/
→ 从磁盘读取 CSS
→ 添加 7 天缓存头
→ 返回浏览器
③ 请求 API
GET /api/info
→ 匹配 location /api/
→ 检查限流
→ 去掉 /api/ 前缀
→ least_conn 选择 A 或 B
→ 转发 /info
→ 后端返回 JSON
→ Nginx 记录 upstream 和耗时
→ 返回浏览器
④ 请求慢接口
GET /timeout/slow
→ 匹配 location /timeout/
→ 转发后端 /slow
→ 后端等待 5 秒
→ Nginx 等待 1 秒后超时
→ 返回 504
⑤ 请求 /raw/info
GET /raw/info
→ 匹配 location /raw/
→ 保留完整路径 /raw/info
→ 后端没有该接口
→ 返回 404
(17)修改配置的正确步骤
先检查语法:podman exec nginx-lab nginx -t
成功后平滑加载:podman exec nginx-lab nginx -s reload
合并执行:
podman exec nginx-lab nginx -t &&
podman exec nginx-lab nginx -s reload
查看最终完整配置:podman exec nginx-lab nginx -T
查看实时日志:
tail -f logs/access.log
tail -f logs/error.log
核心:
nginx.conf:全局能力
lab.conf:网站与路由规则
upstream:后端名单
server:一个网站
location:不同 URL 怎么处理
proxy_pass:请求转给谁
网硕互联帮助中心






评论前必须登录!
注册