ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nginx实战指南:反向代理、负载均衡与HTTPS配置详解

Nginx实战指南:反向代理、负载均衡与HTTPS配置详解 1. nginx到底是什么为什么这么多人用它1.1 从一次压测说起先说个我自己的经历。几年前我接手一个老项目后端是单机Tomcat用户一多就卡死老板天天催优化。我一开始以为是业务代码的问题结果压测一看Tomcat每秒处理几百个请求就到了瓶颈。后来把nginx架在前面做静态资源分离和反向代理同样的业务代码整体吞吐直接翻了几倍机器负载反而降了下来。从那以后我就意识到nginx这个高性能Web服务器的称号不是吹出来的。nginx的并发模型是epoll事件驱动配合master-worker进程架构一个worker进程可以同时处理成千上万个连接。用生活化的类比来解释传统服务器像银行柜台一个柜员一次只能服务一个客户nginx则像一个自助业务大厅一个柜员可以同时盯着一堆自助终端谁有需要就响应谁没有请求时就继续等着。这就是它能扛高并发的核心原因。1.2 nginx适合哪些人能解决什么问题如果你在做后端开发、运维、DevOps相关工作nginx基本上是一门绕不开的必修课。它最常见的用途包括托管静态网站、做反向代理网关、负载均衡、配置HTTPS证书、缓存静态资源、灰度发布入口等。这套东西搞明白了日常工作中涉及Web服务层的很多问题都会变得清晰。nginx还能解决一个很实际的团队协作问题前后端联调时前端代码跑在nginx上接口请求通过反向代理转发到后端服务这样就不需要后端单独开跨域允许也不用前端用各种代理插件转来转去。一个配置文件搞定联调环境效率会高很多。这篇文章不是官方文档式的罗列我尽量用实际接触过的完整场景带大家把nginx从安装、配置到运维排查整体过一遍把我在一线踩过的坑和验证过的方法直接写出来能少走弯路就少走弯路。2. 安装篇Linux和Windows两条路线全走一遍2.1 Linux源码编译安装的完整流程在生产环境我用得最多的是CentOS和Ubuntu系系统。nginx编译安装主要依赖gcc、make、pcre、zlib、openssl这些组件建议在编译前一次性装好依赖避免编译过程中报错中断# CentOS/RHEL系 yum -y install gcc gcc-c make pcre-devel zlib-devel openssl-devel # Ubuntu/Debian系 apt -y install build-essential libpcre3-dev zlib1g-dev libssl-dev接着下载nginx源码包。这里有个小经验源码包版本不要追新选择官方标记的stable稳定版即可生产环境稳定性优先级永远高于功能迭代。解压后进入目录configure阶段可以根据需求加模块参数./configure --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --with-stream make -j4 make installconfigure这一步最容易踩坑很多人直接用默认参数编译后面要用到SSL模块才发现没编进去只能重新编译整个nginx。我在实际操作中的习惯是即使眼下用不到也会把http_ssl_module和stream模块先编上后面加配置时就不用再折腾二进制了。2.2 用包管理器快速安装的场景如果只是本地验证、测试环境用系统包管理器装nginx是最快的。CentOS/RedHat系在执行yum install nginx之前需要先确认EPEL源已配置Ubuntu/Debian则直接执行apt install nginx即可。优点是依赖自动处理、开机自启也方便缺点是版本相对保守想用新功能或定制模块时比较受限。安装完成后用nginx -v查看版本再用nginx -t检查配置语法。这里有个细节容易让人困惑包管理器安装的nginx默认配置路径是/etc/nginx/nginx.conf编译安装的默认配置路径是/usr/local/nginx/conf/nginx.conf。网上很多教程把这两种混着写新手容易看懵。先确认自己用哪种方式装的再去找对应的配置文件能省掉很多时间。另外还有一点用包管理器装的nginxsystemd服务文件已经准备好了systemctl enable nginx设置开机自启即可编译安装则需要自己写systemd服务文件否则重启机器后nginx不会自动起来。2.3 Windows下安装与日常使用Windows上用nginx做开发环境代理也很常见。下载Windows版压缩包后解压目录里直接有nginx.exe不需要安装程序。启动方式是在nginx根目录执行start nginx.exe首次启动不建议双击exe而是在命令行里先执行nginx.exe -t做配置检查确认没问题再启动。Windows版默认监听80端口如果本机IIS或其他服务占用了80启动会失败通过修改conf/nginx.conf里的listen端口即可规避。日常查看运行状态用tasklist | findstr nginx关闭用nginx.exe -s stop。Windows版nginx的性能远不如Linux版事件模型和文件缓存机制有明显差异所以我只在Windows上做开发联调生产环境一律用Linux。这一点在团队协作时最好提前说明免得有同事在Windows上测得好好的部署到Linux后因为路径分隔符、权限模型、目录结构差异出现莫名其妙的问题。开发环境可以随便折腾生产环境还是要守住底线。3. 配置篇静态资源、反向代理、负载均衡逐个击破3.1 nginx.conf的骨架与关键指令nginx的配置文件核心结构就三块main全局配置、events事件模型、httpHTTP服务配置。http块内部有server块server块内部有location块这种逐层嵌套的结构本质上是在描述怎么接收请求、按什么规则分发请求、请求转到哪里去。我见过不少刚接触的人看到几百行的默认配置就发怵其实真正要改的地方不多。优先掌握这几个指令就够了worker_processes建议设为auto由系统按CPU核心数自动分配worker_connections单个worker的最大并发连接数配合系统文件描述符上限调整server_name虚拟主机名决定哪个域名或IP命中哪个server块location路径匹配规则决定请求资源由谁处理3.2 静态资源服务与文件共享目录nginx托管静态文件是它最基础的用法。把前端打包后的dist目录指向一个server或开放一个目录作为文件下载服务配置如下server { listen 80; server_name files.example.com; location / { root /data/files; index index.html; autoindex on; autoindex_exact_size off; autoindex_localtime on; } }autoindex on这条指令很多人不知道它开启后访问目录会直接生成文件列表页面相当于瞬间拥有一个简易网盘非常适合团队内部共享安装包、制品产物和日志。配合limit_rate 512k这类限速指令还能控制下载带宽避免有人拉大文件把业务流量打满。静态文件服务有几个性能优化点一是开启gzip压缩静态资源二是配置expires缓存头三是用open_file_cache缓存文件句柄。这些配置加起来不到十行却能让静态资源的加载速度有非常明显的提升尤其是图片、JS、CSS这些体积不大但数量很多的文件。这个优化对高并发场景尤其重要因为省下的不是CPU而是磁盘I/O和系统调用次数。3.3 反向代理配置详解反向代理是nginx在生产环境应用最广的玩法。简单说nginx接收外部请求按照规则转发给内网的后端服务再把后端的响应返回给客户端。这个过程对客户端完全透明客户端只知道自己在跟nginx通信。正向代理是替客户端访问外部资源反向代理是替后端服务接收外部流量方向正好相反这是理解反向代理的一个关键点。一个典型的反向代理配置大概长这样location /api/ { proxy_pass http://127.0.0.1:8080; 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_connect_timeout 60s; proxy_read_timeout 120s; proxy_send_timeout 120s; }proxy_set_header这几行是重点。后端应用如果拿不到客户端真实IP就必须靠X-Real-IP或X-Forwarded-For这些头字段否则后端日志记录到的全是nginx的IP排查用户问题时就什么都看不清。我经常被问到为什么后端看不到真实IP十有八九就是这些请求头没有传。另外要注意的是如果后端是个需要记录客户端来源的登录或风控系统这类头缺失甚至会导致业务功能异常不只是日志问题。3.4 负载均衡与上游策略当后端服务有多台实例时nginx的upstream模块就派上用场了。在http块中声明一组后端服务器server块里通过proxy_pass把流量分发过去常用的策略包括轮询、权重、ip_hash等upstream backend_web { server 192.168.1.10:8080 weight3; server 192.168.1.11:8080 weight1; server 192.168.1.12:8080 backup; } location / { proxy_pass http://backend_web; }weight参数控制权重权重高的实例承担更多流量适合多台机器配置不一致的场景backup标记备用节点正常情况下不接收流量只有其他节点全部不可用时才启用。如果业务要求同一客户端始终访问同一台后端比如Session没有做集中化存储就用ip_hash策略按客户端IP的hash值分配节点这样同一用户的请求总会落在同一台后端上。负载均衡的细节坑不少upstream里某个节点宕机后max_fails和fail_timeout参数控制着故障剔除机制合理配置可以避免请求反复打向已经挂掉的节点。我习惯把fail_timeout设成30smax_fails设成3这样单节点故障时nginx会在30秒内快速摘除问题节点节点恢复后下一个周期自然重新加入流量。这个机制对稳定性影响很大建议在演示或生产验证时开启access log观察分流情况确认策略真的按预期工作。4. SSL证书接入HTTPS落地全过程4.1 证书从哪来、怎么选给nginx配置HTTPS核心是拿到一张SSL证书。证书按验证级别分为DV域名验证、OV组织验证、EV增强验证个人网站和一般企业用到DV级别就够了。获取途径上有云厂商提供的免费证书、Lets Encrypt免费证书也有收费的商业证书。免费证书通常有效期为90天或一年商用证书有效期更长但价格不便宜。如果项目规模不大从云厂商控制台申请免费证书是最省事的路径。关于nginx的SSL证书格式一般拿到的是PEM格式的证书文件和私钥文件扩展名可能是.crt、.pem、.key。有些证书服务商还提供nginx专用类型的证书下载包里面会明确区分证书链和私钥目录结构开箱即用。下载证书时优先选nginx类型可以省去后面自己拼接证书链的麻烦。这里多说一句证书私钥是敏感信息千万不能提交到代码仓库也不能让普通开发人员随意接触否则等于把HTTPS的防线拱手送人。4.2 nginx开启SSL的配置实操nginx开启HTTPS的核心配置很简单在server块内增加443监听和证书路径指定server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/certs/example.com.crt; ssl_certificate_key /etc/nginx/certs/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; }配置里有两个坑必须提醒。第一证书目录的权限要保证nginx的worker进程能读私钥文件尤其要注意建议设置为640且属主为root或nginx用户权限给太大有泄露风险给太小又会让nginx启动失败第二证书链文件如果服务商有单独提供要与主证书合并到一个文件里或者用ssl_trusted_certificate单独指定否则部分客户端会因为证书链不完整而报错表现就是浏览器明明访问的是HTTPS站点却一直提示证书不受信任。配置完成后执行nginx -t检查语法确认无误后nginx -s reload让配置生效。这里有个经验配置完HTTPS后一定要用浏览器和curl双重验证证书链完整性因为有些老设备对证书链的校验特别严格缺少中间证书直接拒绝连接。用curl双向验证的命令可以参考curl -v https://example.com --resolve example.com:443:127.0.0.14.3 HTTP强制跳转HTTPS配置好HTTPS之后还要解决用户通过http访问的转化问题。如果用户直接输入域名默认走的还是80端口的HTTP不处理就会看到站点无法访问或内容不加密。常规做法是在80端口的server块里做一个301跳转server { listen 80; server_name example.com; return 301 https://$host$request_uri; }这段配置的含义是所有80端口的请求都返回301状态码并带上完整的HTTPS地址浏览器自动发起新的HTTPS请求。这里要注意不要用302代替301。301是永久重定向浏览器会缓存跳转结果后续访问直接走HTTPS省去一次跳转302是临时重定向每次访问都要先请求一遍HTTP再跳转白白增加延迟。搜索引擎优化也倾向301因为这不稀释域名权重。5. 平滑升级与版本更迭的实操心得5.1 为什么nginx可以做到不停服升级nginx的架构是master进程管理多个worker进程。master负责监听端口、管理worker生命周期worker负责实际处理请求。升级时只需要用新版本二进制替换master进程老的worker在处理完当前请求后自然退出新请求由新版本的worker接管。这个设计让nginx可以不停服升级对生产环境来说是个巨大的优势不用再为升级专门申请维护窗口了。深入了解这个机制你会发现nginx的信号控制是平滑升级的核心。USR2信号让master启动新的master进程WINCH信号让老的worker优雅退出HUP信号用于重载配置或做回滚。理解了这几个信号的作用整个升级过程就不再是死记硬背的几条命令而是一套可以灵活组合的操作方法。5.2 平滑升级完整步骤平滑升级的步骤我按实际操作为准整理一遍。假设当前nginx版本是1.20.x要升到1.22.x# 1. 确认当前版本 /usr/local/nginx/sbin/nginx -v # 2. 下载并编译新版本prefix参数保持一致 ./configure --prefix/usr/local/nginx --with-http_ssl_module make -j4 # 3. 备份旧二进制替换新二进制 mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old cp objs/nginx /usr/local/nginx/sbin/nginx # 4. 发送USR2信号让master用新二进制启动新的master kill -USR2 cat /usr/local/nginx/logs/nginx.pid # 5. 发送WINCH信号让老的worker进程逐步退出 kill -WINCH cat /usr/local/nginx/logs/nginx.pid.oldbin执行完第5步老的worker会全部退出新worker正常接管。此时nginx -v查看版本已经变成新版本。如果升级后发现问题可以随时用老二进制回滚# 恢复老版本处理请求 kill -HUP cat /usr/local/nginx/logs/nginx.pid.oldbin # 再关闭新master的worker kill -TERM cat /usr/local/nginx/logs/nginx.pid这个操作我强烈建议在测试环境完整演练一遍。生产环境如果流量大升级前的日志、监控、备份策略都要提前想好。我曾经在升级时漏了备份自定义模块的编译参数结果新二进制加载动态模块失败幸好有回滚流程影响面才控制住。对于有动态模块的nginx升级前建议把configure参数完整导出归档新版本编译时尽量沿用原有参数把差异降到最小。5.3 卸载nginx的正确姿势卸载nginx也是要分场景的。如果是编译安装的直接rm -rf把安装目录删掉再把/etc/init.d/下的自启脚本或systemd service文件一并清掉如果是yum/apt安装的用对应命令卸载。但这里有一个常被忽略的细节nginx的日志文件、临时目录、pid文件默认都留在安装目录直接删目录会把历史日志也一起带走。如果这些日志要用于审计或问题回溯先把logs目录拷贝出来再删。另外如果之前编译安装时加入了自定义模块旧版本卸载时这些模块不会自动清理重新安装新版本时可能会因为模块路径冲突而报错。我习惯在每次编译安装时把./configure的参数用tee保存为一份记录文件放在安装目录同级位置确保几个月后要重装也能快速复现原来的构建环境。这个习惯看起来不起眼遇到紧急的版本回退时会显得非常重要。6. 高频问题排查与面试点整理6.1 常见问题速查表排障是nginx日常使用里最考验经验的部分。这几年遇到过的典型问题不少我把最有代表性的整理成一张速查表方便大家按图索骥问题现象排查思路与解法502 Bad Gateway上游服务无响应或连接失败查看upstream节点状态、防火墙策略、服务是否监听在预期端口504 Gateway Timeout上游响应超时调大proxy_read_timeout排查后端慢查询确认是否有必要放宽超时413 Request Entity Too Large上传文件过大调大client_max_body_size同时确认后端上传大小限制403 Forbidden静态文件目录无权限检查root目录权限、index文件是否存在、autoindex配置404 Not Found路径匹配不上检查location匹配规则注意root与alias混用时的语义差异端口被占用启动失败用netstat或ss命令查看端口占用修改listen或释放端口证书不生效浏览器提示不安全检查证书链是否完整、私钥与证书是否匹配、443端口是否正常监听每个问题都要配一个逐层排除的思路。比如502先确认后端服务进程还在不在再用telnet或nc测一下端口通不通最后看nginx的错误日志error.log里有没有connect() failed的详细记录按这个顺序排查通常五分钟内能定位根因。不要一遇到问题就重启nginx那样大概率只是把症状掩盖住根子上的问题还在后面还会复发。6.2 归一化处理nginx面试高频考点如果你在准备面试nginx相关的题目也很有规律。高频的包括nginx与Apache的定位差异、nginx的epoll事件驱动模型如何工作、反向代理与正向代理的本质区别、负载均衡有哪些算法及适用场景、如何配置HTTPS与证书链、平滑升级的原理、worker进程数和连接数如何设置、如何做动静分离。这些问题本质上是在考配置能力原理理解的组合。面试官真正想听的往往不是死记硬背的答案而是你对取舍的理解。比如问worker_processes设多少不要只回答CPU核心数而是要说清楚为什么匹配CPU核心数每个worker是一个独立的事件循环worker太多会导致上下文切换开销增加太少又无法充分利用多核另外还要关心worker_connections与系统文件描述符上限的关系这两条参数是配套调整的单看一个没有意义。这种从原理出发的答题方式很容易和背题的人拉开差距。提示动手实践永远比背题管用。自己搭一台虚拟机把nginx装好依次配置静态站点、反向代理、负载均衡和HTTPS很多原理层面的东西会在操作过程中突然想通。等你能调通一主一备的upstream配置再回头看面试题会发现它们其实都是同一个知识体系的不同切面。6.3 日志分析与排障利器日志分析是排障绕不开的环节。nginx的access log和error log是两个完全不同的东西access log记录每一次请求的访问明细格式可以在log_format指令里自定义建议把耗时、状态码、上游地址、客户端IP都记全error log记录的是nginx自身或上游交互过程中的错误信息排查502、504时重点看它。我见过很多人在排障时只盯access log翻半天看不明白其实真正的报错原因就在error log里两行就讲清楚了。如果流量比较大日志轮转也是要提前考虑的。生产环境建议用logrotate按天切割access log避免单个日志文件膨胀到几个GB后排查时连grep都跑不动。配置了切割后nginx需要执行USR1信号重开日志文件否则日志写入的还是旧的已切割文件句柄配合不好会出现日志丢数据的假象。这个细节在交接运维时经常被忽略但影响很实在。我自己还有一个习惯每次排障完会把问题的现象、排查路径、根因和解决办法整理成一条笔记放到团队知识库里。nginx的问题很多是重复的过几个月再遇到类似场景直接翻笔记就能少走弯路比临时查文档高效得多。这个习惯坚持下来你对nginx的理解会积累得很快。这也是做运维和开发工作最值得长期投入的一件事把踩过的坑变成可复用的经验。
返回列表