跳到正文
English

从零搭建个人服务器(04):Node.js 与 PM2

完整记录 Node.js 生产环境部署与 PM2 守护配置:进程守护、集群模式、开机自启与日志管理。

DigitalScope1 min

nodejspm2deploy


服务器跑起来之后,最重要的问题就从「能不能访问」变成了「挂了怎么办」。这一篇记录 Node.js 进程守护与反向代理的完整配置——目标是:重启机器之后,一切自动恢复

先说结论:不要用 node app.js 直接对外。用 PM2 守护进程、Nginx 反代 80/443、pm2 startup 接管开机自启。

运行时选择#

Node.js 选择 LTS 版本(≥20),通过 NodeSource 源安装,避免 Ubuntu 仓库里的古老版本:

bash
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -sudo apt-get install -y nodejsnode -v # v22.x

进程守护#

PM2 的核心价值是:崩溃自动重启、集群模式利用多核、日志管理。最小可用的启动命令:

bash · deploy.sh
pm2 start dist/server.js --name blogpm2 save                    # 保存进程列表pm2 startup systemd         # 生成开机自启脚本

把「重启后自动恢复」写进部署验收清单——它是最容易被忽略、又最容易在半夜出问题的一环。

配置文件#

项目内维护 ecosystem.config.js,比命令行参数更可追溯:

js · ecosystem.config.js
module.exports = {  apps: [{    name: "blog",    script: "dist/server.js",    instances: 2,    exec_mode: "cluster",    max_memory_restart: "512M",  }],}

集群还是单进程#

场景建议原因
纯 API / SSR 服务cluster × CPU 核数吞吐量线性提升
内部状态多的服务fork 单实例共享内存语义简单
定时任务进程fork 单实例避免重复执行

Nginx 反向代理#

Nginx 负责 TLS、压缩与静态资源,Node 只处理动态请求。整体链路如下:

graph LR
    U[Visitor] -->|HTTPS :443| N[Nginx]
    N -->|proxy_pass :3000| P1[PM2 cluster #1]
    N -->|proxy_pass :3000| P2[PM2 cluster #2]
    P1 --> D[(日志 / 静态资源)]
    P2 --> D

关键配置:

nginx · blog.conf
server {    listen 443 ssl http2;    server_name blog.example.com;    location / {        proxy_pass http://127.0.0.1:3000;        proxy_set_header Host $host;        proxy_set_header X-Forwarded-Proto $scheme;    }    location /_next/static/ {        alias /var/www/blog/current/.next/static/;        expires max;        add_header Cache-Control "public, immutable";    }}

内存与连接的量化关系可以用一个粗略模型估算——假设单连接平均占用内存服从

Mtotal=n⋅c⋅mˉM_{total} = n \cdot c \cdot \bar{m}Mtotal=ncmˉ

其中 nnn 为集群实例数、ccc 为并发连接、mˉ\bar{m}mˉ 为单连接平均内存,MtotalM_{total}Mtotal 不应超过实例内存预算的 70%。1


上线检查清单#

  • pm2 list 状态全部 online,重启次数为 0
  • pm2 startup 已执行,服务器重启后自动拉起
  • Nginx -t 通过且已 reload
  • HTTPS 评级达标(目标 A+)
  • 日志切割与磁盘告警就位

Footnotes#

  1. 这是容量规划的粗估模型,实际压测才是金标准:用 autocannon -c 100 -d 30 打一轮再下结论。