简介这是一份面向Linux运维、后端开发及网站架构学习者的Nginx系统学习资料包内容覆盖指令详解、配置文件编写、服务集成、集群搭建、负载均衡、反向代理与Lua扩展等核心主题能够帮助读者从零构建认知体系并应对生产环境常见场景。资源共17个文件压缩包大小19.88MB其中包括5个md笔记、5个pdf文档、2个war部署案例、2个png流程图、1个xmind大纲及html/js示例md与pdf适合系统阅读war包可部署验证图例便于快速理解启动与配置流程。目前该资料已有184人学习下载。学习路径按基础篇、进阶篇、架构篇、模块篇四个阶段递进并配有多个可实际动手的配置案例nginx启动流程图和HTTP配置块解析图可帮助读者理清服务启动与请求处理过程。笔记部分对每个指令的作用、参数、作用域、注释、场景、用法和示例都做了详细记录PDF与MD双格式排版清晰无论是系统学习还是作为工程师日常手册都能随用随查、快速定位。1. Linux 服务里的 nginx它到底解决了什么问题先讲一个很常见的困境某公司内部跑着一个用某框架写的 web 服务开发机上一共就十几个用户直接python app.py监听 8000 端口大家也用了大半年。直到某天上午十点页面开始转圈数据库连接被打满日志里全是Too many open files。查了一圈发现根本不是代码慢而是单进程的开发服务器同时只能处理有限的请求连接一多直接排队排死。这时候最省事的办法不是去重构业务代码而是往前端加一层 nginx它负责接收所有请求再按规则转发给后面的业务进程同时把静态文件、超时、并发连接这些事都接管了。这篇笔记就是围绕「Linux 服务 nginx 学习资料」这个标题来写的面向的是那些已经把 Linux 基本操作搞熟、正准备把 nginx 真正用起来的开发者。nginx 不是一门需要啃源码才能学会的东西但它的配置体系很吃经验同样一句proxy_pass末尾多一个斜杠行为就完全不同同样一个location写法不同匹配优先级就变了。文章会从进程模型和配置文件结构讲起一路走到静态站点、反向代理、负载均衡、缓存最后落在日志和常见坑上让你照着敲完就能在自己的 Linux 服务器上把 nginx 跑起来并且知道出了问题该往哪儿看。2. nginx 为什么是 Linux 服务里的首选进程模型与配置结构2.1 一个 master 带一群 workernginx 高并发的根基第一次打开 nginx 配置文件时很多人会被worker_processes和worker_connections这两个参数搞蒙以为数字越大越好。实际上 nginx 的高并发能力不靠线程靠的是进程模型和事件驱动。nginx 启动后会有一个 master 进程它不处理请求只负责读取配置、管理工作进程、平滑重载真正干活的是 worker 进程每个 worker 都是一个独立的单线程事件循环。所有连接进来后由内核通过epoll事件机制分发给 workerworker 不需要为每个请求创建线程所以几千个并发连接在它眼里就是几千个文件描述符在排队等事件而不是几千个线程在抢 CPU。这个模型的直接好处是worker 进程数量通常设为 CPU 核心数而不是越大越好。因为每个 worker 是单线程的一个 worker 能同时处理的连接数上限由worker_connections决定理论上最大并发数约等于worker_processes * worker_connections但实际还要受文件描述符上限ulimit -n的限制。常见做法是把worker_processes设为auto让 nginx 自己按 CPU 核数决定worker_connections默认 1024对大部分内部系统够用但如果做静态资源服务或反代高并发入口可以调到 4096 或更高同时必须确认系统的文件描述符上限没卡住。调完参数后先用nginx -t验证语法再nginx -s reload平滑生效reload 不会中断现有连接这是线上环境最重要的操作习惯。2.2 配置文件树nginx.conf、conf.d 与 server 块nginx 的配置不是一个单文件而是一棵树。主配置文件是/etc/nginx/nginx.conf它里面定义了全局参数和http块然后在http块里通过include指令把/etc/nginx/conf.d/*.conf和/etc/nginx/sites-enabled/*加载进来。这个设计是有意的每个站点或每个服务一个独立配置文件改其中一个不影响其他出问题时也能快速定位。你在 Linux 上装完 nginx 后默认会有sites-available和sites-enabled两个目录前者放配置模板后者放真正生效的软链接管理逻辑和 Debian 系的服务管理风格一致。一个最小的 server 块长这样server { listen 80; server_name example.local; root /var/www/example; index index.html; }listen指定监听端口和 IPserver_name用来匹配请求的 Host 头root指定站点文件根目录index是默认首页文件。这段配置的含义是当请求到达本机 80 端口且 Host 为example.local时nginx 去/var/www/example目录找对应文件返回。如果有多个 server 块监听同一端口nginx 会先按server_name精确匹配再考虑通配符最后落到默认 server。判断默认 server 的写法是listen 80 default_server;在配置多站点时最好显式指定不然很容易出现「明明配了新站点访问 IP 却还是老页面」的情况。配置文件的层次关系可以理解为http块是全局默认值server块针对某个域名或端口覆盖部分默认值location块再在匹配到的 URL 路径上做更细的控制。改配置时的原则是「优先在最小作用域里改」能写进某个server或location的就不要动http块否则会影响这台机器上所有站点。每改完一段配置先跑nginx -t输出syntax is ok和test is successful再 reload这是唯一的正确姿势。2.3 server_name 与 location 匹配nginx 配置的核心思维在 nginx 的所有配置指令里location的匹配规则是最值得花时间搞清楚的。因为它直接决定了一个 URL 请求会落到哪个配置块而配置块里的root、proxy_pass、缓存策略完全可能不一样。匹配规则按优先级从高到低排列location /path精确匹配location ^~ /path前缀匹配且匹配后不再检查正则location ~ /path和location ~* /path正则匹配前者区分大小写后者不区分最后是location /path普通前缀匹配。很多人配置静态资源时习惯写location /static但如果有location /兜底nginx 实际会选择「最长前缀匹配」也就是static这个前缀更长请求还是会进到静态资源块这不算错但如果你同时写了正则location ~ \.php$正则的优先级会高于普通前缀匹配PHP 请求会直接跳过静态资源块。server { listen 80; server_name assets.example.local; location /favicon.ico { log_not_found off; access_log off; } location ^~ /static/ { alias /data/static/; expires 7d; } location / { proxy_pass http://127.0.0.1:8080; } }这段配置里/favicon.ico精确匹配直接关掉日志和 404 记录避免每次浏览器请求图标都刷一条 error log/static/前缀匹配到静态文件目录并带上 7 天浏览器缓存其余请求全部反代到本地 8080 端口的业务服务。这种三层结构是静态文件与动态服务混跑时的标准布局静态资源由 nginx 直接返回动态请求转发给后端缓存策略只管静态资源后端不需要关心文件读取。3. 在 Linux 上安装并跑通第一个 nginx 服务最小可行配置3.1 安装方式选择包管理器优先源码编译按需在 Linux 上装 nginx最常见也是我推荐的做法是直接用发行版的包管理器Debian/Ubuntu 系用aptCentOS/RHEL 系用dnf或yum。这样装出来的 nginx 会和系统的 systemd 服务管理、日志轮转、默认目录结构完全契合后续维护成本最低。源码编译安装的适用场景只有一种需要官方 apt 源里没有的模块比如某些第三方模块或需要自定义编译参数。对绝大多数做服务运维的人来说没必要自己从源码编译因为升级和卸载都很麻烦而且默认编译参数可能和系统的安全策略不一致。# Debian / Ubuntu sudo apt update sudo apt install nginx -y # CentOS / RHEL sudo dnf install nginx -y安装完成后先确认服务的状态和版本信息systemctl status nginx nginx -vnginx -v输出的是编译版本号nginx -V则输出完整编译参数和模块列表排查模块缺失时用后者。装完后默认站点会监听 80 端口先在浏览器里访问服务器 IP看到 nginx 默认欢迎页就说明服务本身没问题接下来把它替换成自己的站点配置。3.2 用 systemd 管理 nginx开机自启与常用操作nginx 安装后默认不会自动启动。要把 nginx 设为开机自启并立即启动标准做法是sudo systemctl enable --now nginxenable创建开机自启的软链接--now表示同时立即启动。以后日常维护只需要记住四个命令systemctl reload nginx用于平滑重载配置systemctl restart nginx用于重启systemctl status nginx看运行状态和最近日志journalctl -u nginx -f实时跟踪 nginx 日志。reload和restart的区别非常关键reload会让 master 进程重新读取配置并启动新的 worker同时优雅关闭旧 worker不中断正在处理的请求restart是完整停掉再起所有连接都会断开。所以线上变更配置一律用reload只有修改了监听的端口、用户等 master 级参数时才需要restart。如果修改了user指令或listen端口reload可能不会完全生效这时需要restart。遇到这种情况nginx -t通过但 reload 后配置没变化先检查是不是改错了文件——很多人会同时存在conf.d里的配置和sites-enabled里的软链接两个文件内容不一致时后加载的会覆盖前一个的同名server块造成「改了没生效」的假象。用下面的命令排查实际加载了哪些配置nginx -T | grep -E server_name|listen|includenginx -T输出的是合并后的完整配置能看到最终生效的server_name和listen值这是排查多文件配置冲突的利器。3.3 静态站点最小配置从默认页到第一个真实站点现在把默认站点替换成一个真实的静态站点。假设你的站点文件放在/var/www/mysite目录里有一个index.html在/etc/nginx/conf.d/mysite.conf里写server { listen 80; server_name mysite.local; root /var/www/mysite; index index.html; location / { try_files $uri $uri/ 404; } }try_files $uri $uri/ 404的含义是先按原样路径找文件找不到就按目录找再找不到直接返回 404。这一步能让/about这种没有后缀的路径先尝试找/about文件再找/about/目录下的 index如果不写try_filesnginx 对/about这类路径会直接返回 403因为目录默认不允许列出。写完配置后按顺序执行sudo nginx -t sudo systemctl reload nginx curl -I http://127.0.0.1/curl -I只取响应头看到HTTP/1.1 200 OK和Server: nginx就说明站点已经通了。如果server_name用的是本地域名要在访问机器的 hosts 文件里加一行映射否则浏览器里输入域名是解析不到服务器 IP 的。4. 反向代理与负载均衡nginx 在 Linux 服务里最常干的活4.1 反向代理为什么你的业务服务不该直接暴露端口在 Linux 服务器上跑业务服务时最常见的架构是业务进程监听内网端口如 8080nginx 监听 80/443所有外部请求先进 nginx 再转发。这样做有三个实际好处。一是隐藏后端细节外部只能看到 nginx 的地址和端口不知道后端有几个节点、跑在什么端口二是统一入口后可以在 nginx 层做超时控制、请求限制、缓存和日志这些如果散落在各业务服务里每个服务都要重复实现一遍三是后端起多个实例时nginx 负责把请求分发到不同实例业务服务本身不需要知道自己被谁代理。最简反向代理配置只有三行server { listen 80; server_name api.example.local; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }proxy_pass是转发目标proxy_set_header用来把客户端的原始信息传给后端。Host $host是必须的不然后端收到的主机名会是 127.0.0.1很多框架的 URL 生成和站点校验会出错。X-Real-IP让后端能从请求头里拿到客户端真实 IP否则后端日志里全是 nginx 的 IP排查问题时等于瞎了。除了这两个X-Forwarded-For也是常用头它会在原有值后面追加客户端 IP适合多级代理场景。4.2 proxy_pass 末尾斜杠的玄学一个字符决定转发路径proxy_pass是 nginx 配置里最容易翻车的地方因为末尾多一个/或少一个/转发路径会完全不同。规则可以用一句话概括如果proxy_pass后面不带 URI即没有路径部分nginx 会把原始请求的完整 URI 原样转发给后端如果带了 URI哪怕只是一个/nginx 会用 location 匹配到的部分替换掉原始 URI 的前缀后转发。举例说明location /api/和proxy_pass http://127.0.0.1:8080;配合请求/api/user会原样转成http://127.0.0.1:8080/api/user。但如果proxy_pass写成http://127.0.0.1:8080/;请求/api/user会被转成http://127.0.0.1:8080/user因为/api/这个前缀被替换成了/。很多人配完后端接口时发现 404排查半天结果就是这里多写了个斜杠。踩过这个坑之后我现在写proxy_pass时都会先问自己一句后端接口的完整路径是什么我要不要把 location 前缀传给后端。4.3 upstream 负载均衡让多个后端节点分摊压力当流量大到单个后端实例扛不住时就需要把请求分摊到多个实例。nginx 的upstream块定义一组后端节点proxy_pass指向这组节点而不是单个地址upstream backend { server 127.0.0.1:8080 weight3; server 127.0.0.1:8081 weight1; } server { listen 80; server_name api.example.local; location / { proxy_pass http://backend; proxy_next_upstream error timeout; } }默认情况下 nginx 会按轮询方式把请求分发给每个节点weight参数可调整比例适合后端机器性能不一致的场景。proxy_next_upstream的作用是当某个节点返回错误或超时时自动把请求转给下一个节点相当于一次自动容错。这个参数默认值就包含error timeout但需要注意它默认不包含http_502这类状态码如果后端节点正常情况下会返回 502nginx 不会自动切换。需要根据后端实际情况调整proxy_next_upstream error timeout http_502 http_503 http_504;upstream还支持ip_hash或least_conn等负载策略。ip_hash按客户端 IP 哈希分配保证同一个 IP 总是打到同一个节点适合需要会话保持的场景least_conn会把请求分给当前连接数最少的节点。配置多个策略时要注意ip_hash和weight同时使用的话哈希分布会受权重影响行为不太直观。如果业务服务本身是无状态的用默认轮询最简单可靠如果依赖 session 或者说缓存优先考虑ip_hash或干脆在后端用共享存储解决会话问题而不是把希望全押在负载均衡策略上。5. nginx 配置避坑现象、原因与解决办法5.1 reload 后配置没生效新站点怎么都访问不到现象改了conf.d下的配置文件nginx -t也通过了systemctl reload nginx执行了但访问新配置的域名或路径还是返回旧页面或 404。这时候先别怀疑 nginx 没 reload按照下面的顺序排查。先看nginx -T输出的合并配置里有没有自己的配置如果没有说明文件没有被 include如果有但server_name或listen和预期不一致说明被其他配置文件的同名server块覆盖或冲突了。Debian 系默认的 nginx.conf 里会同时 includeconf.d/*.conf和sites-enabled/*如果同一个端口、同一个server_name在两个目录各写了一份后加载的那个生效。解决方式是统一目录管理把配置只放在conf.d或只放在sites-enabled不要在两边同时维护。另外reload 只会让配置变更生效新增了listen 443这类端口时需要确认端口没被占用用ss -lntp | grep 443看一下。5.2 上传文件提示 413 Request Entity Too Large但代码没问题现象通过 nginx 反代的后端接口上传文件小文件正常超过几兆就返回 413。原因几乎可以肯定是 nginx 的client_max_body_size默认值挡住了请求。nginx 默认只允许 1MB 的请求体超过就直接拒绝不会把请求转发给后端。解决方式是在http、server或location块里调整这个值client_max_body_size 20m;建议放在server块里避免影响所有站点。改完 reload 后再用curl -F测试大文件上传确认状态码变成 200 而不是 413。这个坑特别容易出现「前端和后端都查不出问题」的情况因为两端日志里都没有任何异常只有 nginx 层面静默拦截了。5.3 静态资源 404但文件明明就在服务器上现象配置了root /var/www/site访问首页正常但只要路径带子目录就 404比如/assets/app.js返回 404可/var/www/site/assets/app.js确实存在。原因多半是root和alias用混了。root会把完整的请求 URI 拼在 root 路径后面location /assets/下的root /var/www/site;实际查找的路径是/var/www/site/assets/app.js这没问题但如果写成alias且路径拼接错了比如alias /var/www/site/assets;那请求/assets/app.js查找的路径变成/var/www/site/assets/assets/app.js自然 404。简单记法root是「目录 URI 全路径」alias是「把 location 匹配的部分替换成 alias 指定的路径」。我一般只在location精确匹配到某个固定路径时才用alias其余情况一律root能少踩一半的坑。5.4 访问日志正常但错误日志刷大量open() /var/www/... failed (13: Permission denied)现象页面能打开但 error log 里不停刷权限拒绝的记录。原因通常是 nginx worker 进程的运行用户对站点目录没有读权限。nginx 默认 worker 以www-data或nginx用户运行取决于发行版如果站点文件是 root 创建的且权限是 700worker 用户自然进不去。解决方式是调整文件权限或属主sudo chown -R www-data:www-data /var/www/mysite sudo chmod -R 755 /var/www/mysite这里要区分执行权限和读权限目录需要r-x才能进入和列出文件文件需要r--才能被读取。如果不想改属主也可以给目录加ox让其他用户能进入但这样安全性差一些。配置里还有个user指令可以改 worker 运行用户但不建议为了迁就目录权限去改 nginx 的用户保持默认更安全。5.5 用curl测试返回 200浏览器访问却一直转圈现象命令行里curl -I返回HTTP/1.1 200 OK但浏览器打开同一地址就一直 loading 不出内容或者刷新时快时慢。原因通常是响应头里缺少Content-Length或Transfer-Encoding处理有问题最常见的是反代配置里开了gzip但后端也同时开了压缩两边都压缩导致响应体无法被正确解析。解决办法是确认 nginx 的gzip配置没把已经压缩过的响应二次压缩gzip on; gzip_types text/plain text/css application/json application/javascript;同时在后端关闭压缩或让后端识别Via头并跳过压缩。另一个常见场景是反代 WebSocket 时没有设置升级头浏览器连接一直挂起location /ws/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; }遇到浏览器和curl行为不一致的问题先开浏览器开发者工具看 Network 面板确认是卡在请求等待阶段还是响应下载阶段再对症下药。6. 进阶日志分析、性能调参和验证习惯真正把 nginx 的配置跑稳之后日常最重要的三件事分别是从日志里看出问题、按需调性能参数、以及养成每次改配置都验证的习惯。先看日志。nginx 的访问日志默认在/var/log/nginx/access.log错误日志在/var/log/nginx/error.log两者都可以在配置里自定义格式和路径。我一般会让所有反代站点独立一个日志文件并在log_format里加上请求耗时和上游响应状态log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for rt$request_time ut$upstream_response_time;配置后用tail -f /var/log/nginx/access.log实时观察请求重点看两个值rt是 nginx 处理整个请求的耗时ut是后端返回响应消耗的时间。如果ut很大而rt也很大的说明瓶颈在后端如果ut很小但rt大说明瓶颈在 nginx 到后端的网络链路或排队上。排查慢请求时这个字段能直接帮你判断该去调业务代码还是调网络省得两边瞎猜。每次改完log_format记得 reload不然格式不生效。性能调参方面最值得动的几个参数是worker_processes、worker_connections、keepalive和gzip。worker_processes auto按 CPU 核数生成 workerworker_connections建议不低于 4096同时确认系统ulimit -n没有卡住keepalive 64表示每个 worker 最多保持 64 个到后端的空闲长连接减少频繁建连的开销。这些参数不是越大越好需要结合服务器的内存和文件描述符上限来判断改完用nginx -t验证再 reload。另外静态资源如果长期不变可以在location里加expires 7d;让浏览器缓存能明显降低重复请求的压力。最后一个习惯是每次改配置之前先备份一份改完之后用nginx -T确认合并后的配置没有意外覆盖再 reload。我在某次改负载均衡配置前没有备份结果proxy_pass的 URI 写错导致一个内部系统整整五分钟的请求全部打到错误路径上从那以后就养成了cp一份带日期的配置再动手的习惯。日志是 nginx 给你留下的第一手线索配置验证是最后一道防线这两件事做好了绝大多数线上问题都能在五分钟内定位到方向。希望这篇笔记能帮你在 Linux 服务上把 nginx 的路走顺。本文还有配套的精品资源点击获取