在 systemd 下运行 Node.js 应用
如何在 VDS 上运行 Node 应用,使其在 SSH 断开和机器重启后依然存活:systemd 单元、环境变量、日志。
更新于 2026年8月23日
手动启动的 node index.js 会随 SSH 会话结束而终止。要让应用持续运行,并在重启后自动恢复,请将其作为 systemd 服务运行——这是系统内置机制,无需安装任何东西。
准备工作
从官方仓库安装 Node,而不是使用系统自带的旧软件包:
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
node -v
创建专用用户——应用绝不能以 root 身份运行:
useradd -r -m -d /srv/app -s /usr/sbin/nologin appuser
chown -R appuser:appuser /srv/app
sudo -u appuser npm ci --omit=dev --prefix /srv/app
systemd 服务
/etc/systemd/system/myapp.service 文件:
[Unit]
Description=My Node app
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/srv/app
EnvironmentFile=/srv/app/.env
ExecStart=/usr/bin/node /srv/app/index.js
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now myapp
systemctl status myapp
Restart=always 会在进程崩溃后将其重新拉起。EnvironmentFile 是普通的 KEY=value 文件,不加引号,也不写 export;由于其中存放密码,请将其权限设为 600。
通过代理对外暴露
应用应只监听 127.0.0.1:3000,由带证书的 Web 服务器对外提供服务:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
更多细节请参阅反向代理和 Let's Encrypt。如果应用监听 0.0.0.0,就可以绕过代理、以未加密的方式从互联网直接访问。
日志与更新
journalctl -u myapp -f
journalctl -u myapp --since "1 hour ago" -p err
systemctl restart myapp
输出到 stdout 的内容会自动写入 journal——您无需自行配置日志文件或日志轮转。
常见错误
| 现象 | 原因 |
|---|---|
status=203/EXEC | ExecStart 中 node 或文件的路径错误——请使用绝对路径 |
| 服务反复重启 | 应用在启动时崩溃:检查 journalctl -u myapp -n 50 |
EADDRINUSE | 手动启动的进程仍在运行:ss -tulpn | grep 3000 |
| 通过 SSH 运行正常,作为服务却不行 | 缺少环境变量——systemd 中没有这些变量,请在 EnvironmentFile 中设置 |
| 在 VDS-1 上构建时内存不足 | 在本地构建,然后将构建产物上传到机器 |
不要在 systemd 之上再套一层 pm2。一个进程由两个监管程序管理会造成混乱:pm2 正在重启进程时,systemd 却认为进程仍然存活。