ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Windows服务器部署Node.js项目:Nginx反向代理与nssm服务管理实战

Windows服务器部署Node.js项目:Nginx反向代理与nssm服务管理实战 1. 项目背景与整体部署思路拆解1.1 为什么要把Nodejs项目放到Windows服务器上很多做前端或者全栈的朋友第一反应是Nodejs项目就该跑在Linux上用pm2一挂Nginx一配完事。但现实情况是不少中小团队、传统企业的IT基础设施就是Windows Server运维同事对IIS和Windows服务更熟悉机房里的机器也是Windows环境。你不可能因为自己习惯Linux就要求整个运维体系为你改。所以把Nodejs项目部署到Windows服务器并且用Nginx做反向代理是一个非常实际的需求。这个方案能解决什么问题简单说就是让你的Nodejs应用在Windows服务器上稳定跑起来外部请求通过Nginx转发到Node进程同时Nginx还能顺便处理静态资源、负载均衡、SSL终止这些活。适合谁参考适合手头只有Windows服务器、又不想把Node应用直接暴露在外面的开发者也适合刚接触服务端部署、想找一个完整可复现方案的新手。1.2 整体架构与请求链路先把这个方案的架构说清楚不然后面配起来容易晕。整个链路是这样的用户请求先到NginxNginx监听80或者443端口根据配置的规则把动态请求转发给本机的Node进程Node进程监听一个内部端口比如3000或者8080。静态文件比如图片、CSS、JSNginx可以直接从磁盘读不用经过Node这样能减轻Node的压力。为什么不让Node直接对外原因有几个。第一Node处理静态文件的效率不如NginxNginx底层是事件驱动处理静态资源非常快。第二直接用Node对外端口管理、SSL证书、访问日志这些都要自己写Nginx现成的功能不用白不用。第三后面如果要加缓存、限流、多实例负载均衡Nginx层做比在Node里做方便得多。1.3 方案选型的几个关键决策在Windows上跑Node进程管理是个绕不开的问题。Linux上有pm2、systemdWindows上也有pm2但pm2在Windows上的自启和稳定性需要额外处理。另一个选择是用Windows服务的方式借助node-windows或者nssm把Node进程注册成系统服务。我实测下来nssm更稳配置也直观后面会详细讲。Nginx在Windows上的版本和Linux版本功能基本一致但有一点要注意Windows版的Nginx不支持epoll用的是select模型高并发下性能不如Linux。不过对于中小流量场景完全够用。另外Windows版Nginx没有官方的服务封装需要自己用nssm或者winsw把它注册成服务否则服务器重启后Nginx不会自动起来。提示如果你的服务器流量很大比如日均几十万请求建议还是优先考虑Linux环境。Windows方案更适合内部系统、中小型对外服务、或者运维体系已经固定为Windows的场景。2. 环境准备与核心工具选型2.1 Nodejs运行环境的安装与版本选择第一步是在Windows服务器上装Nodejs。直接去官网下载LTS版本的msi安装包双击安装就行。安装路径建议不要放在C盘默认的Program Files下因为后面配置服务的时候路径里有空格会比较麻烦。我一般装在D:\nodejs这种没有空格的路径下。安装完成后打开cmd或者PowerShell执行node -v和npm -v确认版本。这里有个坑如果你服务器上之前装过旧版本最好先卸载干净再装新版本。不同大版本之间的Nodenpm包兼容性可能有问题尤其是涉及原生模块编译的时候。版本选择上建议用当前LTS版本比如18.x或者20.x。不要追最新的奇数版本那些是实验性的生产环境求稳。装完之后把npm的源换成国内镜像不然装依赖的时候会慢到怀疑人生。命令是npm config set registry https://registry.npmmirror.com这个操作能省很多时间。2.2 Nginx for Windows的下载与目录规划Nginx官网有Windows版的zip包下载下来解压到一个固定目录比如D:\nginx。解压后的目录结构里conf放配置文件logs放日志html放默认静态页。你不需要安装解压就能用但需要手动启动。目录规划上我建议把Nginx和Node项目分开放比如Nginx在D:\nginxNode项目在D:\apps\myproject。这样后面配路径的时候清晰备份和迁移也方便。Nginx的配置文件主要改conf\nginx.conf但更好的做法是在conf下新建一个vhost目录把每个站点的配置单独放一个文件然后在nginx.conf里用include引入。这样以后加站点不用动主配置。注意Windows版Nginx的路径分隔符用正斜杠/或者双反斜杠\\不要用单反斜杠否则会解析出错。这是新手最容易踩的坑之一。2.3 进程管理工具nssm的引入理由前面说了Windows上要让Node进程稳定跑最好注册成系统服务。nssm是一个轻量的服务封装工具可以把任意exe注册成Windows服务支持自动重启、日志重定向、启动参数配置。相比pm2nssm的优势是它本身就是Windows服务机制不依赖额外的守护进程服务器重启后自动拉起。下载nssm后解压得到nssm.exe放到一个固定目录比如D:\tools\nssm。然后把这个目录加到系统环境变量Path里这样在任意位置都能调用nssm命令。后面配置Node服务和Nginx服务都会用到它。2.4 工具选型对比表工具用途优势注意事项Nodejs LTS运行环境稳定、生态成熟路径避免空格换国内源Nginx Windows版反向代理配置灵活、静态资源高效需手动注册服务不支持epollnssm服务封装轻量、自动重启、日志重定向路径加入环境变量pm2进程管理功能丰富、跨平台Windows自启需额外配置这张表是我自己在选型时整理的核心逻辑就是能用系统原生机制就用原生nssm比pm2在Windows上更贴合系统。当然如果你团队已经熟悉pm2继续用也行只是自启那块要多做一步。3. Nodejs项目的部署与实操配置3.1 项目上传与依赖安装把Node项目传到服务器上可以用Git克隆也可以直接压缩包上传。我一般用Git方便后续更新。项目放到D:\apps\myproject然后在项目根目录打开cmd执行npm install --production。加--production是为了不装devDependencies减少体积和潜在的安全风险。安装过程中如果遇到原生模块编译失败比如node-sass、bcrypt这类需要先装Windows Build Tools。命令是npm install --global windows-build-tools但这个包已经废弃了现在更推荐装Visual Studio Build Tools勾选C编译工具。这一步比较耗时但一次装好后面就省心了。安装完成后先本地跑一下node app.js或者npm start确认项目能正常启动监听端口比如3000。如果启动报错先解决代码层面的问题不要急着配服务。我见过有人服务配了半天最后发现是项目本身跑不起来白白浪费时间。3.2 用nssm把Node进程注册成Windows服务确认项目能跑之后开始注册服务。打开cmd执行nssm install MyNodeApp会弹出一个图形界面。在Path里选node.exe的完整路径比如D:\nodejs\node.exe。在Startup directory里填项目根目录D:\apps\myproject。在Arguments里填入口文件比如app.js或者server.js。切换到I/O标签页配置日志输出。Output填D:\logs\mynode_out.logError填D:\logs\mynode_err.log。这样Node的console输出和错误都会写到文件里排查问题的时候非常有用。再切换到Exit actions标签页设置重启延迟比如Restart delay填5000毫秒这样进程意外退出后5秒自动重启。配置完成后点Install service然后执行nssm start MyNodeApp启动服务。用nssm status MyNodeApp查看状态显示SERVICE_RUNNING就说明成功了。这时候打开浏览器访问http://localhost:3000应该能看到你的应用。实操心得nssm的图形界面虽然方便但如果你要批量部署或者写自动化脚本可以用命令行方式nssm install MyNodeApp D:\nodejs\node.exe app.js然后nssm set MyNodeApp AppDirectory D:\apps\myproject。命令行方式更适合写进部署脚本。3.3 环境变量与端口配置的注意事项Node项目里经常用环境变量来区分开发和生产比如process.env.NODE_ENV和process.env.PORT。用nssm注册服务的时候默认不会带上你cmd里设置的环境变量。需要在nssm的Environment标签页里手动添加每行一个格式是KEYVALUE。比如添加NODE_ENVproduction和PORT3000。这样Node进程启动时就能读到正确的配置。如果你项目里用了.env文件那要确保dotenv这类库能正确加载路径要对。我建议生产环境尽量用系统环境变量而不是.env文件因为.env文件容易被误提交到代码仓库有安全风险。端口选择上Node监听一个内部端口比如3000、8080、5000不要用80或者443那些留给Nginx。端口号在项目配置里写死或者通过环境变量传入都行关键是要和后面Nginx配置里的转发目标一致。3.4 验证Node服务是否稳定运行服务注册好之后不要急着配Nginx先观察一下Node服务是否稳定。可以做几个测试第一用nssm restart MyNodeApp重启服务看能否正常拉起。第二用任务管理器杀掉node进程看nssm是否自动重启。第三重启整个服务器看服务是否自动启动。这三个测试都通过说明Node服务这块没问题了。我遇到过nssm配置了自动重启但没生效的情况后来发现是Exit actions里的Restart选项没选对默认是No action需要手动改成Restart application。这个细节很容易忽略但很关键。4. Nginx反向代理的配置与调优4.1 Nginx核心配置文件的编写Nginx的反向代理配置是整个方案的核心。打开D:\nginx\conf\nginx.conf找到http块在里面加一个server块。最基础的配置大概是这样server { listen 80; server_name your_domain.com; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; 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 X-Forwarded-Proto $scheme; } }这几行配置的意思是Nginx监听80端口收到请求后转发给本机3000端口的Node服务。proxy_set_header那几行是把原始请求的信息传给Node不然Node拿到的客户端IP全是127.0.0.1日志和业务逻辑都会出问题。proxy_http_version 1.1这行也建议加上因为HTTP/1.1支持长连接性能比1.0好。如果你后面要用WebSocket还需要加proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection upgrade。4.2 静态资源分离与缓存策略如果项目里有静态文件比如图片、CSS、JS建议让Nginx直接处理不要转发给Node。配置大概是这样location /static/ { root D:/apps/myproject/public; expires 30d; add_header Cache-Control public, immutable; } location / { proxy_pass http://127.0.0.1:3000; ... }expires 30d是设置浏览器缓存30天Cache-Control里的immutable告诉浏览器这个文件内容不会变可以放心缓存。这样用户第二次访问的时候静态资源直接从本地缓存读不用再请求服务器速度飞快。注意Windows下Nginx的root路径要用正斜杠比如D:/apps/myproject/public。如果用反斜杠需要写成双反斜杠D:\\apps\\myproject\\public否则会报错。4.3 反向代理的关键参数调优默认的代理配置在高并发或者慢请求场景下可能会出问题需要调几个参数。第一个是proxy_connect_timeout设置Nginx和后端Node建立连接的超时时间默认60秒可以改成10秒避免请求堆积。第二个是proxy_read_timeout设置读取后端响应的超时时间如果Node处理某个请求特别慢这个值要调大否则Nginx会提前断开。第三个是proxy_buffer_size和proxy_buffers控制Nginx缓存后端响应的缓冲区大小。如果后端返回的响应头很大比如带了很多Cookie默认的缓冲区可能不够会报upstream sent too big header错误。这时候需要调大proxy_buffer_size 16k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k;这几个值不是越大越好要根据实际响应大小来调。我一般先按默认跑遇到报错再针对性调整。4.4 把Nginx注册成Windows服务Nginx本身不会自动启动需要注册成服务。用nssm执行nssm install Nginx在Path里选D:\nginx\nginx.exeStartup directory填D:\nginx。Arguments留空就行。然后在Exit actions里设置重启。这里有个细节Nginx在Windows上启动后会在logs目录下生成nginx.pid文件。如果Nginx异常退出这个pid文件可能残留导致下次启动失败。可以在nssm的Exit actions里加一个脚本启动前先删除pid文件或者手动处理。我一般是在服务启动前用taskkill确保没有残留的nginx进程。配置完成后启动服务访问http://localhost如果能看到你的Node应用说明反向代理配通了。4.5 配置验证与常见错误排查配完Nginx后先执行nginx -t检查配置文件语法。这个命令会告诉你配置文件有没有语法错误以及错误在哪个文件的哪一行。确认无误后再nginx -s reload重载配置不要直接重启reload是平滑的不会中断现有连接。如果访问报502 Bad Gateway说明Nginx连不上Node服务。排查步骤第一确认Node服务在跑nssm status MyNodeApp看状态。第二确认端口对netstat -ano | findstr 3000看端口是否监听。第三确认防火墙没拦Windows防火墙默认可能拦了3000端口但因为是本机转发一般不受影响。如果报404说明Nginx转发过去了但Node没有对应的路由。检查proxy_pass的路径和Node路由是否匹配。如果报504说明Node处理超时检查proxy_read_timeout设置和Node本身的性能。5. 常见问题与排查技巧实录5.1 服务启动失败与端口占用排查Windows上端口占用是高频问题。Node服务启动失败日志里写EADDRINUSE说明端口被占了。用netstat -ano | findstr 3000找到占用端口的进程PID然后tasklist | findstr PID看是什么程序。如果是之前残留的node进程用taskkill /F /PID xxx杀掉。Nginx启动失败常见原因是80端口被IIS或者其它Web服务占了。Windows Server默认可能装了IISIIS会监听80端口。要么停掉IIS要么把Nginx换成其它端口。我一般建议直接停掉IIS因为既然用Nginx了IIS就没必要留着。还有一种情况是nssm注册服务时路径填错服务启动后立即停止。这时候去Windows事件查看器里看应用程序日志nssm会把错误写进去。或者直接看nssm配置的Error日志文件里面会有详细报错。5.2 反向代理后获取真实IP失败的处理前面配置里加了X-Real-IP和X-Forwarded-For但Node代码里要正确读取才行。Express框架下需要设置app.set(trust proxy, true)然后用req.ip或者req.headers[x-forwarded-for]获取。如果不设置trust proxyExpress会把代理IP当成客户端IP。如果用了其它框架原理一样就是信任代理头。但要注意X-Forwarded-For是可以伪造的如果直接暴露给公网恶意用户可以伪造IP。所以这个头只在Nginx转发时设置并且Nginx要配置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for这样Nginx会把真实客户端IP追加进去。5.3 静态资源404与路径大小写问题Windows文件系统不区分大小写但Nginx配置里的路径和URL是区分大小写的。如果请求的URL是/Static/logo.png而实际目录是static在Windows上可能能读到但Nginx的location匹配是按配置来的如果location写的是/static/那/Static/就匹配不上会走到默认的代理规则然后Node返回404。解决办法是统一URL和目录的大小写规范location匹配用~*做不区分大小写的正则匹配比如location ~* ^/static/。但正则匹配性能不如前缀匹配所以更好的做法是前端代码里统一用小写路径。5.4 服务自动重启与日志切割nssm的自动重启前面说了但日志文件会一直增长时间长了占满磁盘。需要做日志切割。nssm本身不支持按大小切割可以用Windows的任务计划程序每天定时把日志文件重命名归档然后重启服务生成新日志。或者用一些日志管理工具。我自己的做法是写一个bat脚本每天凌晨执行把mynode_out.log重命名为mynode_out_日期.log然后清空原文件。Nginx的日志切割类似Nginx支持nginx -s reopen重新打开日志文件配合任务计划可以实现切割。5.5 常见问题速查表问题现象可能原因排查方法解决方案502 Bad GatewayNode服务未启动或端口不对检查nssm状态和netstat端口启动服务或修正端口504 Gateway TimeoutNode处理超时查看Node日志和proxy_read_timeout调大超时或优化Node性能404 Not Found路由不匹配或静态路径错误检查Nginx location和Node路由修正配置或路径端口占用残留进程或其它服务占用netstat -ano查PID杀掉进程或换端口服务不自启nssm配置错误查看事件查看器和nssm日志修正Path和Exit actions真实IP获取失败未设置trust proxy检查Node代码和代理头设置trust proxy并读X-Forwarded-For这张表是我在实际部署中反复用到的基本上覆盖了80%的问题。遇到新问题先按这个表排查大部分都能解决。5.6 几个容易被忽略的实操细节第一个细节Windows Server的防火墙默认可能拦了外部对80端口的访问。需要在防火墙入站规则里加一条允许80和443端口。这个不配的话本机访问正常但外部访问不通很容易误判为Nginx配置问题。第二个细节Nginx的worker_processes在Windows上建议设为1。因为Windows版Nginx的多进程模型和Linux不同设多了反而可能有问题。默认配置里是worker_processes 1保持默认就行。第三个细节Node项目里的文件路径要用path.join或者path.resolve不要硬编码/或者\。Windows和Linux的路径分隔符不同硬编码会导致跨平台问题。虽然部署在Windows上但开发环境可能是Mac或者Linux代码要兼容。第四个细节如果项目用了WebSocketNginx配置里除了Upgrade和Connection头还要注意proxy_read_timeout要设大一点因为WebSocket是长连接默认60秒会被断开。可以设成3600秒或者更长。6. 性能监控与后续扩展思路6.1 基础监控指标的采集服务跑起来之后要知道它健不健康。最基础的监控指标包括CPU和内存占用、Node进程的响应时间、Nginx的活跃连接数、错误日志里的报错频率。Windows自带的性能监视器可以看CPU和内存但不够细。我一般会在Node里加一个健康检查接口比如/health返回{status: ok, uptime: process.uptime()}。然后用一个定时任务每隔几分钟请求一次记录响应时间。如果响应时间突然变长或者请求失败就说明有问题。这个接口也可以给Nginx的upstream健康检查用。Nginx的stub_status模块可以暴露一些基础指标比如活跃连接数、总请求数。在配置里加一个locationlocation /nginx_status { stub_status; allow 127.0.0.1; deny all; }这样本机访问http://127.0.0.1/nginx_status就能看到Nginx的运行状态。注意要限制访问来源不要暴露到公网。6.2 多实例部署与负载均衡的扩展如果单实例Node扛不住流量可以在同一台服务器上起多个Node实例监听不同端口然后用Nginx做负载均衡。配置大概是这样upstream node_cluster { server 127.0.0.1:3000; server 127.0.0.1:3001; server 127.0.0.1:3002; } server { listen 80; location / { proxy_pass http://node_cluster; } }每个Node实例用单独的nssm服务管理端口通过环境变量区分。这样一台服务器上可以跑多个实例充分利用多核CPU。Nginx默认的负载均衡策略是轮询也可以改成least_conn或者ip_hash根据业务需求选。提示多实例部署时如果Node项目里有本地文件上传或者session存储要注意多实例之间的数据同步问题。文件上传建议放到共享存储或者对象存储session建议用Redis集中管理不要用内存session。6.3 HTTPS配置与证书管理现在网站基本都要HTTPSNginx配置SSL很简单。拿到证书文件后在server块里加server { listen 443 ssl; server_name your_domain.com; ssl_certificate D:/nginx/ssl/your_domain.crt; ssl_certificate_key D:/nginx/ssl/your_domain.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ... }同时把80端口的请求重定向到443server { listen 80; server_name your_domain.com; return 301 https://$host$request_uri; }证书文件路径同样用正斜杠。证书到期前要记得续期可以写个脚本定时检查证书有效期快到期时自动更新并reload Nginx。6.4 部署流程的自动化思路手动部署容易出错尤其是多台服务器的时候。可以写一个简单的部署脚本用bat或者PowerShell把Git拉取、npm install、nssm restart这几步串起来。每次更新代码执行一下脚本就行。更进一步可以用CI/CD工具比如Jenkins或者GitLab CI自动构建和部署。但对于Windows服务器CI/CD的配置相对复杂中小团队用脚本就够了。关键是脚本要能回滚如果新版本启动失败能自动切回旧版本。这个可以在脚本里加一个判断启动后请求健康检查接口失败就回滚。6.5 我个人的一些经验体会这套方案我在好几个项目里用过整体是稳的。最大的坑其实不在Nginx配置而在Windows的服务管理和路径处理上。nssm的配置一定要仔细尤其是Path和Startup directory填错了服务起不来报错还不明显。日志文件一定要配不然出了问题两眼一抹黑。另外Windows Server的更新有时候会自动重启服务器如果服务没配自启那就全挂了。所以nssm的自动启动和自动重启一定要测试通过。我一般会在部署完成后手动重启一次服务器确认所有服务都能自动起来这样才放心。最后再分享一个小技巧Nginx的配置文件改完后不要直接nginx -s reload先用nginx -t检查语法。这个习惯能避免很多因为配置写错导致的服务中断。而且reload之前最好备份一下当前配置万一新配置有问题能快速回滚。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表