systemd 服务管理:让程序开机自启、崩溃重启

概述

你在 VPS 上跑了一个 Python 脚本、Node.js 应用或者任何常驻程序。关掉 SSH 窗口它就停了。手动写 crontab 监控又太麻烦。

systemd 是 Linux 的初始化和系统服务管理器,它能帮你把一个普通程序变成真正的系统服务。开机自动启动、程序崩溃自动重启、日志统一收集、资源限制都能管。

学会这一招,你的 VPS 运维水平直接上一个台阶。

准备工作

你需要以下条件:

  • 一台运行 systemd 的 Linux VPS(Ubuntu 20.04+、Debian 11+、CentOS 8+ 都支持)
  • root 或 sudo 权限
  • 一个你想托管的程序(可以用任意 Python 脚本代替练习)
  • 约 0MB 磁盘空间(systemd 是系统自带组件)

先用下面的命令确认你的系统用的是 systemd:

systemctl --version

看到 systemd xx 的输出就对了。

步骤

第一步:准备你的程序

假设你有一个 Python 脚本放在 /root/myapp/app.py,内容如下:

#!/usr/bin/env python3
import time

while True:
    print(f"运行中 {time.strftime('%Y-%m-%d %H:%M:%S')}")
    time.sleep(60)

给它执行权限:

chmod +x /root/myapp/app.py

确保你的程序能用绝对路径运行。systemd 不会继承你的环境变量,所以路径一定要写全。

第二步:创建 systemd 服务文件

/etc/systemd/system/ 目录下创建一个 .service 文件:

sudo nano /etc/systemd/system/myapp.service

写入以下内容:

[Unit]
Description=My Python Application
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/root/myapp
ExecStart=/usr/bin/python3 /root/myapp/app.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

逐行解释一下关键配置:

  • After=network.target:等网络就绪后再启动
  • Type=simple:程序前台运行,systemd 直接管理
  • User=root:以 root 身份运行(生产环境建议用独立用户)
  • WorkingDirectory:程序的工作目录
  • ExecStart:启动命令,必须用绝对路径
  • Restart=on-failure:非正常退出时自动重启
  • RestartSec=5:重启前等待 5 秒
  • WantedBy=multi-user.target:多用户模式(正常开机)下启动

第三步:启动并启用服务

重载 systemd 配置:

sudo systemctl daemon-reload

启动服务:

sudo systemctl start myapp

设置开机自启:

sudo systemctl enable myapp

enable 会在 /etc/systemd/system/multi-user.target.wants/ 下创建一个符号链接,这样下次开机就会自动启动。

第四步:查看服务状态

sudo systemctl status myapp

输出类似这样:

● myapp.service - My Python Application
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
     Active: active (running) since Tue 2026-07-07 10:00:00 CST
   Main PID: 12345 (python3)
      Tasks: 1 (limit: 4915)
     Memory: 12.0M
        CPU: 200ms
     CGroup: /system.slice/myapp.service
             └─12345 /usr/bin/python3 /root/myapp/app.py

Active: active (running) 说明服务正在运行。

第五步:查看日志

systemd 自带日志系统 journalctl,不需要额外装东西:

# 实时查看日志
sudo journalctl -u myapp -f

# 查看最近 100 条日志
sudo journalctl -u myapp -n 100

# 只看今天的日志
sudo journalctl -u myapp --since today

# 查看上次启动到现在的日志
sudo journalctl -u myapp -b -1

-f 参数像 tail -f 一样实时滚动输出,调试的时候特别好用。

第六步:常用管理命令

# 停止服务
sudo systemctl stop myapp

# 重启服务
sudo systemctl restart myapp

# 重新加载配置(改了 service 文件后执行)
sudo systemctl reload-or-restart myapp

# 禁用开机自启
sudo systemctl disable myapp

# 查看服务的资源占用
sudo systemctl status myapp

验证

完成配置后,跑一组检查确认一切正常:

# 1. 确认服务状态
sudo systemctl is-active myapp
# 应该输出:active

# 2. 确认开机自启已启用
sudo systemctl is-enabled myapp
# 应该输出:enabled

# 3. 模拟崩溃,看能否自动重启
# 找到进程号
ps aux | grep app.py
# 杀掉它
sudo kill -9 <PID>
# 等 5 秒后检查是否自动恢复
sleep 5
sudo systemctl status myapp

如果杀掉进程后 systemd 自动重启了它,说明 Restart=on-failure 配置生效了。

常见问题

问:服务启动失败怎么排查?

sudo journalctl -u myapp -xe

加上 -xe 会显示详细错误信息和上下文。大部分情况下是路径不对、权限不足或者 Python 解释器找不到。

问:能不能限制服务的内存和 CPU 使用?

可以。在 [Service] 段加几行:

MemoryMax=512M
CPUQuota=100%

内存超过 512MB 会被强制终止,CPU 最多占用一个核心。

问:以普通用户运行服务?

先创建用户:

sudo useradd -r -s /bin/false myappuser

然后把 service 文件里的 User=root 改成 User=myappuser,并确保文件所有者也是这个用户:

sudo chown -R myappuser:myappuser /root/myapp

问:我的程序需要环境变量怎么办?

在 service 文件里加 Environment 行:

Environment="DATABASE_URL=postgres://localhost/mydb"
Environment="SECRET_KEY=mysecretkey"

或者从文件读取:

EnvironmentFile=/root/myapp/.env

.env 文件格式:

DATABASE_URL=postgres://localhost/mydb
SECRET_KEY=mysecretkey

问:多个服务之间有依赖关系怎么处理?

比如你的 Python 服务依赖 Redis:

[Unit]
Description=My App
After=network.target redis.service
Requires=redis.service

Requires 表示强依赖,Redis 挂了你的服务也会跟着停。

问:怎么把 systemd 服务和 Docker 容器配合使用?

ExecStart 里直接调用 docker 命令:

ExecStart=/usr/bin/docker start -a mycontainer

或者用 docker compose:

ExecStart=/usr/bin/docker compose -f /opt/myapp/docker-compose.yml up

systemd 是 Linux 运维的基石技能。掌握了它,你的 VPS 上跑的任何程序都能获得企业级的可靠性保障。把你那个总是断掉的脚本改成 systemd 服务,今晚就能睡个安稳觉。

你的 VPS 上有没有哪个程序经常挂掉?把它改成 systemd 服务试试。

这篇文章对你有帮助吗?