器部署Node.js項(xiàng)目:Nginx反向代理與nssm服務(wù)管理實(shí)戰(zhàn))
1. 項(xiàng)目背景與整體部署思路拆解1.1 為什么要把Nodejs項(xiàng)目放到Windows服務(wù)器上很多做前端或者全棧的朋友第一反應(yīng)是Nodejs項(xiàng)目就該跑在Linux上用pm2一掛Nginx一配完事。但現(xiàn)實(shí)情況是不少中小團(tuán)隊(duì)、傳統(tǒng)企業(yè)的IT基礎(chǔ)設(shè)施就是Windows Server運(yùn)維同事對(duì)IIS和Windows服務(wù)更熟悉機(jī)房里的機(jī)器也是Windows環(huán)境。你不可能因?yàn)樽约毫?xí)慣Linux就要求整個(gè)運(yùn)維體系為你改。所以把Nodejs項(xiàng)目部署到Windows服務(wù)器并且用Nginx做反向代理是一個(gè)非常實(shí)際的需求。這個(gè)方案能解決什么問題簡(jiǎn)單說就是讓你的Nodejs應(yīng)用在Windows服務(wù)器上穩(wěn)定跑起來外部請(qǐng)求通過Nginx轉(zhuǎn)發(fā)到Node進(jìn)程同時(shí)Nginx還能順便處理靜態(tài)資源、負(fù)載均衡、SSL終止這些活。適合誰參考適合手頭只有Windows服務(wù)器、又不想把Node應(yīng)用直接暴露在外面的開發(fā)者也適合剛接觸服務(wù)端部署、想找一個(gè)完整可復(fù)現(xiàn)方案的新手。1.2 整體架構(gòu)與請(qǐng)求鏈路先把這個(gè)方案的架構(gòu)說清楚不然后面配起來容易暈。整個(gè)鏈路是這樣的用戶請(qǐng)求先到NginxNginx監(jiān)聽80或者443端口根據(jù)配置的規(guī)則把動(dòng)態(tài)請(qǐng)求轉(zhuǎn)發(fā)給本機(jī)的Node進(jìn)程N(yùn)ode進(jìn)程監(jiān)聽一個(gè)內(nèi)部端口比如3000或者8080。靜態(tài)文件比如圖片、CSS、JSNginx可以直接從磁盤讀不用經(jīng)過Node這樣能減輕Node的壓力。為什么不讓Node直接對(duì)外原因有幾個(gè)。第一Node處理靜態(tài)文件的效率不如NginxNginx底層是事件驅(qū)動(dòng)處理靜態(tài)資源非???。第二直接用Node對(duì)外端口管理、SSL證書、訪問日志這些都要自己寫Nginx現(xiàn)成的功能不用白不用。第三后面如果要加緩存、限流、多實(shí)例負(fù)載均衡Nginx層做比在Node里做方便得多。1.3 方案選型的幾個(gè)關(guān)鍵決策在Windows上跑Node進(jìn)程管理是個(gè)繞不開的問題。Linux上有pm2、systemdWindows上也有pm2但pm2在Windows上的自啟和穩(wěn)定性需要額外處理。另一個(gè)選擇是用Windows服務(wù)的方式借助node-windows或者nssm把Node進(jìn)程注冊(cè)成系統(tǒng)服務(wù)。我實(shí)測(cè)下來nssm更穩(wěn)配置也直觀后面會(huì)詳細(xì)講。Nginx在Windows上的版本和Linux版本功能基本一致但有一點(diǎn)要注意Windows版的Nginx不支持epoll用的是select模型高并發(fā)下性能不如Linux。不過對(duì)于中小流量場(chǎng)景完全夠用。另外Windows版Nginx沒有官方的服務(wù)封裝需要自己用nssm或者winsw把它注冊(cè)成服務(wù)否則服務(wù)器重啟后Nginx不會(huì)自動(dòng)起來。提示如果你的服務(wù)器流量很大比如日均幾十萬請(qǐng)求建議還是優(yōu)先考慮Linux環(huán)境。Windows方案更適合內(nèi)部系統(tǒng)、中小型對(duì)外服務(wù)、或者運(yùn)維體系已經(jīng)固定為Windows的場(chǎng)景。2. 環(huán)境準(zhǔn)備與核心工具選型2.1 Nodejs運(yùn)行環(huán)境的安裝與版本選擇第一步是在Windows服務(wù)器上裝Nodejs。直接去官網(wǎng)下載LTS版本的msi安裝包雙擊安裝就行。安裝路徑建議不要放在C盤默認(rèn)的Program Files下因?yàn)楹竺媾渲梅?wù)的時(shí)候路徑里有空格會(huì)比較麻煩。我一般裝在D:\nodejs這種沒有空格的路徑下。安裝完成后打開cmd或者PowerShell執(zhí)行node -v和npm -v確認(rèn)版本。這里有個(gè)坑如果你服務(wù)器上之前裝過舊版本最好先卸載干凈再裝新版本。不同大版本之間的Nodenpm包兼容性可能有問題尤其是涉及原生模塊編譯的時(shí)候。版本選擇上建議用當(dāng)前LTS版本比如18.x或者20.x。不要追最新的奇數(shù)版本那些是實(shí)驗(yàn)性的生產(chǎn)環(huán)境求穩(wěn)。裝完之后把npm的源換成國(guó)內(nèi)鏡像不然裝依賴的時(shí)候會(huì)慢到懷疑人生。命令是npm config set registry https://registry.npmmirror.com這個(gè)操作能省很多時(shí)間。2.2 Nginx for Windows的下載與目錄規(guī)劃Nginx官網(wǎng)有Windows版的zip包下載下來解壓到一個(gè)固定目錄比如D:\nginx。解壓后的目錄結(jié)構(gòu)里conf放配置文件logs放日志html放默認(rèn)靜態(tài)頁(yè)。你不需要安裝解壓就能用但需要手動(dòng)啟動(dòng)。目錄規(guī)劃上我建議把Nginx和Node項(xiàng)目分開放比如Nginx在D:\nginxNode項(xiàng)目在D:\apps\myproject。這樣后面配路徑的時(shí)候清晰備份和遷移也方便。Nginx的配置文件主要改conf\nginx.conf但更好的做法是在conf下新建一個(gè)vhost目錄把每個(gè)站點(diǎn)的配置單獨(dú)放一個(gè)文件然后在nginx.conf里用include引入。這樣以后加站點(diǎn)不用動(dòng)主配置。注意Windows版Nginx的路徑分隔符用正斜杠/或者雙反斜杠\\不要用單反斜杠否則會(huì)解析出錯(cuò)。這是新手最容易踩的坑之一。2.3 進(jìn)程管理工具nssm的引入理由前面說了Windows上要讓Node進(jìn)程穩(wěn)定跑最好注冊(cè)成系統(tǒng)服務(wù)。nssm是一個(gè)輕量的服務(wù)封裝工具可以把任意exe注冊(cè)成Windows服務(wù)支持自動(dòng)重啟、日志重定向、啟動(dòng)參數(shù)配置。相比pm2nssm的優(yōu)勢(shì)是它本身就是Windows服務(wù)機(jī)制不依賴額外的守護(hù)進(jìn)程服務(wù)器重啟后自動(dòng)拉起。下載nssm后解壓得到nssm.exe放到一個(gè)固定目錄比如D:\tools\nssm。然后把這個(gè)目錄加到系統(tǒng)環(huán)境變量Path里這樣在任意位置都能調(diào)用nssm命令。后面配置Node服務(wù)和Nginx服務(wù)都會(huì)用到它。2.4 工具選型對(duì)比表工具用途優(yōu)勢(shì)注意事項(xiàng)Nodejs LTS運(yùn)行環(huán)境穩(wěn)定、生態(tài)成熟路徑避免空格換國(guó)內(nèi)源Nginx Windows版反向代理配置靈活、靜態(tài)資源高效需手動(dòng)注冊(cè)服務(wù)不支持epollnssm服務(wù)封裝輕量、自動(dòng)重啟、日志重定向路徑加入環(huán)境變量pm2進(jìn)程管理功能豐富、跨平臺(tái)Windows自啟需額外配置這張表是我自己在選型時(shí)整理的核心邏輯就是能用系統(tǒng)原生機(jī)制就用原生nssm比pm2在Windows上更貼合系統(tǒng)。當(dāng)然如果你團(tuán)隊(duì)已經(jīng)熟悉pm2繼續(xù)用也行只是自啟那塊要多做一步。3. Nodejs項(xiàng)目的部署與實(shí)操配置3.1 項(xiàng)目上傳與依賴安裝把Node項(xiàng)目傳到服務(wù)器上可以用Git克隆也可以直接壓縮包上傳。我一般用Git方便后續(xù)更新。項(xiàng)目放到D:\apps\myproject然后在項(xiàng)目根目錄打開cmd執(zhí)行npm install --production。加--production是為了不裝devDependencies減少體積和潛在的安全風(fēng)險(xiǎn)。安裝過程中如果遇到原生模塊編譯失敗比如node-sass、bcrypt這類需要先裝Windows Build Tools。命令是npm install --global windows-build-tools但這個(gè)包已經(jīng)廢棄了現(xiàn)在更推薦裝Visual Studio Build Tools勾選C編譯工具。這一步比較耗時(shí)但一次裝好后面就省心了。安裝完成后先本地跑一下node app.js或者npm start確認(rèn)項(xiàng)目能正常啟動(dòng)監(jiān)聽端口比如3000。如果啟動(dòng)報(bào)錯(cuò)先解決代碼層面的問題不要急著配服務(wù)。我見過有人服務(wù)配了半天最后發(fā)現(xiàn)是項(xiàng)目本身跑不起來白白浪費(fèi)時(shí)間。3.2 用nssm把Node進(jìn)程注冊(cè)成Windows服務(wù)確認(rèn)項(xiàng)目能跑之后開始注冊(cè)服務(wù)。打開cmd執(zhí)行nssm install MyNodeApp會(huì)彈出一個(gè)圖形界面。在Path里選node.exe的完整路徑比如D:\nodejs\node.exe。在Startup directory里填項(xiàng)目根目錄D:\apps\myproject。在Arguments里填入口文件比如app.js或者server.js。切換到I/O標(biāo)簽頁(yè)配置日志輸出。Output填D:\logs\mynode_out.logError填D:\logs\mynode_err.log。這樣Node的console輸出和錯(cuò)誤都會(huì)寫到文件里排查問題的時(shí)候非常有用。再切換到Exit actions標(biāo)簽頁(yè)設(shè)置重啟延遲比如Restart delay填5000毫秒這樣進(jìn)程意外退出后5秒自動(dòng)重啟。配置完成后點(diǎn)Install service然后執(zhí)行nssm start MyNodeApp啟動(dòng)服務(wù)。用nssm status MyNodeApp查看狀態(tài)顯示SERVICE_RUNNING就說明成功了。這時(shí)候打開瀏覽器訪問http://localhost:3000應(yīng)該能看到你的應(yīng)用。實(shí)操心得nssm的圖形界面雖然方便但如果你要批量部署或者寫自動(dòng)化腳本可以用命令行方式nssm install MyNodeApp D:\nodejs\node.exe app.js然后nssm set MyNodeApp AppDirectory D:\apps\myproject。命令行方式更適合寫進(jìn)部署腳本。3.3 環(huán)境變量與端口配置的注意事項(xiàng)Node項(xiàng)目里經(jīng)常用環(huán)境變量來區(qū)分開發(fā)和生產(chǎn)比如process.env.NODE_ENV和process.env.PORT。用nssm注冊(cè)服務(wù)的時(shí)候默認(rèn)不會(huì)帶上你cmd里設(shè)置的環(huán)境變量。需要在nssm的Environment標(biāo)簽頁(yè)里手動(dòng)添加每行一個(gè)格式是KEYVALUE。比如添加NODE_ENVproduction和PORT3000。這樣Node進(jìn)程啟動(dòng)時(shí)就能讀到正確的配置。如果你項(xiàng)目里用了.env文件那要確保dotenv這類庫(kù)能正確加載路徑要對(duì)。我建議生產(chǎn)環(huán)境盡量用系統(tǒng)環(huán)境變量而不是.env文件因?yàn)?env文件容易被誤提交到代碼倉(cāng)庫(kù)有安全風(fēng)險(xiǎn)。端口選擇上Node監(jiān)聽一個(gè)內(nèi)部端口比如3000、8080、5000不要用80或者443那些留給Nginx。端口號(hào)在項(xiàng)目配置里寫死或者通過環(huán)境變量傳入都行關(guān)鍵是要和后面Nginx配置里的轉(zhuǎn)發(fā)目標(biāo)一致。3.4 驗(yàn)證Node服務(wù)是否穩(wěn)定運(yùn)行服務(wù)注冊(cè)好之后不要急著配Nginx先觀察一下Node服務(wù)是否穩(wěn)定??梢宰鰩讉€(gè)測(cè)試第一用nssm restart MyNodeApp重啟服務(wù)看能否正常拉起。第二用任務(wù)管理器殺掉node進(jìn)程看nssm是否自動(dòng)重啟。第三重啟整個(gè)服務(wù)器看服務(wù)是否自動(dòng)啟動(dòng)。這三個(gè)測(cè)試都通過說明Node服務(wù)這塊沒問題了。我遇到過nssm配置了自動(dòng)重啟但沒生效的情況后來發(fā)現(xiàn)是Exit actions里的Restart選項(xiàng)沒選對(duì)默認(rèn)是No action需要手動(dòng)改成Restart application。這個(gè)細(xì)節(jié)很容易忽略但很關(guān)鍵。4. Nginx反向代理的配置與調(diào)優(yōu)4.1 Nginx核心配置文件的編寫Nginx的反向代理配置是整個(gè)方案的核心。打開D:\nginx\conf\nginx.conf找到http塊在里面加一個(gè)server塊。最基礎(chǔ)的配置大概是這樣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監(jiān)聽80端口收到請(qǐng)求后轉(zhuǎn)發(fā)給本機(jī)3000端口的Node服務(wù)。proxy_set_header那幾行是把原始請(qǐng)求的信息傳給Node不然Node拿到的客戶端IP全是127.0.0.1日志和業(yè)務(wù)邏輯都會(huì)出問題。proxy_http_version 1.1這行也建議加上因?yàn)镠TTP/1.1支持長(zhǎng)連接性能比1.0好。如果你后面要用WebSocket還需要加proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection upgrade。4.2 靜態(tài)資源分離與緩存策略如果項(xiàng)目里有靜態(tài)文件比如圖片、CSS、JS建議讓Nginx直接處理不要轉(zhuǎn)發(fā)給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是設(shè)置瀏覽器緩存30天Cache-Control里的immutable告訴瀏覽器這個(gè)文件內(nèi)容不會(huì)變可以放心緩存。這樣用戶第二次訪問的時(shí)候靜態(tài)資源直接從本地緩存讀不用再請(qǐng)求服務(wù)器速度飛快。注意Windows下Nginx的root路徑要用正斜杠比如D:/apps/myproject/public。如果用反斜杠需要寫成雙反斜杠D:\\apps\\myproject\\public否則會(huì)報(bào)錯(cuò)。4.3 反向代理的關(guān)鍵參數(shù)調(diào)優(yōu)默認(rèn)的代理配置在高并發(fā)或者慢請(qǐng)求場(chǎng)景下可能會(huì)出問題需要調(diào)幾個(gè)參數(shù)。第一個(gè)是proxy_connect_timeout設(shè)置Nginx和后端Node建立連接的超時(shí)時(shí)間默認(rèn)60秒可以改成10秒避免請(qǐng)求堆積。第二個(gè)是proxy_read_timeout設(shè)置讀取后端響應(yīng)的超時(shí)時(shí)間如果Node處理某個(gè)請(qǐng)求特別慢這個(gè)值要調(diào)大否則Nginx會(huì)提前斷開。第三個(gè)是proxy_buffer_size和proxy_buffers控制Nginx緩存后端響應(yīng)的緩沖區(qū)大小。如果后端返回的響應(yīng)頭很大比如帶了很多Cookie默認(rèn)的緩沖區(qū)可能不夠會(huì)報(bào)upstream sent too big header錯(cuò)誤。這時(shí)候需要調(diào)大proxy_buffer_size 16k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k;這幾個(gè)值不是越大越好要根據(jù)實(shí)際響應(yīng)大小來調(diào)。我一般先按默認(rèn)跑遇到報(bào)錯(cuò)再針對(duì)性調(diào)整。4.4 把Nginx注冊(cè)成Windows服務(wù)Nginx本身不會(huì)自動(dòng)啟動(dòng)需要注冊(cè)成服務(wù)。用nssm執(zhí)行nssm install Nginx在Path里選D:\nginx\nginx.exeStartup directory填D:\nginx。Arguments留空就行。然后在Exit actions里設(shè)置重啟。這里有個(gè)細(xì)節(jié)Nginx在Windows上啟動(dòng)后會(huì)在logs目錄下生成nginx.pid文件。如果Nginx異常退出這個(gè)pid文件可能殘留導(dǎo)致下次啟動(dòng)失敗??梢栽趎ssm的Exit actions里加一個(gè)腳本啟動(dòng)前先刪除pid文件或者手動(dòng)處理。我一般是在服務(wù)啟動(dòng)前用taskkill確保沒有殘留的nginx進(jìn)程。配置完成后啟動(dòng)服務(wù)訪問http://localhost如果能看到你的Node應(yīng)用說明反向代理配通了。4.5 配置驗(yàn)證與常見錯(cuò)誤排查配完Nginx后先執(zhí)行nginx -t檢查配置文件語(yǔ)法。這個(gè)命令會(huì)告訴你配置文件有沒有語(yǔ)法錯(cuò)誤以及錯(cuò)誤在哪個(gè)文件的哪一行。確認(rèn)無誤后再nginx -s reload重載配置不要直接重啟reload是平滑的不會(huì)中斷現(xiàn)有連接。如果訪問報(bào)502 Bad Gateway說明Nginx連不上Node服務(wù)。排查步驟第一確認(rèn)Node服務(wù)在跑nssm status MyNodeApp看狀態(tài)。第二確認(rèn)端口對(duì)netstat -ano | findstr 3000看端口是否監(jiān)聽。第三確認(rèn)防火墻沒攔Windows防火墻默認(rèn)可能攔了3000端口但因?yàn)槭潜緳C(jī)轉(zhuǎn)發(fā)一般不受影響。如果報(bào)404說明Nginx轉(zhuǎn)發(fā)過去了但Node沒有對(duì)應(yīng)的路由。檢查proxy_pass的路徑和Node路由是否匹配。如果報(bào)504說明Node處理超時(shí)檢查proxy_read_timeout設(shè)置和Node本身的性能。5. 常見問題與排查技巧實(shí)錄5.1 服務(wù)啟動(dòng)失敗與端口占用排查Windows上端口占用是高頻問題。Node服務(wù)啟動(dòng)失敗日志里寫EADDRINUSE說明端口被占了。用netstat -ano | findstr 3000找到占用端口的進(jìn)程PID然后tasklist | findstr PID看是什么程序。如果是之前殘留的node進(jìn)程用taskkill /F /PID xxx殺掉。Nginx啟動(dòng)失敗常見原因是80端口被IIS或者其它Web服務(wù)占了。Windows Server默認(rèn)可能裝了IISIIS會(huì)監(jiān)聽80端口。要么停掉IIS要么把Nginx換成其它端口。我一般建議直接停掉IIS因?yàn)榧热挥肗ginx了IIS就沒必要留著。還有一種情況是nssm注冊(cè)服務(wù)時(shí)路徑填錯(cuò)服務(wù)啟動(dòng)后立即停止。這時(shí)候去Windows事件查看器里看應(yīng)用程序日志nssm會(huì)把錯(cuò)誤寫進(jìn)去。或者直接看nssm配置的Error日志文件里面會(huì)有詳細(xì)報(bào)錯(cuò)。5.2 反向代理后獲取真實(shí)IP失敗的處理前面配置里加了X-Real-IP和X-Forwarded-For但Node代碼里要正確讀取才行。Express框架下需要設(shè)置app.set(trust proxy, true)然后用req.ip或者req.headers[x-forwarded-for]獲取。如果不設(shè)置trust proxyExpress會(huì)把代理IP當(dāng)成客戶端IP。如果用了其它框架原理一樣就是信任代理頭。但要注意X-Forwarded-For是可以偽造的如果直接暴露給公網(wǎng)惡意用戶可以偽造IP。所以這個(gè)頭只在Nginx轉(zhuǎn)發(fā)時(shí)設(shè)置并且Nginx要配置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for這樣Nginx會(huì)把真實(shí)客戶端IP追加進(jìn)去。5.3 靜態(tài)資源404與路徑大小寫問題Windows文件系統(tǒng)不區(qū)分大小寫但Nginx配置里的路徑和URL是區(qū)分大小寫的。如果請(qǐng)求的URL是/Static/logo.png而實(shí)際目錄是static在Windows上可能能讀到但Nginx的location匹配是按配置來的如果location寫的是/static/那/Static/就匹配不上會(huì)走到默認(rèn)的代理規(guī)則然后Node返回404。解決辦法是統(tǒng)一URL和目錄的大小寫規(guī)范location匹配用~*做不區(qū)分大小寫的正則匹配比如location ~* ^/static/。但正則匹配性能不如前綴匹配所以更好的做法是前端代碼里統(tǒng)一用小寫路徑。5.4 服務(wù)自動(dòng)重啟與日志切割nssm的自動(dòng)重啟前面說了但日志文件會(huì)一直增長(zhǎng)時(shí)間長(zhǎng)了占滿磁盤。需要做日志切割。nssm本身不支持按大小切割可以用Windows的任務(wù)計(jì)劃程序每天定時(shí)把日志文件重命名歸檔然后重啟服務(wù)生成新日志?;蛘哂靡恍┤罩竟芾砉ぞ?。我自己的做法是寫一個(gè)bat腳本每天凌晨執(zhí)行把mynode_out.log重命名為mynode_out_日期.log然后清空原文件。Nginx的日志切割類似Nginx支持nginx -s reopen重新打開日志文件配合任務(wù)計(jì)劃可以實(shí)現(xiàn)切割。5.5 常見問題速查表問題現(xiàn)象可能原因排查方法解決方案502 Bad GatewayNode服務(wù)未啟動(dòng)或端口不對(duì)檢查nssm狀態(tài)和netstat端口啟動(dòng)服務(wù)或修正端口504 Gateway TimeoutNode處理超時(shí)查看Node日志和proxy_read_timeout調(diào)大超時(shí)或優(yōu)化Node性能404 Not Found路由不匹配或靜態(tài)路徑錯(cuò)誤檢查Nginx location和Node路由修正配置或路徑端口占用殘留進(jìn)程或其它服務(wù)占用netstat -ano查PID殺掉進(jìn)程或換端口服務(wù)不自啟nssm配置錯(cuò)誤查看事件查看器和nssm日志修正Path和Exit actions真實(shí)IP獲取失敗未設(shè)置trust proxy檢查Node代碼和代理頭設(shè)置trust proxy并讀X-Forwarded-For這張表是我在實(shí)際部署中反復(fù)用到的基本上覆蓋了80%的問題。遇到新問題先按這個(gè)表排查大部分都能解決。5.6 幾個(gè)容易被忽略的實(shí)操細(xì)節(jié)第一個(gè)細(xì)節(jié)Windows Server的防火墻默認(rèn)可能攔了外部對(duì)80端口的訪問。需要在防火墻入站規(guī)則里加一條允許80和443端口。這個(gè)不配的話本機(jī)訪問正常但外部訪問不通很容易誤判為Nginx配置問題。第二個(gè)細(xì)節(jié)Nginx的worker_processes在Windows上建議設(shè)為1。因?yàn)閃indows版Nginx的多進(jìn)程模型和Linux不同設(shè)多了反而可能有問題。默認(rèn)配置里是worker_processes 1保持默認(rèn)就行。第三個(gè)細(xì)節(jié)Node項(xiàng)目里的文件路徑要用path.join或者path.resolve不要硬編碼/或者\(yùn)。Windows和Linux的路徑分隔符不同硬編碼會(huì)導(dǎo)致跨平臺(tái)問題。雖然部署在Windows上但開發(fā)環(huán)境可能是Mac或者Linux代碼要兼容。第四個(gè)細(xì)節(jié)如果項(xiàng)目用了WebSocketNginx配置里除了Upgrade和Connection頭還要注意proxy_read_timeout要設(shè)大一點(diǎn)因?yàn)閃ebSocket是長(zhǎng)連接默認(rèn)60秒會(huì)被斷開??梢栽O(shè)成3600秒或者更長(zhǎng)。6. 性能監(jiān)控與后續(xù)擴(kuò)展思路6.1 基礎(chǔ)監(jiān)控指標(biāo)的采集服務(wù)跑起來之后要知道它健不健康。最基礎(chǔ)的監(jiān)控指標(biāo)包括CPU和內(nèi)存占用、Node進(jìn)程的響應(yīng)時(shí)間、Nginx的活躍連接數(shù)、錯(cuò)誤日志里的報(bào)錯(cuò)頻率。Windows自帶的性能監(jiān)視器可以看CPU和內(nèi)存但不夠細(xì)。我一般會(huì)在Node里加一個(gè)健康檢查接口比如/health返回{status: ok, uptime: process.uptime()}。然后用一個(gè)定時(shí)任務(wù)每隔幾分鐘請(qǐng)求一次記錄響應(yīng)時(shí)間。如果響應(yīng)時(shí)間突然變長(zhǎng)或者請(qǐng)求失敗就說明有問題。這個(gè)接口也可以給Nginx的upstream健康檢查用。Nginx的stub_status模塊可以暴露一些基礎(chǔ)指標(biāo)比如活躍連接數(shù)、總請(qǐng)求數(shù)。在配置里加一個(gè)locationlocation /nginx_status { stub_status; allow 127.0.0.1; deny all; }這樣本機(jī)訪問http://127.0.0.1/nginx_status就能看到Nginx的運(yùn)行狀態(tài)。注意要限制訪問來源不要暴露到公網(wǎng)。6.2 多實(shí)例部署與負(fù)載均衡的擴(kuò)展如果單實(shí)例Node扛不住流量可以在同一臺(tái)服務(wù)器上起多個(gè)Node實(shí)例監(jiān)聽不同端口然后用Nginx做負(fù)載均衡。配置大概是這樣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; } }每個(gè)Node實(shí)例用單獨(dú)的nssm服務(wù)管理端口通過環(huán)境變量區(qū)分。這樣一臺(tái)服務(wù)器上可以跑多個(gè)實(shí)例充分利用多核CPU。Nginx默認(rèn)的負(fù)載均衡策略是輪詢也可以改成least_conn或者ip_hash根據(jù)業(yè)務(wù)需求選。提示多實(shí)例部署時(shí)如果Node項(xiàng)目里有本地文件上傳或者session存儲(chǔ)要注意多實(shí)例之間的數(shù)據(jù)同步問題。文件上傳建議放到共享存儲(chǔ)或者對(duì)象存儲(chǔ)session建議用Redis集中管理不要用內(nèi)存session。6.3 HTTPS配置與證書管理現(xiàn)在網(wǎng)站基本都要HTTPSNginx配置SSL很簡(jiǎn)單。拿到證書文件后在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; ... }同時(shí)把80端口的請(qǐng)求重定向到443server { listen 80; server_name your_domain.com; return 301 https://$host$request_uri; }證書文件路徑同樣用正斜杠。證書到期前要記得續(xù)期可以寫個(gè)腳本定時(shí)檢查證書有效期快到期時(shí)自動(dòng)更新并reload Nginx。6.4 部署流程的自動(dòng)化思路手動(dòng)部署容易出錯(cuò)尤其是多臺(tái)服務(wù)器的時(shí)候。可以寫一個(gè)簡(jiǎn)單的部署腳本用bat或者PowerShell把Git拉取、npm install、nssm restart這幾步串起來。每次更新代碼執(zhí)行一下腳本就行。更進(jìn)一步可以用CI/CD工具比如Jenkins或者GitLab CI自動(dòng)構(gòu)建和部署。但對(duì)于Windows服務(wù)器CI/CD的配置相對(duì)復(fù)雜中小團(tuán)隊(duì)用腳本就夠了。關(guān)鍵是腳本要能回滾如果新版本啟動(dòng)失敗能自動(dòng)切回舊版本。這個(gè)可以在腳本里加一個(gè)判斷啟動(dòng)后請(qǐng)求健康檢查接口失敗就回滾。6.5 我個(gè)人的一些經(jīng)驗(yàn)體會(huì)這套方案我在好幾個(gè)項(xiàng)目里用過整體是穩(wěn)的。最大的坑其實(shí)不在Nginx配置而在Windows的服務(wù)管理和路徑處理上。nssm的配置一定要仔細(xì)尤其是Path和Startup directory填錯(cuò)了服務(wù)起不來報(bào)錯(cuò)還不明顯。日志文件一定要配不然出了問題兩眼一抹黑。另外Windows Server的更新有時(shí)候會(huì)自動(dòng)重啟服務(wù)器如果服務(wù)沒配自啟那就全掛了。所以nssm的自動(dòng)啟動(dòng)和自動(dòng)重啟一定要測(cè)試通過。我一般會(huì)在部署完成后手動(dòng)重啟一次服務(wù)器確認(rèn)所有服務(wù)都能自動(dòng)起來這樣才放心。最后再分享一個(gè)小技巧Nginx的配置文件改完后不要直接nginx -s reload先用nginx -t檢查語(yǔ)法。這個(gè)習(xí)慣能避免很多因?yàn)榕渲脤戝e(cuò)導(dǎo)致的服務(wù)中斷。而且reload之前最好備份一下當(dāng)前配置萬一新配置有問題能快速回滾。