关闭 SSH 后网站也应该继续运行
在终端执行 npm start 能证明应用可运行,不能证明它适合生产。会话断开、服务器重启或进程崩溃后,网站可能直接消失。systemd 的价值是把运行方式写成系统可理解的声明:以谁运行、从哪里启动、失败如何处理、日志去哪里。 开始前先完成 新服务器基础配置 与 SSH、防火墙安全设置。下面使用 myapp 和 127.0.0.1:3000 作为示例,目录与命令必须替换成项目真实值。
先用专用用户跑通同一条启动命令
创建不能交互登录的系统用户,并让它只拥有需要的目录。不要直接写 unit 后反复猜权限;先切换到该用户,用生产环境变量执行准确启动命令。
sudo useradd --system --home /opt/myapp --shell /usr/sbin/nologin myapp
sudo chown -R myapp:myapp /opt/myapp
sudo -u myapp -H /usr/bin/node /opt/myapp/server.js确认应用只监听 127.0.0.1:3000,并用 curl http://127.0.0.1:3000/health 验证。Node、pnpm 或其他运行时路径要使用 command -v 找到的绝对路径;systemd 不会自动加载你的交互式 shell 配置。
环境文件与 unit 分开保存
把非公开配置放到 /etc/myapp/myapp.env,所有者 root,组可以是应用专用组,权限限制为 640 或更严格。环境文件不是保险箱,拥有读取权限的进程仍能看到它;真正高敏感值还要结合专用 secrets 机制和轮换。
# /etc/systemd/system/myapp.service
[Unit]
Description=My website application
After=network.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target不要在 ExecStart 里写依赖 shell 展开的复杂串联命令。需要构建、迁移和启动三个阶段时,把构建放在发布流程,数据库迁移单独控制,服务只负责启动已经准备好的版本。
加载、启动与验证要分三步
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl status myapp --no-pager
curl -fsS http://127.0.0.1:3000/health
sudo systemctl enable myapp先 start 并验证健康,再 enable 开机启动。status 显示 active 只说明进程存在,不代表页面可用,所以必须请求健康端点。随后重启服务器做一次真实验收,确认服务和反向代理都能自动回来。
Restart 不是越积极越好
Restart=on-failure 适合意外退出,RestartSec 给依赖恢复和日志留时间。不要用极短间隔无限重启一个配置错误的程序,它会刷满日志并掩盖首个错误。systemd 有启动频率限制,触发后应查看根因,修复后再 reset-failed。 应用主动正常退出是否需要重启,取决于进程语义。定时任务不应伪装成长驻服务;一次性迁移也不应配置永久重启。
用 journalctl 看当前这一轮,而不是淹没在历史里
journalctl -u myapp -n 100 --no-pager
journalctl -u myapp -f
journalctl -u myapp --since '20 minutes ago'日志里应有时间、级别和请求关联信息,但不能打印密码和完整令牌。应用自行写文件时还要配置轮转;若统一进入 journal,也要确认系统日志的磁盘上限和保留周期。
完成标准
关闭 SSH 后应用仍在,服务器重启后自动回来,进程不是 root,环境文件权限可解释,健康端点成功,journalctl 能找到一次启动和一次失败原因。下一篇把公网请求安全地交给它:Caddy 多站点反向代理与配置验证。
参考来源
- systemd.servicesystemd
- systemd.execsystemd