用 systemd 守护你的服务:开机自启 + 崩溃自动重启
你写了一个 Python 服务,怎么让它开机自动跑、崩了自动重启、日志有地方看?答案是 systemd。Linux 上跑后台服务的标准方式。
一、systemd 是什么
systemd 是 Linux 的初始化系统(init),负责管理所有系统服务。你写一个 unit 文件告诉它"怎么启动这个服务",它就帮你管生命周期。
二、创建服务文件
sudo nano /etc/systemd/system/myservice.service
[Unit]
Description=My Python Service
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/myservice
ExecStart=/usr/bin/python3 /opt/myservice/app.py
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
# 可选:环境变量
Environment=APP_ENV=production
Environment=PORT=8000
[Install]
WantedBy=multi-user.target
关键配置解释
After=network.target— 等网络就绪再启动(需要网络的服务必加)User=www-data— 以什么用户跑(别用 root)Restart=always— 崩了自动重启,重启间隔 5 秒WorkingDirectory— 工作目录,相对路径都基于这里PYTHONUNBUFFERED=1— Python 日志实时输出(不然会缓冲,日志延迟)
三、常用命令
# 重新加载配置(改完 unit 文件后必跑)
sudo systemctl daemon-reload
# 启动
sudo systemctl start myservice
# 停止
sudo systemctl stop myservice
# 重启
sudo systemctl restart myservice
# 查看状态
sudo systemctl status myservice
# 开机自启
sudo systemctl enable myservice
# 取消开机自启
sudo systemctl disable myservice
# 查看日志
sudo journalctl -u myservice -f # 实时跟踪
sudo journalctl -u myservice --since "1 hour ago" # 最近1小时
sudo journalctl -u myservice -n 50 # 最近50行
四、Restart 策略
Restart=always— 任何退出都重启(最常用)Restart=on-failure— 非 0 退出码才重启Restart=on-abnormal— 信号/超时/异常才重启Restart=never— 不重启(默认)
五、Python 服务特殊注意
日志缓冲
💡 必做:Python 默认缓冲 stdout,日志不会实时写到 journal。加
Environment=PYTHONUNBUFFERED=1 或者代码里用 print(..., flush=True)。虚拟环境
# 如果用 venv,路径要写绝对路径
ExecStart=/opt/myservice/venv/bin/python /opt/myservice/app.py
多 worker(用 gunicorn 等)
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/myservice
ExecStart=/opt/myservice/venv/bin/gunicorn app:app -w 4 -b 127.0.0.1:8000
Restart=always
六、调试技巧
服务起不来
sudo systemctl status myservice # 看状态和最近日志
sudo journalctl -u myservice -n 100 # 看更多日志
sudo /opt/myservice/venv/bin/python /opt/myservice/app.py # 手动跑,看报错
改了代码不生效
sudo systemctl restart myservice # 重启服务
# 或
sudo systemctl reload myservice # 如果服务支持 reload(Nginx 支持)
七、用户级服务(不需要 root)
个人开发时不想每次 sudo,可以用用户级服务:
# 文件放在 ~/.config/systemd/user/
mkdir -p ~/.config/systemd/user/
nano ~/.config/systemd/user/mydev.service
配置同上,只是 User= 那行去掉(默认当前用户)。然后:
systemctl --user daemon-reload
systemctl --user start mydev
systemctl --user enable mydev