概述
你在 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 服务试试。