接入 Nginx: nginx.conf 三层结构与块级作用域
纲要
「Nginx配置文件整体结构」,把conf/nginx.conf从逻辑上拆开:
- 三大块:全局块、
events块、http块各自负责什么 http块的两层嵌套:http全局块 →server块 →location块- 对照真实配置逐行讲:以
nginx-1.16.1自带的默认nginx.conf为例 - 固定指令 vs 可配置值:哪些是关键字不能动,哪些可以改
- 多
server、多location:虚拟主机与路径匹配的组织方式 - 语法规则:分号、花括号、注释、相对路径基准
一、为什么要先理解结构
Nginx的能力全部通过conf/nginx.conf表达。这个文件默认有 117 行,其中大量是注释,但初次打开依然会觉得无从下手。
理解结构后你会知道:改配置就是往正确的块里放正确的指令。后面的三件事——部署静态资源、反向代理、负载均衡——本质上分别是:
| 要做的事 | 改哪里 |
|---|---|
| 部署静态资源 | server块里的location,配root+index |
| 反向代理 | server块里新增location,配proxy_pass |
| 负载均衡 | http块里新增upstream,再在location的proxy_pass里引用 |
二、默认配置文件全貌
下面是nginx-1.16.1安装后的默认conf/nginx.conf,已去掉注释,这是它真正的骨架:
#user nobody; worker_processes 1; #error_log logs/error.log; #pid logs/nginx.pid; events { worker_connections 1024; } http { include 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" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }只有 40 行左右。去掉注释是读nginx.conf的第一步——注释占了原文件的三分之二,且绝大多数是PHP/HTTPS的示例模板,与当前场景无关。
三、全局块
范围
从文件开头到events {之前,全部属于全局块。
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid;职责
配置与Nginx运行本身相关的全局参数,与具体请求处理无关。
| 指令 | 作用 | 说明 |
|---|---|---|
user | 运行worker进程的用户 | 默认被注释,即nobody |
worker_processes | worker进程数 | 默认1,建议设为auto或CPU核数 |
error_log | 错误日志路径与级别 | 级别可选debug/info/notice/warn/error/crit |
pid | pid文件路径 | 默认logs/nginx.pid |
关于被注释的指令
注意这些行前面都有#。被注释不代表不重要,而是表示"使用默认值"。
比如#pid logs/nginx.pid;被注释,但启动时依然会生成logs/nginx.pid——因为pid指令的默认值就是这个。把它打开并改成别的值,才会变。
error_log是值得显式打开的:
error_log logs/error.log; error_log logs/error.log notice;两行都写是常见写法(不同级别记到不同文件)。调试阶段可以开info甚至debug(debug需要编译时加--with-debug)。
一个易错点
worker_processes与后面events块里的worker_connections共同决定理论最大连接数:
最大连接数 ≈ worker_processes × worker_connections默认1 × 1024 = 1024。这是"同时保持的连接数",不是QPS。反向代理场景下,一个客户端连接会占用一个到后端的连接,所以作为反向代理时实际承载的客户端连接数要除以 2。
四、events块
范围
events { worker_connections 1024; }职责
配置与网络连接相关的参数。
| 指令 | 作用 |
|---|---|
worker_connections | 每个worker进程能同时处理的最大连接数 |
use | 指定事件驱动模型,如use epoll;(Linux下推荐) |
multi_accept | 是否一次接受多个新连接 |
accept_mutex | 是否用互斥锁均衡各worker的新连接分配 |
默认配置里只有worker_connections。Linux下Nginx会自动选择最高效的模型(epoll),通常不需要手写use epoll;。
worker_connections调大时的配套操作:Linux单进程默认最多打开 1024 个文件描述符(ulimit -n),连接数超过它会报too many open files。需要同时调整系统限制:
worker_rlimit_nofile 65535; # 放在全局块 events { worker_connections 65535; }# /etc/security/limits.conf* soft nofile65535* hard nofile65535五、http块
范围与职责
http { ... }及其内部全部内容。这是配置量最大、操作最频繁的块,代理、缓存、日志、虚拟主机(server)都在这里配。
http块在逻辑上再分为两部分:
http全局块:http {之后到第一个server {之前server块:可以有一个或多个
http全局块
http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #gzip on; server { ... } }这里的指令对所有server生效(server内可以覆盖):
| 指令 | 作用 | 为什么重要 |
|---|---|---|
include mime.types | 引入MIME类型映射 | 决定Content-Type,删了会导致CSS/JS失效 |
default_type | 未匹配MIME时的默认值 | 默认application/octet-stream(下载) |
sendfile | 开启零拷贝文件传输 | 静态资源性能关键,直接内核态发送,不经用户态 |
tcp_nopush | 配合sendfile,攒够一个包再发 | 提高网络利用率 |
keepalive_timeout | 长连接超时秒数 | 默认 65 秒,减少TCP握手开销 |
gzip | 响应压缩 | 默认关闭,开启可显著减小文本类响应体积 |
access_log/log_format | 访问日志 | 默认被注释但生效(使用默认路径与格式) |
sendfile on是Nginx静态资源性能强于Tomcat的核心原因之一。传统读文件发送要经历:磁盘 → 内核缓冲区 → 用户缓冲区 → 内核socket缓冲区 → 网卡,两次CPU拷贝、两次上下文切换。sendfile让数据直接在内核态从文件描述符传到socket,省掉用户态中转。
server块
server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }server块即虚拟主机(Virtual Host)——一台机器上的一个"站点"。
一个http块可以配多个server,这是Nginx托管多站点的基础:
server { listen 80; server_name localhost; location / { root html; index index.html; } } server { listen 81; server_name localhost; location / { root html81; index index.html; } }http块从逻辑上分为:
server全局块:listen、server_name等location块:可有一个或多个
| 指令 | 作用 | 说明 |
|---|---|---|
listen | 监听端口 | 可写80、81、443 ssl、127.0.0.1:80 |
server_name | 服务器名/域名 | 学习阶段写localhost;生产写真实域名 |
server_name的作用:多个server监听同一个端口时,Nginx依据请求头里的Host与server_name匹配来决定交给哪个server处理。这就是"一台服务器用80端口托管多个域名"的原理。
location块
location / { root html; index index.html index.htm; }location用于匹配请求的URI路径。
| 指令 | 作用 | 说明 |
|---|---|---|
root | 静态资源根目录 | html是相对路径,基准是安装目录/usr/local/nginx |
index | 默认首页 | 可配多个,空格分隔,依次查找,都找不到返回403/404 |
proxy_pass | 反向代理目标地址 | 下一篇的核心 |
alias | 路径别名 | 与root的拼接规则不同,见后文 |
一个server可以配多个location,这是路径分发的基础:
location / { root html; # 静态资源走本地 } location /api/ { proxy_pass http://192.168.138.101:8080; # /api 前缀走后端 }root与alias的区别
这是配置静态资源时最容易踩的坑。
# root:最终路径 = root + 完整 URI location /static/ { root /usr/local/nginx/html; } # 请求 /static/logo.png → /usr/local/nginx/html/static/logo.png # alias:最终路径 = alias + (URI 去掉 location 前缀后的部分) location /static/ { alias /usr/local/nginx/html/; } # 请求 /static/logo.png → /usr/local/nginx/html/logo.pngroot会拼上完整的location路径,alias会替换掉location匹配的部分。用错会导致 404,且报错信息不会告诉你是路径拼错了。
六、固定指令与可配置值
nginx.conf里有两种内容:
固定指令(关键字,不能改):server、listen、server_name、location、root、index、include、error_page、proxy_pass、upstream……
可配置值(按需修改):端口号、域名、URI匹配规则、目录名、首页文件名、代理地址……
server { # server 是固定指令 listen 80; # ← 80 可改 server_name localhost; # ← localhost 可改 location / { # ← / 可改(匹配规则) root html; # ← html 可改(目录名) index index.html; # ← index.html 可改(文件名) } }改配置时只动"值",不动"指令名"。把server_name写成servername、listen写成listen_port,都会报unknown directive。
七、语法规则
| 规则 | 说明 | 违反的后果 |
|---|---|---|
每条指令以分号;结尾 | worker_processes 1; | directive is not terminated by ";" |
块用花括号{}包裹 | http { ... } | unexpected "}"或is not terminated by "}" |
注释用# | #gzip on; | — |
| 指令与值之间用空格分隔 | 至少一个空格 | invalid number of arguments |
| 相对路径基准是安装目录 | root html;→/usr/local/nginx/html | — |
| 缩进不影响语义 | 只为可读性 | — |
漏写分号是最高频的报错。课程演示中就出现过:把index index.html;改成index hello.html(漏了分号),nginx -s reload报:
nginx: [emerg] unexpected "}" in /usr/local/nginx/conf/nginx.conf:46报错行号是 46(花括号所在行),但真正的问题在上一行漏了分号——报错位置往往滞后一行,这是排查时的经验点。
用vim打开时可以用:set nu显示行号,快速定位:
vim/usr/local/nginx/conf/nginx.conf :set nu八、作用域与继承
指令在不同块中的生效范围不同,子块可以覆盖父块:
规则:
http块的配置对该http内所有server生效server块的配置对该server内所有location生效- 子块中重复定义同一指令,子块优先
- 有些指令只能出现在特定块中,放错位置会报
"xxx" directive is not allowed here
常见指令的允许位置:
| 指令 | 可出现的位置 |
|---|---|
worker_processes | 全局块 |
worker_connections | events块 |
include/sendfile/gzip/upstream | http块 |
listen/server_name | server块 |
root/index/proxy_pass/alias | location块(也可在server/http中作为默认值) |
九、最小可用配置模板
理解了结构后,一个能跑起来的最小配置只需要这些:
worker_processes auto; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } } }后面所有的功能扩展,都是在这个骨架上加upstream、加location、加指令。
API 速览
| 指令 | 所属块 | 作用 |
|---|---|---|
user | 全局 | 指定worker进程运行的用户 |
worker_processes | 全局 | worker进程数,建议auto |
worker_rlimit_nofile | 全局 | worker进程可打开的最大文件描述符数 |
error_log | 全局 /http/server/location | 错误日志路径与级别 |
pid | 全局 | master进程ID文件路径 |
worker_connections | events | 单个worker最大连接数 |
use | events | 事件驱动模型(epoll/select/poll) |
include | 任意 | 引入其他配置文件 |
default_type | http/server/location | 默认MIME类型 |
sendfile | http/server/location | 零拷贝文件传输 |
tcp_nopush | http/server/location | 攒包发送,配合sendfile |
keepalive_timeout | http/server/location | 长连接超时时间 |
gzip | http/server/location | 响应压缩 |
listen | server | 监听端口 |
server_name | server | 虚拟主机域名 |
error_page | http/server/location | 错误页映射 |
location | server/location | URI路径匹配块 |
root | http/server/location | 静态资源根目录(拼接完整URI) |
alias | location | 路径别名(替换location前缀) |
index | http/server/location | 默认首页,可多个,空格分隔 |
官方文档
Nginx配置文件结构(Beginner's Guide):https://nginx.org/en/docs/beginners_guide.htmlNginx核心模块(全局块与events指令):https://nginx.org/en/docs/ngx_core_module.htmlNginxhttp核心模块:https://nginx.org/en/docs/http/ngx_http_core_module.htmlNginx指令字母索引:https://nginx.org/en/docs/dirindex.htmlNginxlocation匹配规则:https://nginx.org/en/docs/http/ngx_http_core_module.html#location
总结
整个nginx.conf就三个块:全局块、events块、http块。前两个通常不动,日常 90% 的工作都在http块里。
http块内部是两层嵌套:http全局块(对所有站点生效的公共配置)→ 若干server块(虚拟主机,靠listen+server_name区分)→ 每个server内若干location块(靠URI前缀区分)。这个"多server+ 多location"的组织方式,正是Nginx能同时托管多个站点、同时处理静态资源与反向代理的结构基础。
读配置的第一件事是删注释。默认文件 117 行里三分之二是注释和PHP/HTTPS模板,删完只剩 40 行骨架,结构立刻清晰。
每个指令只能出现在特定块中,放错会报directive is not allowed here;子块可以覆盖父块的同名指令。改配置前先想清楚"这条指令该放哪一层"——比如gzip放http是对所有站点生效,放某个location就只对匹配的路径生效。
漏分号是最高频报错,且报错行号通常滞后一行。看到unexpected "}"时往上翻一行找分号。
root与alias的拼接规则不同:root是"根目录 + 完整URI",alias是"别名 + 去掉location前缀后的剩余部分"。配静态资源 404 时优先怀疑这里。
下一篇用这个结构做第一件实事:把外卖平台的静态页面部署到Nginx,并逐条解释listen、server_name、location、root、index的实际作用。