
Nginx这个名字后端和运维的朋友每天都要打交道。部署前端项目要用它给后端接口做反向代理要用它负载均衡、HTTPS证书、日志切割几乎每个环节都有它的影子。我当年刚接触时也被一堆配置项搞得头大location、proxy_pass、upstream这些东西看着就懵。后面踩了不少坑才把整条链路理顺。这篇博文就按“速成”的思路来写不铺开讲理论直接从“把服务跑起来”到“能接真实项目”把日常工作里最常用到的Nginx技能讲透。无论你是刚转行做运维的新人还是被临时拉去配服务器的后端开发看完这篇基本能上手处理绝大多数场景。很多人一学Nginx就去啃官方文档结果几千页的Manual直接把人劝退。我的经验是Nginx入门不需要全套知识你只需要搞懂三件事怎么装、怎么配、怎么查日志。这三件事搞定了你就能解决90%的日常问题。剩下的10%遇到再搜也不迟。1. 先搞清楚Nginx到底在解决什么问题1.1 Nginx的角色定位网上把Nginx吹得天花乱坠什么高并发、高性能、异步非阻塞这些词汇对于一个刚入门的人来说其实没有任何帮助。我换个方式给你讲。你把Nginx想象成一个物业前台。访客来了先到前台前台根据访客要拜访哪户人家告诉他去几栋几单元如果他要找的人不在前台还能帮忙把消息记录下来等他回来了再转交。这个“告诉访客去哪找对应服务”的动作就是反向代理如果小区有多栋楼都住着同一个公司的人前台帮忙分流让访客分别去不同楼找人这就是负载均衡如果访客只是想在楼下大堂看看宣传册不用上楼前台直接递给他一份这就是静态资源服务。这样一比喻就清楚了。Nginx是一个高性能的HTTP服务器和反向代理服务器它站在用户请求和后端服务之间统一接收请求再按照你配置的规则把请求转发给对应的处理程序。我们日常工作中90%的Nginx配置都是围绕着“转发规则”来做的。1.2 速成的正确姿势按场景学配置很多教程喜欢把Nginx的配置文件从头到尾一行行讲这对新手来说其实是灾难。因为配置文件里的几十个指令你实际工作中可能一年都用不到一半。我的建议是按场景去学。你遇到了“前端页面打不开”的问题就去查server块怎么配你遇到了“接口请求503”就去查proxy_pass怎么配你遇到了“服务器扛不住高并发”再去研究upstream和负载均衡策略。场景驱动学习效率远高于从第一行读到最后一行的“教科书式学习”。这篇文章后面所有的内容我都按照这个思路来组织。每个章节解决一类真实场景你把这个场景对应的配置吃透下次再遇到类似问题就能直接拍板。2. 安装与启动先把Nginx跑起来2.1 Linux环境下的安装与启动命令绝大多数生产环境都是Linux所以先从Linux说起。以CentOS和Ubuntu两个最常见的发行版为例。CentOS/RHEL系列使用yum安装但默认源里的Nginx版本通常比较老建议先添加Nginx官方源再安装# 添加官方源 sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm # 安装 sudo yum install -y nginx # 启动 sudo systemctl start nginx # 设置开机自启 sudo systemctl enable nginx # 查看运行状态 sudo systemctl status nginxUbuntu/Debian系列用apt安装sudo apt update sudo apt install -y nginx # 启动 sudo systemctl start nginx # 开机自启 sudo systemctl enable nginx还有一个容易被新手忽略的细节改完配置后要测试配置文件语法是否正确。用nginx -t如果输出syntax is ok和test is successful再执行重载。千万不要改完配置直接重启服务万一语法写错了服务可能会直接挂掉线上业务就断了。# 测试配置语法 nginx -t # 配置无误后重新加载 nginx -s reloadreload和restart的区别得说清楚。reload是平滑重载Nginx会先检查新配置语法然后把旧的worker进程慢慢停掉用新配置启动新的worker进程正在处理的请求不会中断。而restart是强制重启所有连接都会断开。生产环境里尽量用reload不要用restart。如果你是Ubuntu 14.04这类老系统没有systemd那就会用到init.d脚本。/etc/init.d/nginx start、/etc/init.d/nginx stop、/etc/init.d/nginx reload这套老命令现在虽然用得少了但在一些存量服务器上还是能碰到。2.2 Windows环境部署NginxWindows服务器上部署Nginx也很常见尤其是Windows Server 2016、2019这些系统。Nginx官方提供了Windows版本直接去官网下载zip压缩包解压就能用不需要安装。下载的时候注意看版本号Windows版本没有官方预编译的稳定版标识建议选择mainline版本以外的stable稳定版。解压出来的目录结构是这样的C:\nginx-1.24.0\ ├── conf\ # 配置文件目录 ├── contrib\ ├── docs\ ├── html\ # 默认站点目录 ├── logs\ # 日志目录 ├── temp\ └── nginx.exe # 主程序Windows下启动Nginx直接在命令行里执行cd C:\nginx-1.24.0 start nginx.exe注意这里要用start不用start的话命令行窗口会被Nginx进程占住关掉窗口Nginx就停了。用start启动后Nginx会在后台运行。停止和重载的命令nginx.exe -s stop # 强制停止 nginx.exe -s reload # 重新加载配置 nginx.exe -t # 测试配置语法Windows下改端口是高频操作。很多人装完Nginx发现启动不了进去看日志才发现是80端口被占用。IIS、SQL Server Reporting Services这些服务都会抢80端口。改端口很简单打开conf目录下的nginx.conf找到listen 80;改成你想要的端口比如listen 8080;保存后执行nginx -s reload即可。我个人的经验是Windows机器上最好把Nginx注册成Windows服务来管理不然每次开机都要手动启动。用NSSMNon-Sucking Service Manager这个小工具一行命令就能把nginx.exe注册为服务nssm install nginx C:\nginx-1.24.0\nginx.exe nssm set nginx AppParameters -p C:\nginx-1.24.0 nssm start nginx这样Nginx就能跟随Windows开机自启也能通过服务管理器统一管理。2.3 安装后的第一件事验证进程与页面无论哪种系统装完Nginx后都要做两件事确认进程活着、确认页面能打开。# 确认进程存在 ps -ef | grep nginx # 确认端口监听 netstat -tlnp | grep 80 # 用curl抓取默认页面 curl http://localhost如果看到了Welcome to nginx!的页面恭喜你Nginx已经跑起来了。接下来所有的工作都是基于这个跑起来的服务做配置。3. 配置文件逐段拆解nginx.conf到底写了什么3.1 从整体结构入手全局块、events块、http块Nginx的默认配置文件路径在Linux下通常是/etc/nginx/nginx.confWindows下在conf\nginx.conf。打开这个文件整体结构大致是这样的# 全局块全局生效通常配置运行用户、worker进程数等 user nginx; worker_processes auto; # events块配置连接处理机制 events { worker_connections 1024; } # http块HTTP服务器的核心配置绝大部分配置都在这里 http { include /etc/nginx/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; # 虚拟主机配置 server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } } }我见过不少新手一上来就盯着location看其实整个配置文件的骨架就三段全局块管的是Nginx进程本身跑在什么环境下events块管的是连接怎么处理http块管的是网页服务怎么做。你理解了这三层配置文件在你眼里就不是天书了。这里有个高频面试题也是高频实际疑问worker_processes和worker_connections到底怎么设置worker_processes建议设为CPU核心数可以用auto自动检测worker_connections表示每个worker进程能同时保持的最大连接数。两者相乘大致就是Nginx能支撑的最大并发连接数。机器是4核CPUworker_processes设置为4worker_connections设置为1024最大并发就是4096这个指标对你评估服务器容量有直接参考意义。3.2 server块和location块是配置的核心server块代表一个虚拟主机。一个Nginx可以配置多个server通过listen的端口号和server_name的域名来区分请求应该交给哪个server处理。location块是server内部的路由规则。它匹配的是URL中域名后面的路径部分。举个实际例子server { listen 80; server_name example.com; # 匹配所有请求 location / { proxy_pass http://backend_server; } # 以/api开头的请求 location /api/ { proxy_pass http://api_server; } # 以.png结尾的请求 location ~ \.png$ { root /data/images; } }关于location的匹配规则网上讨论很多我直接给你一个优先级结论精确匹配优先级最高匹配到了直接使用不再往下找^~前缀匹配如果匹配到了且是最长前缀就不再看正则~和~*正则匹配按书写顺序匹配找到即停/通用前缀匹配兜底规则所有请求都匹配这个优先级背下来就行实际配置里最常用的是location /、location /api/和location /后两个是健康检查常配的路径。3.3 修改配置后如何让改动生效这里必须要强调完整流程了。我见过太多生产事故都是因为改完配置直接restart导致的。正确的操作流程是# 第一步修改配置文件建议先备份原始文件 cp nginx.conf nginx.conf.bak # 第二步检查语法 nginx -t # 第三步平滑重载 nginx -s reloadnginx -t这个命令太重要了。它会帮你检查配置文件语法如果有错误会明确告诉你第几行有问题。我在真实项目里养成一个习惯凡是涉及配置变更哪怕只是改一个数字也要走一遍nginx -t再reload这个习惯帮我避免了好几次线上故障。4. 三大高频实战场景一次讲透4.1 反向代理一个入口访问多个内部服务公司内部往往有很多服务Java的Spring Boot应用、Python的Flask应用、Node.js服务各自跑在不同的端口上。总不能每个服务都让用户记一个端口去访问这时候Nginx就派上用场了。我举个例子。一台服务器上有两个服务Java服务跑在8080端口处理/api/请求Vue前端跑在3000端口处理静态页面使用Nginx做一个反向代理统一从80端口入口server { listen 80; server_name www.example.com; # 前端页面请求转发到Vue开发服务器 location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # API请求转发到Java后端 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_set_header这三行大部分人都知道要配但很多人不理解为什么。我来解释一下。Nginx做反向代理时后端服务收到的请求来源是Nginx本身而不是真实的客户端。X-Real-IP和X-Forwarded-For这两个头就是用来传递真实客户端IP的。后端应用读取访问日志或者做用户行为分析时如果没有这两个头拿到的IP全是Nginx服务器的IP那日志就没有任何分析价值了。另外说一句代理到TongWeb这类国产Java中间件时配置方式基本一样都是location加proxy_pass。TongWeb有时候对请求头校验更严格proxy_set_header Host $host;必须配上否则后端拿到的Host是内网IP可能会触发一些校验逻辑。4.2 负载均衡upstream后端集群配置一台服务器扛不住流量了怎么办最直接的办法是多加几台服务器然后用Nginx把请求分发到各个服务器上。这就是负载均衡。Nginx的负载均衡通过upstream指令实现。我在实际项目里最常用的配置是这样的upstream backend_cluster { # 不写任何策略的话默认是轮询 server 192.168.1.10:8080 weight3; server 192.168.1.11:8080 weight1; server 192.168.1.12:8080 backup; } server { listen 80; server_name example.com; location / { proxy_pass http://backend_cluster; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }上面这个配置里192.168.1.10和192.168.1.11是两台正常的后端服务器请求会按照3:1的比例轮询分发。192.168.1.12是备用服务器只有前两台都挂了才会接手请求。这种“主备权重”的混合架构处理中小规模流量的高可用场景已经足够了。Nginx支持几种负载均衡算法我整理了一下算法关键字适用场景轮询默认后端服务器配置相近的场景加权轮询weight服务器性能有差异的场景IP哈希ip_hash需要客户端会话保持的场景最少连接least_conn请求处理时间差异大的场景一致性哈希hash $request_uri需要按URL分发的缓存场景这里最大的坑在于会话保持。如果后端应用用了Session没有做分布式Session共享那你用了默认的轮询策略后用户第一次请求被分到A服务器登录了第二次请求被分到B服务器B服务器没有这个用户的Session就会提示未登录。最简单的解决办法是用ip_hash让同一个IP的请求始终保持在同一台服务器上。当然更好的方案是改造后端使用Redis等中间件做Session共享但那属于后端开发的范畴这里不展开。如果后端是OpenShift这类容器平台上的服务反向代理配置也是同样的思路。OpenShift的路由本身可以做流量分发但如果你的集群没有暴露外部路由或者需要通过统一的Nginx入口管理多个集群服务就可以把OpenShift的服务地址直接写进upstreamupstream openshift_service { server myapp-myproject.apps.internal.example.com:443; } server { listen 8443 ssl; server_name myapp.example.com; location / { proxy_pass https://openshift_service; proxy_set_header Host myapp-myproject.apps.internal.example.com; } }需要注意HTTPS后端和SSL证书的头传递问题这种场景下proxy_ssl_server_name on;和proxy_set_header要配合着设置否则后端证书校验会失败。4.3 部署Vue3等静态项目root与alias的区别前后端分离的项目越来越多前端构建出来的dist目录直接交给Nginx托管部署方式堪称最简单但又最容易配错的一个场景。很多人在两个指令上栽过跟头root和alias。先说结论root会把location中的路径拼接到root指定的目录后面alias会用alias指定的目录直接替换location中的路径举个例子。访问http://example.com/vue3/假设项目文件在/data/projects/vue3/dist目录下使用root配置location /vue3/ { root /data/projects/vue3/dist; }实际访问路径是/data/projects/vue3/dist/vue3/明显不对会404。因为root会把URL中的/vue3/拼上去。使用alias配置location /vue3/ { alias /data/projects/vue3/dist/; }实际访问路径是/data/projects/vue3/dist/这才是正确的结果。因为alias用后面的路径直接替换了/vue3/这个前缀。这个坑我见过太多次了。新手部署Vue项目用root配置半天打不开页面打开F12看到404第一反应是后端接口问题查了一圈才发现是路径映射错了。部署Vue3项目还有一个绕不开的问题history路由。Vue3默认使用history模式的话URL里没有#号比如http://example.com/user/1。这个路径在Nginx层面是不存在的文件直接访问会404。解决方案是加一个try_files指令server { listen 80; server_name example.com; root /data/projects/demo/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://backend_api; } }try_files $uri $uri/ /index.html的含义是先查找请求对应的真实文件找不到就尝试找目录目录也找不到就返回index.html。这样无论前端路由怎么跳刷新页面时Nginx都会返回前端入口文件再由Vue Router接管并渲染对应页面。Windows服务器上部署Vue3项目思路一样只是路径分隔符要写成Windows风格alias D:/projects/vue3/dist/;。注意Windows下路径末尾的斜杠也别落下不然路径拼接时会出问题。5. Docker部署Nginx并挂载多个项目目录5.1 镜像版本怎么选Docker化部署在现在的环境里几乎成了标配。使用docker pull nginx拉取镜像时很多人直接不写版本号拉个latest回来。我个人建议明确指定版本号比如docker pull nginx:1.21.5。原因很简单latest标签会跟随上游更新而变化今天拉的是1.24过阵子再拉可能就变成1.26了大版本迭代往往伴随着配置指令行为的变化可能会导致你的配置文件突然失效。生产环境明确锁定版本号之后的部署行为才是可预期、可复现的。# 拉取指定版本 docker pull nginx:1.21.5 # 查看本地镜像 docker images | grep nginx5.2 挂载多项目目录的目录设计用Docker跑Nginx最大的优势之一就是挂载宿主机目录这样修改配置文件和部署前端代码时都不需要重新构建镜像。以一台要部署三个项目目录的服务器为例我会这样设计目录结构/opt/nginx/ ├── conf.d/ # 存放各个项目的server配置文件 │ ├── project-a.conf │ ├── project-b.conf │ └── project-c.conf ├── html/ │ ├── project-a/ # 项目A的静态文件 │ ├── project-b/ # 项目B的静态文件 │ └── project-c/ # 项目C的静态文件 ├── logs/ │ ├── access.log │ └── error.log └── nginx.conf # 主配置文件容器启动命令docker run -d \ --name nginx \ -p 80:80 \ -p 443:443 \ -v /opt/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /opt/nginx/conf.d:/etc/nginx/conf.d:ro \ -v /opt/nginx/html:/usr/share/nginx/html:ro \ -v /opt/nginx/logs:/var/log/nginx \ --restartalways \ nginx:1.21.5这里我解释几个关键参数的含义。-p 80:80是把宿主机的80端口映射到容器的80端口只有做了这个映射外部的请求才能进入容器内的Nginx。-v是挂载目录冒号前面是宿主机路径后面是容器内路径:ro表示只读挂载防止容器内进程意外修改配置。--restartalways确保Docker服务重启后容器会自动拉起这是生产环境的保命配置。启动完成后进容器验证一下Nginx是否正常# 进入容器 docker exec -it nginx bash # 测试配置文件语法 nginx -t # 查看当前生效的配置 nginx -T如果你使用的是docker compose配置会更清晰version: 3.8 services: nginx: image: nginx:1.21.5 container_name: nginx ports: - 80:80 - 443:443 volumes: - /opt/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - /opt/nginx/conf.d:/etc/nginx/conf.d:ro - /opt/nginx/html:/usr/share/nginx/html:ro - /opt/nginx/logs:/var/log/nginx restart: always要注意的是Docker容器内的Nginx配置路径和物理机有所区别比如/etc/nginx/conf.d/这个目录在部分官方镜像的默认nginx.conf里是通过include指令引入的。如果你改了主配置或者新增了conf.d下的文件必须reload或重启容器才生效# 执行nginx -t并reload docker exec nginx nginx -t docker exec nginx nginx -s reload还有一种场景是编译Nginx时动态链接第三方库比如要添加http_sub_module做反向代理内容替换、添加http_stub_status_module做状态监控。官方镜像默认是不带这些模块的需要自己编译或者找包含这些模块的镜像。如果你只是需要字符替换功能Nginx内置的sub_filter指令其实就够了改一下配置就能用location / { proxy_pass http://backend; sub_filter 旧内容 新内容; sub_filter_once off; }这个指令在做反向代理时替换页面文本很有用比如后端返回的静态资源路径是/static/你希望通过Nginx改成CDN地址/cdn/static/就能用sub_filter实现。6. 日志、SSL与常见问题排查6.1 日志路径与常见定位手段日志是排查Nginx问题时最重要的线索也是很多新手最容易忽视的部分。默认情况下Nginx的访问日志和错误日志路径在Linux/var/log/nginx/access.log和/var/log/nginx/error.logWindowsnginx安装目录下的logs\access.log和logs\error.logDocker启动时-v挂载的宿主机目录比如上面的/opt/nginx/logs/调试的时候优先看error.log里面会记录具体的错误原因。比如端口被占用、配置文件语法错误、worker进程启动失败都会在这里留下记录。我举个例子。启动Nginx时报错错误日志里写[emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)这说明80端口被占用了。排查方法# 查看80端口被哪个进程占用 lsof -i :80 # 或 netstat -tlnp | grep 80拿到占用进程的PID后确认是可杀掉的进程就停掉再重新启动Nginx。这个问题的出现频率极高尤其是Windows机器IIS默认监听80端口安装Nginx后经常冲突。日志还有一个使用场景核对请求有没有打到预期的后端。客户反馈“某个接口特别慢”你先打开access.log看看对应接口的request_time和upstream_response_time两个字段基本就能判断是Nginx层慢还是后端服务慢。6.2 配置HTTPS私钥类型与证书链现在部署HTTPS几乎成了标配。Nginx配置HTTPS的核心就是证书和私钥。很多人在这一块遇到迷惑Nginx支持哪几种类型的私钥Nginx支持的是PEM格式的私钥内容以-----BEGIN PRIVATE KEY-----或-----BEGIN RSA PRIVATE KEY-----开头。常见的私钥类型包括私钥格式Nginx是否支持说明PEM支持最常见的格式文本可读DER需要转换二进制格式需要转成PEMPFX/P12不支持直接使用Windows常见的证书格式需转换JKS不支持Java环境常见需转成PEM如果你拿到的是PFX格式的证书很多Windows服务器申请证书时会导出成这个格式就不能直接给Nginx用需要先用OpenSSL转换# 将PFX格式证书转为PEM格式证书和私钥 openssl pkcs12 -in certificate.pfx -out certificate.pem -nodes转换完成后Nginx配置大概是这样的server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.crt; ssl_certificate_key /etc/nginx/ssl/example.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://backend; } }配置HTTPS时我最常遇到的坑是证书文件路径写错或者证书链不完整。访问时一直报“证书无效”但浏览器查看证书看不出问题。这种情况多半是部署时只上传了站点证书没有上传中间证书链。正确的做法是把站点证书和中间证书合并成一个文件或者用ssl_trusted_certificate指定证书链文件。6.3 常见问题速查表最后把高频问题整理成一张速查表方便你实际排查时对照使用。现象可能原因排查思路首页显示Welcome to nginx而不是自己项目的页面server块的root或index配置没生效检查server_name和listen配置是否匹配了当前访问的域名和端口页面404root路径不对或location匹配不到检查root/alias路径检查location块的匹配规则接口能通但前端页面刷新404前端使用的是history路由给location / 加上try_files配置502 Bad Gateway后端服务没启动或端口不对检查proxy_pass指向的内网地址和端口能否访问504 Gateway Timeout后端处理请求超时适当增大proxy_read_timeout参数403 Forbidden权限问题检查静态文件目录的Linux读写权限index文件是否存在启动时报Address already in use端口被其他进程占用lsof或netstat查端口占用停掉冲突进程或改Nginx监听端口这里额外说一个排查效率技巧每次修改Nginx配置后如果出现异常第一反应不要直接百度错误信息而是先做两个动作# 1. 测试配置语法 nginx -t # 2. 查看错误日志最近20行 tail -n 20 /var/log/nginx/error.log这两个命令能解决80%的Nginx问题。剩下的20%才是配置逻辑层面的问题需要结合上文提到的location匹配规则、proxy_pass路径拼接等知识去分析。还有一个处理方案值得一提当你手头恰好没有测试环境又不敢直接动生产配置可以复制一份Nginx配置修改listen端口比如改成8081然后单独启动一个Nginx实例去做验证。确认没问题后再去改生产配置。这个操作我做过不止一次稳妥可靠。等你把上面这些场景都跑通了Nginx的基本盘就算拿下了。后面再遇到更复杂的场景比如HTTP/2、gzip压缩调优、缓存配置、限流防刷、日志按天切割都是基于这篇文章的骨架去扩展。我自己刚接触Nginx时也是从“配一个能用的代理”开始的很多指令只有亲手配过、踩过坑才记得牢。如果这篇文章能帮你少走几个弯路那目的就达到了。