返回笔记列表

用 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