web学习笔记编程技术学习与分享

用 systemd 托管一个常驻服务

2026 年 08 月 20 日约 3 分钟阅读 运维与部署

进程管理还在用 nohup ... &,服务器一重启就全丢。systemd 是现代 Linux 的标准答案,一个 unit 文件就能获得开机自启、崩溃自动拉起、日志收集。

最小可用模板

# /etc/systemd/system/worker.service
[Unit]
Description=My background worker
After=network.target mysql.service

[Service]
Type=simple
User=www
WorkingDirectory=/srv/app
ExecStart=/usr/bin/php /srv/app/bin/worker.php
Restart=always
RestartSec=5
Environment=APP_ENV=prod
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now worker    # 开机自启并立即启动
systemctl status worker

常用字段说明

  • Type=simple:前台进程(绝大多数框架的 worker 都是);守护进程用 forking 并配 PIDFile;
  • Restart=always:任何退出都重启;on-failure 只在非零退出时重启,更适合任务型进程;
  • RestartSec:避免崩溃风暴,5 秒起步;
  • User:不要用 root 跑业务进程,降权是最低成本的安全措施;
  • After= 只保证启动顺序,不保证依赖就绪——服务自己要有重连逻辑。

日志

stdout/stderr 自动进入 journal:

journalctl -u worker -f              # 实时跟踪
journalctl -u worker --since "1 hour ago"

应用自己写文件的日志仍会保留,但把异常栈打到 stderr 能让排障时少开一个终端。

定时任务也可以交给它

systemd timer 比 cron 多了「错过的任务补跑」能力(Persistent=true)和依赖管理,长期看值得迁移。crontab 更简单,两者共存没问题。

排障顺序

改了 unit 不生效 → daemon-reload;启动失败 → journalctl -xeu worker 看完整报错;资源不足 → systemctl show worker -p MemoryMax 检查是否被 cgroup 限制。

把服务器上所有 & 结尾的进程清单列一遍,逐个 unit 化,是接手一台老服务器最值得做的第一件事。

Linuxsystemd部署