Nginx 基础与最佳实践指南
本文用于建立 Nginx 的基本认识,并给中小型项目沉淀一套可复用的配置方式。
维护: 本文最后核对日期为 2026-06-09。Nginx 配置细节会随版本、发行版打包方式和模块启用情况变化。落地前应执行
nginx -v、nginx -V、nginx -T核对当前机器的实际配置。
Nginx 是什么
Nginx 常见角色:
| 角色 | 说明 |
|---|---|
| 静态文件服务器 | 直接返回 HTML、CSS、JS、图片、下载文件 |
| 反向代理 | 接收外部请求,转发给后端 Java / Node / Go 服务 |
| HTTPS 入口 | 终止 TLS,管理证书和 HTTPS 跳转 |
| 负载均衡器 | 把请求分发给多个后端实例 |
| TCP / UDP 代理 | 通过 stream 模块代理四层流量 |
| 简单网关 | 做域名、路径、Header、访问控制、日志等入口治理 |
不要把 Nginx 当成业务应用本身。它适合处理入口流量、连接、静态资源、反代、TLS 和轻量路由;业务权限、业务校验、业务审计仍然应该由应用系统负责。
核心运行模型
Nginx 的基本模型是:
1 | master process |
官方文档对这个模型的描述很直接:
master负责读取和评估配置、维护 worker。worker负责实际处理请求。- Nginx 使用事件驱动模型处理连接。
常见配置:
1 | user nginx; |
中小型项目一般不用一开始就调很多性能参数。先把配置结构、域名匹配、反代、HTTPS、日志和 reload 流程做对。
配置文件结构
Nginx 配置由 directive 组成:
简单 directive:
1 | worker_processes auto; |
块 directive:
1 | http { |
常见上下文:
| 上下文 | 位置 | 作用 |
|---|---|---|
main |
顶层 | 全局配置,例如 user、worker_processes、error_log |
events |
顶层 | 连接处理配置 |
http |
顶层 | HTTP 服务配置 |
server |
http 内 |
一个虚拟主机 / 站点 / 项目入口 |
location |
server 内 |
一个 URI 匹配规则 |
upstream |
http 内 |
一组后端服务 |
stream |
顶层 | TCP / UDP 代理配置 |
重点:配置片段放在哪个文件不重要,最终被 include 到哪个上下文才重要。
例如主配置里这样写:
1 | http { |
那么 /etc/nginx/conf.d/app.conf 里的内容就处在 http 上下文里,所以这个文件里可以直接写:
1 | server { |
但不能只写:
1 | location /api/ { |
因为 location 必须放在 server 里面。如果要拆 location 片段,应该在某个 server 内 include:
1 | server { |
插拔式配置
Nginx 的“插拔式配置”靠 include。
官方 include directive 支持加载单个文件,也支持加载匹配 mask 的多个文件,例如:
1 | include mime.types; |
conf.d 风格
常见于 Nginx 官方包、CentOS / RHEL / 通用部署:
1 | http { |
新增项目:
1 | sudo cp project-a.conf /etc/nginx/conf.d/project-a.conf |
禁用项目:
1 | sudo mv /etc/nginx/conf.d/project-a.conf /etc/nginx/conf.d/project-a.conf.disabled |
注意:不要把备份文件命名成 project-a.conf.bak.conf,因为它仍然会被 *.conf 匹配。
sites-available / sites-enabled 风格
常见于 Debian / Ubuntu 风格:
1 | http { |
新增项目:
1 | sudo cp project-a.conf /etc/nginx/sites-available/project-a.conf |
禁用项目:
1 | sudo rm /etc/nginx/sites-enabled/project-a.conf |
sites-available 只是候选配置目录。真正是否加载,看主配置是否 include 了 sites-enabled,以及 sites-enabled 里是否有对应文件或软链接。
只选一种风格
同一个项目不要同时放:
1 | /etc/nginx/sites-enabled/project-a.conf |
如果主配置同时 include 了这两个目录,就会重复加载同一个 server。
常见后果:
nginx -t提示重复或冲突。- 某个
server_name被忽略。 - 请求进入默认站点。
- 多个兜底
server抢同一个listen。
确认实际加载了什么:
1 | sudo nginx -T | grep -nE 'include|server_name|listen|project-a' |
注意:nginx -T 会打印完整配置。不要把包含内部域名、证书路径、Basic Auth 文件路径、上游地址的输出随便贴到公开环境。
多个 server 如何工作
Nginx 支持多个 server 块。它会先按 listen 的地址和端口筛选,再按请求里的 Host 头匹配 server_name。
示例:
1 | server { |
请求:
1 | Host: b.example.com |
会进入 b.example.com 对应的 server。
默认 server
如果请求没有匹配到任何 server_name,Nginx 会把请求交给当前 listen 地址和端口上的默认 server。
显式配置默认站点:
1 | server { |
这里的重点是:
1 | listen 80 default_server; |
不是:
1 | server_name _; |
server_name _ 只是一个常见占位名。它本身不代表通配全部域名。
每个项目单独 server 的前提
每个项目可以单独一个 .conf 文件,前提是项目之间有可区分的入口:
| 区分方式 | 示例 |
|---|---|
| 不同域名 | a.example.com、b.example.com |
| 不同端口 | :8081、:8082 |
| 不同 IP | 192.168.1.10:80、192.168.1.11:80 |
如果多个项目共用同一个域名和端口,就不要拆成多个相同 server_name 的 server。应该在同一个 server 里用不同 location 分流。
同域名多项目
同一个域名下挂多个项目:
1 | https://example.com/app-a/ |
推荐放在同一个 server:
1 | server { |
不要写成两个完全相同域名的 server:
1 | server { |
这样会让同一个 listen + server_name 重复,后续行为不好维护。
location 匹配
server 选定后,Nginx 再用 URI 匹配 location。
常见类型:
| 写法 | 含义 |
|---|---|
location = /health |
精确匹配 |
location /api/ |
前缀匹配 |
location ^~ /static/ |
前缀匹配,命中后不再检查正则 |
location ~ \.php$ |
区分大小写正则 |
| `location ~* .(png | jpg)$` |
location / |
兜底前缀 |
官方文档中的核心规则可以整理成:
- 先找最具体的前缀匹配。
- 再按配置顺序检查正则
location。 - 如果正则命中,用第一个命中的正则。
- 如果正则没有命中,用之前找到的最长前缀。
location只匹配 URI 路径,不匹配 query string。
示例:
1 | server { |
请求结果:
1 | /api/users -> /api/ |
如果静态资源目录不想被正则覆盖,可以用 ^~:
1 | location ^~ /static/ { |
root、alias 和 try_files
root
root 是把 URI 追加到目录后面。
1 | location /images/ { |
请求:
1 | /images/a.png |
实际文件:
1 | /data/images/a.png |
alias
alias 是把匹配到的路径前缀替换成另一个目录。
1 | location /images/ { |
请求:
1 | /images/a.png |
实际文件:
1 | /data/assets/a.png |
常见坑:
location /images/和alias /data/assets/;末尾斜杠要对应。alias更适合 URI 前缀和磁盘目录名不一致的场景。- 普通站点优先用
root,需要路径替换时再用alias。
try_files
静态站点和前端 SPA 常用:
1 | server { |
含义:
- 先找真实文件
$uri。 - 再找目录
$uri/。 - 都没有就回退到
/index.html。
这适合 Vue / React Router 这类前端路由。否则刷新 /users/1 可能直接 404。
反向代理
最基础反代:
1 | server { |
推荐加基础 Header:
1 | location / { |
后端服务需要正确处理这些 Header,尤其是:
- 获取真实客户端 IP。
- 生成正确的回调地址。
- 判断当前请求是不是 HTTPS。
proxy_pass 末尾斜杠
这是 Nginx 最常见坑之一。
场景一:不带 URI。
1 | location /api/ { |
请求:
1 | /api/users |
后端收到:
1 | /api/users |
场景二:带 URI,并且末尾有斜杠。
1 | location /api/ { |
请求:
1 | /api/users |
后端收到:
1 | /users |
因为匹配到的 /api/ 被替换成了 proxy_pass 里的 /。
规则建议:
- 想让后端保留
/api前缀:proxy_pass http://127.0.0.1:8080; - 想去掉
/api前缀:proxy_pass http://127.0.0.1:8080/; - 正则
location里使用proxy_pass时,优先不要在proxy_pass后面写 URI 部分。
WebSocket 代理
WebSocket 需要升级连接。
在 http 上下文放:
1 | map $http_upgrade $connection_upgrade { |
在对应 location 里:
1 | location /ws/ { |
如果少了 Upgrade / Connection,WebSocket 握手通常会失败。
负载均衡
多个后端实例可以用 upstream:
1 | upstream app_backend { |
默认是 Round Robin。
常见方法:
1 | upstream app_backend { |
或者按客户端 IP 粘住:
1 | upstream app_backend { |
注意:
- 如果后端有登录状态,优先让应用无状态化,而不是依赖
ip_hash。 ip_hash在 NAT、代理、移动网络下不一定理想。- Nginx Open Source 主要是被动失败处理;主动健康检查通常是 NGINX Plus 能力或需要其他方案。
HTTPS 基础
HTTPS server 最小结构:
1 | server { |
HTTP 跳 HTTPS:
1 | server { |
要点:
- 证书是公开信息,私钥必须限制权限。
- 多个 HTTPS 域名共用一个 IP 时依赖 SNI。
server_name要写真实域名,不要生产环境全用_。- TLS 协议和 cipher 默认值会随版本变化,老系统落地前必须核对当前 Nginx / OpenSSL 版本。
- 证书自动续期后要 reload Nginx。
检查:
1 | sudo nginx -t |
日志
常见日志:
1 | /var/log/nginx/access.log |
基础配置:
1 | access_log /var/log/nginx/app-access.log; |
更适合排查反代的 access log:
1 | log_format proxy_access |
字段含义:
| 字段 | 用途 |
|---|---|
$remote_addr |
Nginx 看到的客户端 IP |
$host |
Host |
$request |
请求行 |
$status |
响应状态码 |
$request_time |
Nginx 处理请求总耗时 |
$upstream_response_time |
上游响应耗时 |
$http_x_forwarded_for |
上游代理链路里的客户端 IP |
常用查询:
1 | tail -f /var/log/nginx/error.log |
如果应用日志里有 traceId,建议让前端或网关注入请求头,并在 Nginx 日志里记录:
1 | log_format proxy_access |
常用命令
查看版本:
1 | nginx -v |
检查配置:
1 | sudo nginx -t |
打印最终配置:
1 | sudo nginx -T |
重新加载:
1 | sudo systemctl reload nginx |
重启:
1 | sudo systemctl restart nginx |
查看状态:
1 | systemctl status nginx |
查看监听端口:
1 | ss -lntp | grep nginx |
查看配置是否被加载:
1 | sudo nginx -T | grep -n "server_name" |
从本机带 Host 测试:
1 | curl -i -H "Host: api.example.com" http://127.0.0.1/ |
测试后端:
1 | curl -i http://127.0.0.1:8080/health |
推荐配置结构
下面模板里的 proxy_access 需要先在 http 上下文定义 log_format proxy_access ...。如果暂时没有定义日志格式,可以先把 access_log 改成默认格式:
1 | access_log /var/log/nginx/api-access.log; |
单域名反代 Java 服务
1 | server { |
前端静态站点
1 | server { |
前端加后端 API
1 | server { |
这个配置会把 /api/users 原样转给后端。后端收到的路径仍然是 /api/users。
如果后端不想要 /api 前缀,改成:
1 | location /api/ { |
最小上线流程
- 准备项目配置文件。
1 | sudo vim /etc/nginx/conf.d/project-a.conf |
- 检查语法。
1 | sudo nginx -t |
- 查看最终配置是否只加载一份。
1 | sudo nginx -T | grep -n "project-a" |
- reload。
1 | sudo systemctl reload nginx |
- 本机带 Host 测试。
1 | curl -i -H "Host: project-a.example.com" http://127.0.0.1/ |
- 看日志。
1 | tail -f /var/log/nginx/project-a-error.log |
常见问题
为什么新增 .conf 后没有生效
检查:
1 | sudo nginx -T | grep -n "你的配置文件名" |
常见原因:
- 主配置没有 include 这个目录。
- 文件后缀不是
.conf,但 include 写的是*.conf。 - 放到了
sites-available,但没有软链接到sites-enabled。 - 配置写在错误上下文里。
- reload 前没有
nginx -t,配置根本没应用。
为什么访问域名进入了别的项目
检查:
1 | sudo nginx -T | grep -nE "listen|server_name" |
常见原因:
server_name没写真实域名。- 多个
server使用了相同listen + server_name。 - 请求的 Host 和你以为的不一致。
- 没有匹配时进入了默认
server。 - 证书或 CDN 配置把流量打到了另一个入口。
为什么 502
502 通常说明 Nginx 连接上游失败或上游异常。
检查:
1 | tail -f /var/log/nginx/error.log |
常见原因:
- 后端服务没启动。
proxy_pass端口写错。- 后端只监听
127.0.0.1,但 Nginx 在容器或另一台机器。 - 防火墙或安全组拦截。
- 后端处理太慢,触发
proxy_read_timeout。
为什么上传文件 413
默认 client_max_body_size 比较小。按业务设置:
1 | server { |
不要直接设置成无限大。上传接口还要在应用层限制文件类型、大小和鉴权。
为什么刷新前端路由 404
SPA 需要回退到 index.html:
1 | location / { |
为什么静态文件路径不对
先判断你要的是 root 还是 alias。
root:
1 | location /images/ { |
/images/a.png -> /data/images/a.png
alias:
1 | location /images/ { |
/images/a.png -> /data/assets/a.png
为什么 HTTPS 证书不对
常见原因:
- 请求没有带 SNI。
server_name和证书域名不匹配。- 进入了 443 的默认
server。 - 多个配置重复监听同一个域名。
- 证书续期后没有 reload。
检查:
1 | sudo nginx -T | grep -nE "listen 443|server_name|ssl_certificate" |
最佳实践清单
配置组织
- 每个项目一个
.conf文件。 conf.d和sites-enabled二选一,不要同一个项目放两份。- 文件名清晰,例如
api-example-com.conf。 - 不要把备份文件留成
*.conf。 - 片段 include 要注意上下文:
server片段放http内,location片段放server内。
server
- 生产环境写真实
server_name。 - 只保留一个明确的
default_server。 - 不要多个项目都用
server_name _。 - 不同域名可以拆不同
server。 - 同域名不同路径优先放同一个
server,用location分流。
location
- 少用复杂正则,能用前缀就用前缀。
- 静态目录可用
^~避免被正则覆盖。 location /作为兜底。- 明确
proxy_pass是否需要保留路径前缀。
反向代理
- 统一传递
Host、X-Real-IP、X-Forwarded-For、X-Forwarded-Proto。 - 配置合理的
proxy_connect_timeout、proxy_read_timeout。 - 上传接口配置
client_max_body_size。 - 后端应用要信任代理头时,必须限制可信代理来源。
HTTPS
- HTTP 到 HTTPS 用 301。
- 证书私钥限制权限。
- 证书续期后 reload。
- 多域名 HTTPS 确认证书 SAN / wildcard / SNI。
- 老服务器升级前核对 Nginx 和 OpenSSL 版本。
日志和排障
- 每个重要项目建议有独立 access / error log。
- 反代日志加
$request_time和$upstream_response_time。 - 变更前
nginx -t。 - 变更后
nginx -T核对最终配置。 - 502 先看 Nginx error log,再看后端健康检查。
学习路线
按这个顺序学最稳:
- 会
nginx -t、nginx -T、reload、看日志。 - 理解
main、events、http、server、location。 - 理解
include,知道配置是否真的被加载。 - 理解多个
server的选择规则。 - 理解
location匹配和proxy_pass路径变化。 - 能配置静态站点和 SPA。
- 能配置 Java 后端反代。
- 能配置 HTTPS 和 HTTP 跳转。
- 能排查 404、413、502、证书不匹配、Host 进错站点。
- 再学 upstream、缓存、限流、四层代理、HTTP/2、HTTP/3、灰度发布等高级能力。
参考
- NGINX Beginner’s Guide: https://nginx.org/en/docs/beginners_guide.html
- How nginx processes a request: https://nginx.org/en/docs/http/request_processing.html
- Server names: https://nginx.org/en/docs/http/server_names.html
- Core functionality / include: https://nginx.org/en/docs/ngx_core_module.html
- HTTP core module: https://nginx.org/en/docs/http/ngx_http_core_module.html
- HTTP proxy module: https://nginx.org/en/docs/http/ngx_http_proxy_module.html
- NGINX Reverse Proxy Admin Guide: https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/
- HTTP upstream module: https://nginx.org/en/docs/http/ngx_http_upstream_module.html
- HTTP Load Balancing Admin Guide: https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/
- Configuring HTTPS servers: https://nginx.org/en/docs/http/configuring_https_servers.html
- HTTP log module: https://nginx.org/en/docs/http/ngx_http_log_module.html
迭代记录
- 2026-06-09:初始化 Nginx 基础与最佳实践指南,整理配置结构、include 插拔式配置、多 server 匹配、location 规则、反向代理、HTTPS、日志、排障和上线检查清单。
