
简介面向Linux运维与后端开发初学者的Nginx系统学习资料包围绕反向代理、负载均衡、服务集成等核心场景以基础/进阶/架构/模块四阶段大纲串联知识点并配有可动手验证的配置案例与Nginx启动流程、HTTP配置块解析图覆盖指令用法到集群落地的完整进阶路径。压缩包共17个文件包含md与pdf双格式学习笔记、xmind思维导图、war应用示例、png图例及前端演示文件整体约19.88MB。笔记逐条梳理指令的作用、参数、作用域、注释与使用场景示例详实既适合随课对照学习也可作日常查用的技术手册。已有184人学习下载适合希望系统建立Nginx知识体系并强化实际配置能力的开发者。1. 同样是 Nginx 学习资料为什么这一套能当工作手册用而不是吃灰在 Linux 环境里做 Nginx 配置真正的拦路虎往往不是“不会装”而是配置行为不可预期。照着视频敲完访问却出现 404、502 或者循环跳转这种返工情况在负载均衡和反向代理的调试阶段尤其常见。这份 Linux 服务 Nginx 学习资料的编排思路不太一样Xmind 大纲管学习路径HTML/JS 与 war 包案例管验证PDF 与 MD 笔记管速查两张图例管配置块之间的边界关系。它适合一边学一边配置的从业者也适合已经在写配置但经常被指令作用域卡住的人。它不是让你从头读到尾而是学的时候有路线配置的时候有索引遇到故障时能翻到对应参数。2. 先建立认知框架大纲、图例与笔记的三层配合2.1 大纲四阶段拆解基础、进阶、架构、模块先定位自己卡在哪一层压缩包里的 Nginx 大纲.xmind 打开以后其实是一张分阶段的学习地图。它把内容切成基础篇、进阶篇、架构篇、模块篇四条线基础篇主要覆盖安装、目录结构、信号控制、全局配置指令进阶篇集中在 location 匹配规则、rewrite 与正则、日志切割、gzip 压缩架构篇是重头戏包括反向代理、负载均衡、动静分离、缓存和限流模块篇则涉及第三方模块编译、Lua 集成、与认证网关类模块的协同方式。这条路径设计的价值在于它可以帮你快速定位自己“卡在哪一层”。很多人在配置里加了一堆 upstream 和 proxy_pass但问起 worker_processes 与 events 块的分工就含糊说明基础层的全局配置没有真正消化。反过来有人 location 优先级背得很熟但说不清 proxy_pass 带不带斜杠的差别就需要回到进阶篇的 URI 替换规则部分。我在拿到 Xmind 之后的做法是把每个子主题扫一遍在旁边标上“清楚、模糊、没碰过”三个状态然后把模糊和没碰过的部分对应到第 01 到第 05 天的笔记章节里。这套资料的价值就不只是看一遍而是变成一张个人知识地图学过的、没学的、学了一半的全部一目了然。这种自测式学习对配置工作是有效的因为 Nginx 的报错信息通常不直接告诉你“某个指令放错了层”而是让你自己去判断作用域。大纲里每一条指令所属的阶段往往就暗示了它应该出现在哪个配置层级。比如 rewrite 相关指令归在进阶篇实际使用中它既可以出现在 server 层也可以出现在 location 层而 upstream 归在架构篇它只能定义在 http 层。理解了这一步后面看笔记时对“作用域”这个高频词会敏感很多。2.2 nginx 启动流程读图的入口与排错的三个检查点nginx 启动流程.png 这张图画的东西直接决定了你配置出错时该往哪个方向查。简化来说Nginx 启动时先读取主配置文件校验语法结构然后由 master 进程创建监听 socket再 fork 出 worker 进程去处理事件请求。这张图最容易给人启发的一点是语法校验发生在创建监听 socket 之前而 worker 的启动又在 socket 监听之后所以配置语法正确但服务仍然起不来问题往往出在端口被占用、进程权限不足或日志目录不可写。对应这张图我在实际环境里会按下面这套顺序做检查# 1. 校验 Nginx 配置语法看到 syntax is ok 才算通过 /usr/local/nginx/sbin/nginx -t # 2. 查看 master 与 worker 进程是否按预期数量运行 ps -ef | grep nginx | grep -v grep # 3. 确认 80 端口确实在监听且是 nginx 进程占用 ss -lntp | grep :80 # 4. 本机发起一次请求确认响应头完整返回 curl -I http://127.0.0.1/每一步的用途不一样。第一步排除语法层错误第二步确认 master 和 worker 进程结构正常第三步解决“配置文件没问题但端口起不来”的玄学问题第四步验证到业务层是否真的通了。如果 nginx -t 已经通过但 systemctl status nginx 显示启动失败最常见的两个原因就是 80 端口被其他进程占住或者 user 指令指定的用户对日志目录没有写权限。前者用 ss -lntp 就能看到后者要去 logs/error.log 里查 permission denied 关键字。这套检查顺序对应着启动流程图的每一段。配置语法校验通过相当于地图前半段走完了进程结构正常相当于 master-fork-worker 这段通了端口和响应正常事件循环才算真正跑起来。排查时从前往后逐段验证比在错误日志里盲猜要高效得多。2.3 HTTP 配置块解析图把 main、http、server、location 的父子关系刻进脑子里HTTP 配置块解析图.png 是我认为这份资料里性价比最高的一张图。它画的是 Nginx 配置的嵌套结构main 层在最外events 和 http 并行挂在 main 之下http 下面是 serverserver 下面是 location。理解这张图核心在于两条规则一是上层指令默认向下继承二是某些指令只能在特定层级定义。对照着图我把最小可运行的 nginx.conf 骨架写出来逐行对着看# main 层 user nginx; # worker 进程的运行身份 worker_processes auto; # 按 CPU 核数自动设置 worker 数量 error_log logs/error.log warn; # 全局错误日志 pid logs/nginx.pid; # master 进程 pid 写入位置 # events 层 events { worker_connections 1024; # 单个 worker 的最大并发连接数 } # http 层 http { include mime.types; # 引入 MIME 类型映射 default_type application/octet-stream; sendfile on; # 高效文件传输开关 keepalive_timeout 65; # 客户端长连接超时时间 # ---------- server 层 ---------- server { listen 80; server_name localhost; # ---------- location 层 ---------- location / { root html; index index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; } } }这个骨架里值得注意的细节有三个。worker_processes 和 events 组是全局行为不归属于任何 serversendfile、keepalive_timeout 写在 http 层会继承到所有 serverdefault_type 起兜底作用当 Nginx 无法从文件后缀判断类型时就会用这个值。location 层的 proxy_pass 则完全改变了请求的走向它不再读本地文件而是把请求转发给后端。图上那条从 http 到 server 再到 location 的嵌套路径实际上就是配置指令继承和覆盖的主干道。我一般会建议把这张图和骨架配置放在一起看先在图上找到某一个指令所在的层级再在骨架里看它是否有缩进关系。比如 upstream 只能出现在 http 层log_format 也只能定义在 http 层而 root 在 server 和 location 里都可以出现只是生效范围不同。这些边界单看笔记里某一条指令说明是不容易串起来的但放到配置块解析图里就变得非常直观。3. 动手配置案例从静态页面、反向代理到负载均衡三种形态3.1 案例包的组成war 包、HTML 和 JS 怎么部署才算真正利用起来案例目录里同时出现了 demo.war、demo_simple.war、index.html 和 js 文件对应了两种截然不同的部署形态。index.html 和 js 给 Nginx 直接读本地磁盘用验证静态文件服务两个 war 包给 Java 容器用验证反向代理和负载均衡。很多人在练习时只把 index.html 放进 html 目录就结束了war 包完全没有参与结果动态请求的配置练不到。我的做法是搭一个最小环境让两类资源都跑起来。先准备一个静态目录把 HTML 放进去再准备两个监听不同端口的 Java 容器实例# 建立静态资源目录并放入案例里的 index.html mkdir -p /data/projects/nginx-learn/html cp index.html /data/projects/nginx-learn/html/ # 把 war 包部署到两个不同端口的 Java 容器 cp demo.war /data/tomcat-8081/webapps/ cp demo_simple.war /data/tomcat-8082/webapps/ # 静态资源先配一个最简 server 块能访问后再继续往下做 curl -s http://127.0.0.1/ | head -n 10war 包这里有一个容易忽略的点解压后的应用上下文路径取决于 war 包文件名。demo.war 部署后访问路径通常就是 /demo/demo_simple.war 对应 /demo_simple/。后面配 proxy_pass 时必须以实际部署后的上下文为准否则后端会直接 404。如果你的容器配置里设置了 context 别名那就要按你的实际设置来不要想当然地认为文件名等于路径。静态目录准备到位后第 3.1 节的最小 server 配置就可以派上用场了。直接把 root 指到 /data/projects/nginx-learn/html访问根路径看到 index.html 的内容说明 Nginx 的静态文件服务链路是通的这一步是后面所有代理实验的地基。3.2 反向代理配置把 /app/ 动态路径送到后端头信息与 URI 要一起处理反向代理是这份笔记里反复出现的核心概念。它的本质是Nginx 接收客户端请求后把请求转发给后端服务拿到响应再返回给客户端。客户端只看到 Nginx 的地址感知不到后端的存在。配置上最核心的指令就是 proxy_pass配合它使用的还有一组 proxy_set_header。参照案例里的 war 包我一般会把动态请求集中在 /app/ 这个前缀下与静态资源分开处理server { listen 80; server_name learn.test; # 静态资源交给 Nginx 直接读磁盘 location / { root /data/projects/nginx-learn/html; index index.html; } # 动态请求反向代理到 Java 容器 location /app/ { proxy_pass http://127.0.0.1:8081/demo/; 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_read_timeout 30s; proxy_connect_timeout 5s; } }这段配置里有三个值得解释的点。proxy_pass 地址末尾带了 /demo/那么 location 匹配到的前缀 /app/ 会被替换成 /demo/所以客户端请求 /app/login 时后端实际收到的是 /demo/login。proxy_set_header 的作用是让后端拿到真实信息Host 保持客户端原始的域名X-Real-IP 记录客户端真实 IPX-Forwarded-For 记录经过的代理链路。proxy_read_timeout 和 proxy_connect_timeout 是控制超时的后端接口偶尔响应慢的时候这两个参数能避免 Nginx 过早断开。验证这一步是否配对了我一般会在后端容器日志里看请求路径# 浏览器或 curl 触发请求后观察后端日志里的 URI curl -s http://127.0.0.1/app/ tail -f /data/tomcat-8081/logs/catalina.out如果后端日志里出现的路径是 /demo/说明 URI 替换按预期发生了。如果出现的是 /app/说明 proxy_pass 的路径处理方式和你设想的不一样回去查末尾斜杠。这一步看起来小但它是后续很多诡异 404 的根源。3.3 负载均衡块upstream 的通用算法、权重与被动健康检查配置反向代理还只是点对点转发配置负载均衡才是这份资料名字里真正的重头戏。负载均衡的核心是把 upstream 定义在 http 层然后在 location 里用 proxy_pass 指向这个 upstream 组。多个后端节点共同对外提供服务时Nginx 按你指定的算法分配流量。我按案例里 war 包的双节点布局写一个标准配置upstream backend_servers { server 127.0.0.1:8081 weight3 max_fails2 fail_timeout10s; server 127.0.0.1:8082 weight1 max_fails2 fail_timeout10s; keepalive 32; } server { listen 80; server_name learn.test; location /app/ { proxy_pass http://backend_servers; proxy_next_upstream error timeout http_502; } }这里的关键参数按用途拆开看。weight3 和 weight1 表示 8081 每接到 3 份请求8082 接到 1 份比例关系直接由权重决定。max_fails2 配合 fail_timeout10s 的意思是10 秒内如果某个节点失败了 2 次Nginx 就认为它暂时不可用会在接下来的 10 秒内不再往这个节点发请求。keepalive 32 是 Nginx 与后端之间保持的空闲长连接数量能减少频繁建连的开销。最后一行 proxy_next_upstream 表示当后端返回错误、超时或 502 时自动把请求转给下一个节点。算法选择上默认的加权轮询适合大部分无状态接口。只要后端节点处理能力相近权重就能控制流量比例。如果需要保持会话比如同一个用户登录后不能频繁切换节点就用 ip_hash它按客户端 IP 计算哈希值保证同一 IP 固定落在同一节点。least_conn 则适合请求处理时长差异明显的场景它会优先把请求分给当前活跃连接数最少的节点。验证负载均衡最直接的办法是连续请求观察两端的日志计数# 连续请求 10 次观察 8081 与 8082 的日志条数比例 for i in $(seq 1 10); do curl -s http://127.0.0.1/app/index.html done # 分别统计两个后端容器的访问日志条数 wc -l /data/tomcat-8081/logs/*.log wc -l /data/tomcat-8082/logs/*.log如果 10 次请求结束后两边日志比例接近 3:1upstream 配置就算真正跑通了。如果所有请求都落在同一个节点优先检查 server 指令里的地址和端口是否写反了以及 weight 参数是否真的被加载。3.4 动静分离把 js 与静态资源留在 Nginx 本地动态请求转发给集群案例包里同时给了 index.html 和 js 文件这本身就是在暗示动静分离的练习场景。静态资源的特点是文件路径固定、内容不变适合由 Nginx 直接读磁盘返回响应快且不占用后端容器资源。动态请求则带有业务逻辑必须交给后端处理。把这两类请求在 location 层面切分开就是动静分离。我常用的写法是用正则 location 匹配静态资源后缀用前缀 location 匹配动态接口server { listen 80; server_name learn.test; # 静态资源按后缀匹配直接读本地目录 location ~* \.(js|css|png|jpg|gif|ico)$ { root /data/projects/nginx-learn/html; expires 7d; access_log off; } # 动态请求转发到负载均衡组 location /app/ { proxy_pass http://backend_servers; proxy_set_header Host $host; } }正则 location 的匹配优先级高于普通前缀 location这是它能正常工作的前提。请求 /app/index.html 时虽然前缀 /app/ 能命中第二个 location但后缀 .html 会先被正则规则捕获Nginx 直接去本地目录找文件请求根本不会进到代理逻辑里。expires 7d 给静态资源加了一个 7 天的浏览器缓存头第二次访问直接走本地缓存不再请求服务器。这里有一个容易踩的细节加了 expires 之后如果业务上更新了 js 文件但文件名没变客户端浏览器可能继续用旧缓存导致新功能不生效。我一般会建议静态资源在文件名里带版本号比如 app.v2.js这样升级时文件名变化缓存自然失效。这个点不属于配置语法问题但生产环境里坑过不少人。4. 把笔记当工作手册用四类最常踩的配置坑与排查顺序4.1 MD 与 PDF 的分工一个适合随用随查一个适合从头通读这套资料里的笔记同时给了 PDF 和 MD 两种格式这个设计在实际使用中是有讲究的。PDF 适合按顺序通读版面固定做学习笔记时更舒服MD 格式则天然适合被检索。我在本地维护了一组 Nginx 笔记索引配合 grep 可以做到秒级定位指令说明。# 在所有笔记中搜某个指令确认它出现在哪一章 grep -rn proxy_read_timeout Nginx_day*.md # 只看指令所在段落以及后面的说明 grep -A 3 proxy_read_timeout Nginx_day03.mdgrep 输出结果时会带上行号和上下文直接定位到某个指令的默认值、可配置位置以及适用范围。这套用法在工作中有实际价值遇到一个报错先用关键词在 MD 笔记里搜一遍比翻书快得多。PDF 版本我用来做周末的系统性阅读MD 版本则作为长期维护的工作手册底稿。4.2 踩坑 1location 不是先写先得优先级规则是精确先于前缀前缀再分正则现象访问 /app/xxx 时请求被 location / 拦截返回了静态页面内容而不是按预期转发到后端。原因location 的匹配优先级并不是按配置文件出现的先后顺序决定的。精确匹配 location /path 优先级最高其次是 ^~ 修饰的前缀匹配再往后是正则匹配 ~ 和 ~*最后才是普通前缀匹配和根路径 /。很多人在配置里把 /app/ 写在 location / 之前以为先写先命中但普通前缀匹配仍然要遵循“最长前缀优先”的规则而且根路径 / 是兜底规则只有当所有更精确的规则都没有命中时才会生效。解决为动态接口加上 ^~ 修饰符明确告诉 Nginx 这个前缀命中后不需要继续验证正则规则。以我的配置习惯如果 location /app/ 确定只用于代理就直接写成location ^~ /app/ { proxy_pass http://backend_servers; }加了 ^~ 之后匹配逻辑变得清晰先按前缀长度匹配/app/ 命中后立即停止不再向下看正则规则自然不会落到 location / 上。如果你的业务里正则规则必须参与那就要熟记这条优先级链路 大于 ^~大于正则大于普通前缀最长匹配最后才是 / 兜底。4.3 踩坑 2proxy_pass 末尾斜杠决定转发路径多一个斜杠后端路径就不同现象配置里写 location /app/ 加 proxy_pass http://127.0.0.1:8080/demo/访问 /app/login后端收到的路径是 /demo/login符合预期。但把 proxy_pass 改成不带斜杠的 http://127.0.0.1:8080/demo 之后后端收到的是 /demo/app/login接口直接 404。原因proxy_pass 后面带不带 URI决定了 Nginx 是否替换 location 匹配到的前缀。不带路径的 proxy_pass http://127.0.0.1:8080; 会保留原始 URI带路径的 proxy_pass http://127.0.0.1:8080/demo/; 会用 /demo/ 替换掉 location 匹配到的 /app/ 前缀。末尾是否带斜杠替换结果完全不同。解决我在部署前会固定一套规则避免每次都靠猜。规律如下表proxy_pass 写法客户端请求后端实际收到http://127.0.0.1:8080;/app/login/app/loginhttp://127.0.0.1:8080/;/app/login/loginhttp://127.0.0.1:8080/demo/;/app/login/demo/login这个表的核心就是location 匹配到哪一段前缀带 URI 的 proxy_pass 就用它的 URI 去替换这一段。开发环境和生产环境最常见的差异点就是这里代码里写了怎样的路径Nginx 转发后有没有改变它直接决定前后端联调是否顺利。4.4 踩坑 3if 与 add_header 的行为误解部分指令在 if 块里不生效现象在 location 里的 if 块内写了 add_header实际请求的响应头里却找不到这个 header。原因if 是 rewrite 模块的指令它的行为与普通指令执行阶段不一样在 if 块内使用 add_header 并不是所有版本下都可靠。另一个容易被忽视的行为是add_header 在 location 层级声明后会覆盖从上层继承来的全部 add_header 设置。也就是说只要某个 location 里出现了一个 add_headerserver 层的 add_header 在这个 location 下就不会生效了。解决能不加 if 就不加 if把公共响应头统一放在 server 层。如果确实需要依据条件返回不同头信息推荐先用 map 指令把变量算出来再在 add_header 里引用变量。这样既绕开了 if 的执行阶段问题也让配置更符合 Nginx 的处理模型。# 直观但容易翻车的写法不推荐 location / { if ($arg_debug 1) { add_header X-Debug on; } } # 常见做法在 server 层统一加头并带上 always 参数 server { add_header X-Frame-Options SAMEORIGIN always; }这里的 always 参数也值得记住。不加 always 时Nginx 只在响应码为 200、201 等少数几个状态时返回这个头4xx 和 5xx 响应里它会消失。加上 always所有响应才会带上这个安全头。这个细节在安全审计场景里经常被注意到。4.5 踩坑 4配置改完 reload 了却不生效问题通常卡在 reload 之前的一步现象修改 nginx.conf 中的 upstream 节点列表后执行 nginx -s reload配置语法也通过了但旧节点仍在接收请求新配置没有完全生效。原因这里有两个层面。第一reload 只是向 master 进程发送信号由 master 校验配置并重新 fork worker如果配置文件语法有错reload 就会失败进程继续跑旧配置。第二即便 reload 成功已经建立的长连接也不会立刻断开客户端与 Nginx 之间、Nginx 与后端之间的 keepalive 连接仍保持着旧状态某些请求会继续走旧节点直到连接释放。解决改动后按严格顺序执行三步验证。# 第一步校验配置语法 /usr/local/nginx/sbin/nginx -t # 第二步平滑加载新配置 /usr/local/nginx/sbin/nginx -s reload # 第三步观察错误日志确认有没有 reload 相关内容 tail -f /usr/local/nginx/logs/error.log如果 reload 后旧节点依然在工作说明还有长连接存活等连接自然超时释放即可不需要杀掉进程重启。切忌一上来就执行 nginx -s stop 再 start那会中断所有在途请求流量高峰时影响很大。从那以后我每次改完 upstream 都会先看 keepalive 配置是否真的必要再决定是不是需要等待连接自然切换。5. 把资料沉淀成自己的排错清单一次可复用的升级用法这套资源里的 MD 笔记最值得转化的是一张个人排错清单。我自己的做法是把笔记目录固定在一个位置然后在 shell 里加一个别名让检索变成一条命令的事alias nginxhelpgrep -rn --include*.md $1 ~/docs/nginx/之后每次配置 Nginx 前先对要用的指令做一次检索确认它的默认值、作用域和是否支持放在当前配置块里。比如接口偶尔超时的时候我会先搜 proxy_read_timeout 和 proxy_connect_timeout再看对应的笔记笔记章节里是怎么描述超时行为的nginxhelp proxy_read_timeout nginxhelp keepalive_timeout从笔记里确认参数位置后我会把超时配置分成两个层级处理。全局的 keepalive_timeout 负责客户端长连接值设在 60 到 75 秒比较稳妥location 里的 proxy_read_timeout 负责等待后端响应默认 60 秒对多数业务偏长我会踩调到 15 秒左右接口一旦超过这个时间就快速失败避免前端长时间挂起。关键是每次调整后都要走一遍闭环验证/usr/local/nginx/sbin/nginx -t /usr/local/nginx/sbin/nginx -s reload curl -s -o /dev/null -w %{http_code} %{time_total}s\n http://127.0.0.1/app/第一行保证配置可用第二行输出状态码和总耗时用来判断调参到底有没有效果。这个习惯救过我很多次尤其是改完 proxy_pass 或 upstream 之后不跑一遍 curl 很难确认长连接是否还挂在旧配置上。从那以后我每次改完 Nginx 配置都强制走一遍 nginx -t、curl -I、tail -f error.log 这三步这套资料里的 PDF 可以慢慢读MD 笔记则一直留在磁盘上当手册随用随查希望这一套流程能帮到你。本文还有配套的精品资源点击获取