ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Windows下Nginx实战:从安装配置到反向代理与常用命令详解

Windows下Nginx实战:从安装配置到反向代理与常用命令详解 1. 先搞清楚Windows版Nginx的定位再决定要不要装1.1 为什么Windows版不是“Linux版换个壳”先说结论Nginx在Windows上能用但它从设计之初就是为类Unix系统服务的。官方文档对Windows版有几条很实诚的说明——性能上限低于Linux、不支持某些负载均衡算法、连静态文件发送都会走效率更低的路径。原因在于Linux上Nginx赖以成名的是epoll事件驱动模型Windows没有这个机制只能退化为select轮询高并发连接数上来之后性能衰减非常明显。但是“性能不如Linux”不等于“不能用”。我自己的经验是在Windows上跑Nginx最常见的用途有三类一是本地开发环境的前端联调把不同端口的服务聚合到同一入口二是内网小工具站比如给团队提供静态文档、测试页面三是给老系统做一层反向代理用Nginx的规则去分发请求。这三类场景的连接数基本在几十到几百Windows版完全扛得住。有一个很容易被新手忽略的点Windows版Nginx是一个“解压即用”的原生应用没有安装程序也不需要往注册表里写东西。很多人第一次下载后打开压缩包看到里面是文件夹和exe会怀疑“这就算安装了”——对就这么朴素。这也意味着“卸载”就是删文件夹但运行时进程和端口依赖要处理干净后面我会单独讲。1.2 版本选择Mainline和Stable到底选哪个Nginx官网的下载页长期放着两个版本分类Mainline和Stable。Mainline是当前开发版功能更新快会带一些实验性特性适合想要尝鲜、并且遇到问题能自己查文档的人。Stable是稳定版经过一段时间验证修复了主要bug功能冻结。普通用户、线上环境、不想折腾的人我建议直接选Stable没必要为了几个新功能去当小白鼠。这里有一个新手最容易踩的坑下载页上文件名带Linux字样的包解压后没有exe文件因为那是给服务器用的二进制编译版。Windows用户要选文件名包含“Windows”的zip包解压后里面直接就是nginx.exe。另外不要从第三方站下载所谓“整合包”Nginx官网下载就很稳没必要为了省两步操作给自己埋雷。我建议的版本策略很简单个人学习、本地联调稳定版就行只要版本号在1.18以上基础功能都齐全需要WebSocket、HTTP/2这些能力选1.19以上的稳定版别碰Mainline公司内网生产环境用Stable大版本里的最新小版本把nginx -v记录在案方便日后回溯1.3 下载、解压与Windows路径的“反斜杠陷阱”下载地址是nginx.org/en/download.html进去找到“Windows”结尾的zip链接即可。解压时我强烈建议直接把目录放在磁盘根目录下面比如C:\nginx或D:\nginx不要套一层D:\software\nginx-1.26.2这种层级太深的路径更不要放在带空格的目录里比如C:\Program Files\nginx。Nginx的配置文件对这个不敏感但后续写批处理、注册服务、调参数的时候路径短会省掉无数麻烦。解压出来的目录是这样的目录/文件作用conf/所有配置文件核心是nginx.confhtml/默认站点首页目录里面有index.html和50x页面logs/运行日志最关键是error.logtemp/临时文件一般不用管nginx.exe主程序守护进程和worker进程都由它拉起这里要纠正一个非常常见的认知偏差nginx.exe不是一个“双击就能跑起来”的图形化软件。双击它之后一个命令行窗口会一闪而过然后你以为失败了其实它已经在后台运行了。正确方式是打开cmd切到Nginx目录用命令启动。Windows桌面上“双击运行”的习惯在Nginx这里完全不适用。2. 解压不是结束启动、验证与端口冲突排查2.1 启动的两种姿势和验证手段进入C:\nginx目录后启动命令推荐这么写cd C:\nginx start nginxstart是Windows命令行的用法作用是“在新窗口中启动程序并立即返回命令提示符”。这样Nginx就会在后台运行当前终端不会被占住。如果你图省事直接敲nginx.exe当前窗口就会被Nginx的前台进程占住关掉窗口就等于把服务关了所有请求瞬间断开。启动之后第一件事是验证它到底起来没有。我喜欢用三条命令tasklist /fi imagename eq nginx.exe这条命令会列出所有Nginx进程。正常情况你会看到两个进程一个是master进程一个是worker进程。如果只看到一个或完全看不到说明进程没有正常拉起。netstat -ano | findstr :80这条命令是查端口监听状态。Nginx默认监听80端口看到LISTENING状态且PID和上面tasklist查到的master进程PID一致那就OK了。最后打开浏览器访问http://localhost看到“Welcome to nginx!”页面整个安装启动流程就彻底通了。2.2 “80端口被占用”的完整排查链路这是我被问到最多的问题没有之一。浏览器打不开、netstat显示80端口被占用新手第一反应是“Nginx是不是坏了”。其实Nginx连跑的机会都没有因为监听端口被别人占了。排查链路一条条走netstat -ano | findstr :80第二步看最后一列PID然后用这个命令反查是谁tasklist /fi pid eq 1234把1234换成实际PID会看到占用端口的程序名。常见的嫌疑人包括IISWorld Wide Web Publishing Service、Apache、Skype旧版本喜欢占80/443、各种内网穿透工具。找到元凶之后要么停掉那个服务要么给Nginx换端口。如果你不想动别的服务就把Nginx的监听端口改成8080或别的空闲端口。改配置的方式在第三章讲这里先记住排查顺序先看端口再看PID最后决定是干掉别人还是自己让路。另外提一句防火墙弹窗如果出现了记得允许Nginx公网/专用网络访问否则局域网内别的机器访问不到。2.3 启动瞬间闪退多半是语法问题另一种常见现象是start nginx之后立刻弹了个窗口又消失了进程列表里干干净净。这种“闪退”绝大多数情况下不是Nginx本身坏了而是配置语法有问题。处理办法是先手动跑一次配置检查nginx -t命令会告诉你配置文件哪一行报错。新手最常见的两处错误一是每行指令结尾忘了写分号二是路径用了Windows习惯的反斜杠比如root D:\www;Nginx配置里路径要用正斜杠D:/www。改完再跑nginx -t显示syntax is ok和test is successful才算通过。3. 手把手配一份能直接用的nginx.conf3.1 配置结构整不明白后面全白搭nginx.conf是Nginx唯一的入口配置文件其他配置都可以通过include引进来。从结构上看它是一个层层嵌套的“套娃”events块定义连接处理方式http块所有HTTP相关配置的根容器server块代表一个虚拟主机对应一个域名加一组端口location块在server内部定义URL路径的匹配规则用一个不太严谨但好懂的类比http是整个城市server是城市里的一栋楼location是楼里的一个个房间。请求进入城市后先找对楼域名/端口再进对应的房间URL路径。Nginx的匹配逻辑是server通过listen和server_name做第一层定位location用uri前缀或正则做第二层定位。很多教程一上来就扔出一整屏配置读者复制粘贴之后改都不知道怎么改。我的建议是先把配置文件削到最小可运行状态只留一个server块跑通静态站点再一步步叠加反向代理、跨域这些功能。每加一个模块都先nginx -t验证比一次性写完再找错要高效得多。3.2 静态站点托管root与index的组合逻辑如果你只是想让一个目录里的网页通过Nginx访问配置非常简单server { listen 8080; server_name localhost; charset utf-8; location / { root D:/my-site; index index.html; } }这里有三点值得展开第一路径写法。root后面跟的路径在Windows下一定要用正斜杠或用双反斜杠转义。直接写成D:\my-site会上传报错因为Nginx会把反斜杠当成转义字符处理。第二root和index的分工不同。root决定请求最终映射到的物理目录index决定访问目录时默认找哪个文件。比如请求/映射到D:/my-site然后接着找index.html如果index配了多个按顺序尝试。第三charset utf-8这行很多人忽略。如果你的页面里包含中文且没有单独指定编码浏览器可能会用系统默认编码去解析导致乱码。加一行字符集声明能省很多不必要的麻烦。另外说个细节root和alias是截然不同的两个指令。root会把location的路径直接拼接在root后面例如location /static/ { root D:/my-site; }访问/static/a.js实际读取的是D:/my-site/static/a.js。而alias是替换location /static/ { alias D:/my-site/static/; }效果一样但语义更直接。初学时用root就好把整个站点的根目录放上去一劳永逸。3.3 改配置之后必须做的一件事nginx -tnginx.conf改完之后如果你直接重启Nginx重启过程中只要有一行语法错误整个服务就起不来了。所以业界有一个铁律任何配置改动都必须先过nginx -t。之所以强调这一步是因为nginx -t只是检查语法不会真的加载新配置。它能在毫秒级的时间内告诉你“有错”还是“没问题”错误信息会精确到行号和指令。改完配置执行nginx -t看到两行绿色的ok之后再执行热重载nginx -s reloadreload和restart的区别非常关键。reload是平滑重载master进程会重新加载配置文件并启动新worker进程然后优雅地关闭旧worker进程已经建立的连接不会中断。restart是粗暴地杀死所有进程再重新拉起线上环境如果有正在执行的请求全都会被掐断。自己学习时无所谓但如果你将来要在公司服务器上操作养成“改配置先-t然后reload而不是restart”的习惯会少背很多锅。4. 进阶必考反向代理与前后端联调的Nginx配置4.1 最经典的场景一个入口两个服务现在前后端分离几乎是标配。开发环境里前端Vue/React项目跑在8080端口后端Java或Node服务跑在8081端口浏览器访问时却经常出现跨域问题。与其在前端纸面上配置一堆代理不如直接用Nginx做一个统一入口把不同路径的请求分发到不同服务。配置长这样server { listen 80; server_name localhost; location /api/ { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { proxy_pass http://127.0.0.1:8080; } }这份配置的含义是所有以/api/开头的请求都转发给8081端口其余请求一律给8080端口的前端服务。proxy_set_header那一堆是传递客户端真实IP和原始Host头后端程序如果需要拿到用户真实IP做日志分析或访问控制这几个字段就非常关键。4.2 proxy_pass带不带斜杠结果完全不同这个坑我在刚接触Nginx时确实栽过后来带过的几个人也无一例外踩到。简单说proxy_pass后面的URL结尾有没有/决定了整个转发路径的拼接方式。拿上面的例子来看location /api/ { proxy_pass http://127.0.0.1:8081/; }当请求到达/api/user/login时Nginx会把location匹配到的/api/这一段“吃掉”然后拼上剩余的user/login最后发给后端的请求是http://127.0.0.1:8081/user/login。后端收到的是一个很干净的路径。但如果proxy_pass不带斜杠location /api/ { proxy_pass http://127.0.0.1:8081; }同样请求/api/user/loginNginx会原封不动把完整路径拼到后端地址上后端收到的就是http://127.0.0.1:8081/api/user/login。如果你的后端Controller本身有/api前缀那么不带斜杠恰好是对的如果后端没有/api前缀带斜杠才是对的。判断标准只有一条后端接口实际暴露的路径结构是什么。用一个公式总结location匹配的uri前缀是否出现在后端真正需要的地址里。出现在里面就不加斜杠不出现在里面就加斜杠。每次写proxy_pass前都默念这句话能避免90%的路径问题。4.3 跨域问题的Nginx解法跨域是浏览器层面的策略Nginx作为反向代理天然能“骗过”浏览器因为请求从浏览器到Nginx是同源的Nginx代理到后端时后端收到的请求没有Origin头限制。所以只要前端直接访问Nginx不做CORS配置很多时候也能通。但如果你一定要在后端响应里带上CORS头也可以用Nginx统一处理。location /api/ { proxy_pass http://127.0.0.1:8081/; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS; add_header Access-Control-Allow-Headers Content-Type, Authorization; if ($request_method OPTIONS) { return 204; } }OPTIONS请求是浏览器的预检请求CORS复杂请求会先发一个OPTIONS后端如果拒绝这个预检请求真正的请求根本不会发出去。上面用return 204直接拦截掉预检并返回成功状态码是开发环境里非常实用的做法。一个忠告Access-Control-Allow-Origin *意味着任何来源都能访问内网环境图省事可以这样用一旦涉及公网或敏感数据建议把*换成明确的域名比如Access-Control-Allow-Origin http://localhost:8080避免被其他站点偷着调接口。5. 运行期管理日志、服务化、安全加固与卸载5.1 Nginx日志怎么看Nginx的日志默认分成两个文件logs/error.log和logs/access.log。error.log记录的是配置错误、连接异常、worker进程问题等信息。每次启动失败或请求异常先看这个文件它通常会直接告诉你哪一行配置有语法问题、哪个地址连接超时。开发阶段出问题先tail error.log比猜谜效率高得多。access.log记录的是每一个访问请求默认格式包含客户端IP、请求时间、请求方法、URI、状态码、返回字节数、浏览器UA。通过它你可以快速判断请求到底有没有进来、状态码是200还是404/502、耗时多久。这在排查“前端说接口挂了但后端说没收到请求”这种打架问题时就是铁证——看access.log里有没有那条请求就知道请求是否到达了Nginx这一层。有一点要注意Windows版Nginx没有原生的日志轮转机制access.log会无限增长时间长了可能变成好几个G。我的土办法是用Windows计划任务每天凌晨执行一段批处理把日志改名然后让Nginx重新打开日志文件ren C:\nginx\logs\access.log access-%date:~0,10%.log net stop Nginx net start Nginx思路不难实际执行时给批处理加一段日期格式判断就行。不过如果你把Nginx注册成Windows服务下文会讲net stop/start可以换成nginx -s reopen——Nginx支持重开日志文件配合批处理改名就能实现切割不用停服务。5.2 让Nginx开机自启注册成Windows服务Nginx默认是个前台进程也就是说你关掉启动它的命令行窗口服务就没了你重启电脑它也不会自动跑起来。想要开机自启就得把Nginx包装成Windows服务。常用方案是NSSMNon-Sucking Service Manager或WinSW。我习惯用NSSM因为操作简单、命令少。下载NSSM解压后在NSSM目录打开命令行执行nssm install Nginx会弹出一个图形化界面在Path里填C:\nginx\nginx.exeStartup directory填C:\nginx然后点Install service。如果想用命令行完成nssm install Nginx C:\nginx\nginx.exe nssm set Nginx AppDirectory C:\nginx nssm set Nginx AppStdout C:\nginx\logs\stdout.log nssm set Nginx AppStderr C:\nginx\logs\stderr.log nssm start Nginx注册之后打开services.msc能看到Nginx服务启动类型默认自动开机就会跑。以后管理服务就用net start Nginx net stop Nginx这里有一个细节通过NSSM启动Nginx后任务管理器里的进程归属是nginx.exe但服务管理器里如果显示运行中而Nginx没有实际监听多半是配置里有语法错误。这时候去事件查看器或NSSM配置的日志文件里找原因不要反复去点“重启服务”空转。5.3 几行配置就能做的安全加固如果你把Nginx绑到了内网或公网几点基础安全配置必须加上。隐藏版本号。默认情况下Nginx的响应头会带Server: nginx/1.26.2等于告诉全世界你用的是什么版本攻击者可以精准搜索对应漏洞。加一行server_tokens off;之后响应头只剩Server: nginx版本号就没了。限制管理路径的访问来源。比如后端有一个不需要暴露给所有人的管理接口location /admin/ { allow 192.168.1.0/24; deny all; proxy_pass http://127.0.0.1:8081/; }这样只有192.168.1.0/24网段的机器能访问/admin/其他来源一律403。开发环境下大部分人不会配这条但如果你把Nginx作为公司的统一入口这个习惯早晚用得上。调整上传大小。默认client_max_body_size只有1MB上传文件超过这个体积会直接返回413。做文件上传功能时按需调大location /upload/ { client_max_body_size 50m; proxy_pass http://127.0.0.1:8081/; }5.4 卸载和清理Windows版Nginx的卸载是操作系统里少见的清爽操作nginx -s stop然后直接删除整个Nginx目录。不过别急着开心有三处残留需要注意如果注册了Windows服务要先用nssm remove Nginx把服务删掉检查任务管理器里还有没有残留的nginx.exe有就手动结束检查80端口是否被释放这三个地方清理完才算真正卸载干净。如果你后来重装Nginx发现“配置都对但就是起不来”先回头想想是不是上一次卸载时服务没删干净新旧两个Nginx抢同一个端口是内网最常见的翻车原因之一。6. 我长期使用Windows版Nginx攒下来的经验最后写几条平时文档里看不到的东西都是实际操作中被教训出来的。第一强烈建议做一套批处理脚本把常用命令封装起来。我自己在Nginx目录下放了三个文件start-nginx.batecho off cd /d C:\nginx start nginx echo Nginx started.stop-nginx.batecho off cd /d C:\nginx nginx -s stop echo Nginx stopped.reload-nginx.batecho off cd /d C:\nginx nginx -t nginx -s reload echo Nginx reloaded.以后不用每次开cmd敲长命令双击脚本就完事。Windows开发环境下这套“双击文化”反而比命令行更顺手。第二命令行输出中文乱码的问题。Windows的cmd默认编码是GBK而Nginx配置文件和日志是UTF-8执行nginx -t时如果配置里有中文路径或中文注释可能看到乱码但不影响实际运行。真想根治在批处理开头加上chcp 65001把编码切成UTF-8或者干脆别在配置文件里写中文注释。我不建议写中文注释——Nginx配置工具的编码识别能力参差不齐万一某个编辑器存成了带BOM的UTF-8反而容易触发解析问题。第三Windows版Nginx的配置文件直接迁移到Linux时需要改动的地方很少。nginx.conf里的路径写法、反向代理规则、负载均衡配置几乎可以原样复用需要改的只有user指令、路径分隔符、日志轮转机制。所以我的建议一直是学习阶段用Windows版本把Nginx的配置逻辑摸透尤其把location匹配规则和proxy_pass拼接规则吃透将来真要上生产服务器你面对的Linux版Nginx就是一套换皮但不变骨的系统。第四如果你的项目要用WebSocketWindows版Nginx需要1.9以上的版本才支持proxy_http_version 1.1和Upgrade头。实测下来Nginx代理WebSocket在这套组合里是能正常工作的但要注意worker_processes在Windows上别调太高官方文档说Windows版一个worker进程就够了多配反而增加不稳因素。我一般改成worker_processes 1;环境变量大趋势就是稳字当头。最后说一句个人感受Windows版Nginx的定位更像“开发调试利器”和“内网小服务引擎”而不是“高并发生产服务器”。想在公司服务器上扛几万并发老老实实上Linux想在本机快速搭个环境、练手、跑通一套前后端分离流程Windows版完全能顶住。把这篇里的配置吃透从零到一跑通一个动态站点代理你对Nginx的掌握就已经超过大多数只会粘贴复制的人。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进