用 systemd 托管一个 Node 服务

2026 / 10 / 08#systemd#node#部署

最小可用的 unit

/etc/systemd/system/myapp.service:

[Unit]
Description=My App
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/app
ExecStart=/usr/bin/node /home/ubuntu/app/server.js
Restart=on-failure
RestartSec=3
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

然后:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp
journalctl -u myapp -f

三个最容易踩的坑

1. ExecStart 必须用绝对路径。 systemd 不读你的 shell 配置,node 这种裸命令大概率找不到 —— 尤其是通过 nvm 装的 Node,路径在 ~/.nvm/versions/node/vX/bin/node。用 which node 查出来写全。

2. WorkingDirectory 不写会出问题。 代码里用相对路径读配置、写日志,都会相对于 / 而不是项目目录,表现为"手动跑正常、服务起来就报文件找不到"。

3. 环境变量不在 .bashrc 里。 服务不会加载你的 shell 环境。敏感变量用单独文件:

EnvironmentFile=/home/ubuntu/app/.env

并确保该文件权限是 600、属主是运行用户。

和 pm2 怎么选

systemd pm2
安装 系统自带 需要 npm 装
日志 journald,统一 自己管文件
开机自启 原生 要额外 pm2 startup
多进程/负载均衡 要配多个 unit 内置 cluster
适合 单机单服务、简单可靠 多实例、需要面板

单机跑一两个服务,systemd 更省心 —— 少一个需要自己维护的守护进程。

改完之后

改 .service 文件后必须 daemon-reload,否则改动不生效。这一点和 nginx/caddy 改配置要 reload 是同一个道理,但 systemd 不会提示你。

本文为个人学习记录,可能存在错误或已过时,仅供参考。
← 返回笔记列表