教程 · 应用与数据库
用 pm2 让 Node.js 应用常驻并开机自启
难度
进阶
预计时长
25 分钟
步骤
7 步
最近修订
基准系统
Debian 12
要点
用 pm2 让 Node.js 应用常驻并开机自启
pm2 负责进程守护、崩溃重启与日志管理。让应用在重启后仍然自动回来需要三步:pm2 start 启动、pm2 save 保存进程列表、pm2 startup 生成 systemd 单元 —— 三步缺一不可,只做前两步的服务器重启后应用不会自己起来。
前置条件
开始之前,先确认这些都具备
- 一个可以本地跑起来的 Node.js 项目
- 已创建非 root 部署用户(应用应当以它的身份运行)
操作步骤
共 7 步
步骤 01 / 07
安装 Node.js #
发行版仓库里的 Node 往往落后好几个大版本。生产环境用 NodeSource 的源装 LTS 版本;如果需要在同一台机器上切换多个 Node 版本,用 nvm 更灵活,但 nvm 装的 Node 属于某个用户,配 systemd 自启时路径要写全。
Shell curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs node -v npm -v步骤 02 / 07
安装 pm2 #
pm2 全局安装一次即可。用部署用户安装还是 root 安装都能用,但要固定下来 —— 两个用户各装一份 pm2、各有一份进程列表,是排查「进程明明在跑却看不到」的常见原因。
Shell sudo npm install -g pm2 pm2 --version步骤 03 / 07
用 ecosystem 文件描述应用 #
把启动参数写进配置文件,而不是记在某个人的终端历史里。instances 与 exec_mode 决定是否开多进程;max_memory_restart 是内存泄漏时的兜底 —— 与其被 OOM Killer 突然杀掉,不如让 pm2 优雅重启。
JavaScript // ecosystem.config.cjs module.exports = { apps: [ { name: 'api', script: './dist/server.js', cwd: '/home/deploy/apps/api', instances: 2, exec_mode: 'cluster', max_memory_restart: '400M', env: { NODE_ENV: 'production', PORT: 3000, HOST: '127.0.0.1', }, error_file: '/home/deploy/logs/api-error.log', out_file: '/home/deploy/logs/api-out.log', }, ], }步骤 04 / 07
启动并查看状态 #
启动后先看日志确认没有启动即崩溃的情况。pm2 会不断重启崩溃的进程,如果配置有误,表现就是 restart 次数飞快上涨 —— 那个数字比「status: online」更能说明问题。
Shell pm2 start ecosystem.config.cjs pm2 list pm2 logs api --lines 100 pm2 describe api步骤 05 / 07
配置开机自启(最容易漏的一步) #
pm2 startup 会生成并安装一个 systemd 单元;用 -u 与 --hp 指定以哪个用户、哪个家目录恢复进程。之后必须再执行一次 pm2 save,把当前进程列表写进快照 —— 开机时恢复的正是这份快照。
Shell sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u deploy --hp /home/deploy # 切回 deploy 用户执行 pm2 save # 真的重启一次来验证,别只相信命令没报错 sudo reboot # 重连后: pm2 list步骤 06 / 07
开启日志轮转 #
pm2 默认把日志一直往一个文件里追加,小磁盘上这是个定时炸弹。pm2-logrotate 模块按大小切分并保留有限份数。
Shell pm2 install pm2-logrotate pm2 set pm2-logrotate:max_size 10M pm2 set pm2-logrotate:retain 7 pm2 set pm2-logrotate:compress true步骤 07 / 07
更新部署时用 reload 而不是 restart #
cluster 模式下 reload 会逐个替换工作进程,对外表现为零停机;restart 则是全部停掉再起来,中间那几秒访客会看到 502。
Shell cd /home/deploy/apps/api git pull npm ci --omit=dev npm run build pm2 reload api pm2 logs api --lines 50
常见错误
这一步最容易踩的坑
下面每一条都对应一个真实会发生的故障。先读完再动手,比出问题之后再回来查要省时间。
- 忘了 pm2 save。服务器重启后 pm2 起来了,进程列表却是空的 —— 这是「重启后网站没了」的头号原因。
- 用 root 跑应用图省事。应用被攻破就等于整台机器被攻破,用部署用户运行只多花两分钟。
- 应用监听 0.0.0.0。反向代理的所有防护都会被公网直连绕过,监听 127.0.0.1 才对。
- cluster 模式配多实例,但应用把会话存在进程内存里,结果用户随机掉登录。多实例要求会话外置(Redis 或数据库)。
- 日志不轮转,几个月后磁盘写满,服务器上什么都写不进去,故障表现却千奇百怪。
- 在 1 GB 内存机器上跑 npm ci 或 npm run build 被 OOM 结束。加 swap,或者在本地构建好再上传产物。
- 同时用 pm2 和 systemd 直接守护同一个应用,两边互相重启,端口反复被占。选一个。
这篇教程的边界
- 命令以 Debian 12 为准。Ubuntu 与 Rocky Linux 的差异只在正文明确标注之处,未标注的部分请以你所用发行版的官方文档为准。
- 示例中的 IP 来自文档保留段 203.0.113.0/24,域名为 example.com,端口为示意值。复制后必须替换成自己的值, 原样执行不会有任何效果。
- 教程不能替代备份。任何会改动数据或线上流量的步骤,执行前先确认有一份验证过能恢复的备份。
- 本站不提供任何用于绕过网络审查的配置或说明,这篇也不例外。
发现命令过时或有误,请发邮件到 [email protected]。 指出错误的邮件比沉默的旧文档有价值得多。