用 systemd 托管一个自写服务
场景
脚本或程序要开机自启、挂了自动拉起、日志能查。别再写 nohup & 了。
前置条件
- 程序有确定的启动命令和运行目录
- 用独立用户跑,不要用 root
- 知道它会写哪些目录
配置
# 建用户
useradd -r -s /usr/sbin/nologin appuser
# 单元文件
cat >/etc/systemd/system/myapp.service <<'EOF'
[Unit]
Description=My App
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/myapp
Environment="TZ=Asia/Shanghai"
EnvironmentFile=-/opt/myapp/.env
ExecStart=/opt/myapp/venv/bin/python /opt/myapp/main.py
Restart=always
RestartSec=3
LimitNOFILE=65535
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now myapp
验证
systemctl status myapp
journalctl -u myapp -n 100 --no-pager
journalctl -u myapp -f
systemctl restart myapp
杀进程测试自动拉起:
pkill -f main.py && sleep 4 && systemctl is-active myapp
回滚
systemctl disable --now myapp
rm /etc/systemd/system/myapp.service
systemctl daemon-reload
坑
- 改了 unit 文件必须
daemon-reload,否则start还是旧配置。 Type=forking要配 PIDFile,配错会一直activating。EnvironmentFile里的值不要加引号外层再加引号,会原样传进去。- 程序自己要写日志文件时,注意目录属主是
appuser。 Restart=always遇到配置错误会无限重启,看journalctl里的报错再修。- 不要用
systemctl edit之后忘记daemon-reload,这个坑踩过不止一次。