0aa8fe6
这次没有正文改动。
这是 linux/用 systemd 托管一个自写服务.md 的改动记录。后台每次保存都会留一份快照,
这里显示的是快照之间的差异,不会混入其他文章的改动。
还没有后台修改记录。
下面是 Git 里的提交,可能包含其他文章的改动(因为一次提交会带上工作区所有变化)。
0aa8fe6
这次没有正文改动。
be5956e
@@ -0,0 +1,83 @@ +--- +tags: [systemd, 服务, Linux] +order: 30 +--- + +# 用 systemd 托管一个自写服务 + +## 场景 + +脚本或程序要开机自启、挂了自动拉起、日志能查。别再写 `nohup &` 了。 + +## 前置条件 + +- 程序有确定的启动命令和运行目录 +- 用独立用户跑,不要用 root +- 知道它会写哪些目录 + +## 配置 + +```bash +# 建用户 +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 +``` + +## 验证 + +```bash +systemctl status myapp +journalctl -u myapp -n 100 --no-pager +journalctl -u myapp -f +systemctl restart myapp +``` + +杀进程测试自动拉起: + +```bash +pkill -f main.py && sleep 4 && systemctl is-active myapp +``` + +## 回滚 + +```bash +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`,这个坑踩过不止一次。