systemd服务文件必须包含[unit]、[service]、[install]三段,缺一不可;少一段会导致systemctl enable静默失败,无错误提示,且无法生成软链接实现开机启动。

systemd服务文件必须包含哪三段
缺一不可:[Unit]、[Service]、[Install]。少一段,systemctl enable 会静默失败,连错误提示都不给。
常见错误是只写了 [Unit] 和 [Service],漏掉 [Install] —— 这会导致 systemctl enable myscript.service 执行后什么也不发生,/etc/systemd/system/multi-user.target.wants/ 下没有软链接,重启后自然不运行。
-
[Unit]里至少要写Description=和依赖项,比如After=network.target local-fs.target(网络和本地文件系统就绪后再启动) -
[Service]必须有Type=和ExecStart=;ExecStart=后面的路径必须是绝对路径,不能用~/或./ -
[Install]只需一行:WantedBy=multi-user.target;别写成WantedBy=default.target或graphical.target,后者在服务器上通常不激活
脚本权限和解释器声明经常被忽略
systemd 不会帮你执行 chmod +x,也不会自动识别脚本类型。如果脚本没权限或没声明解释器,systemctl start 直接报 Permission denied 或 Exec format error。
- 脚本第一行必须是有效的 shebang,例如:
#!/bin/bash或#!/usr/bin/env python3 - 必须手动加执行权限:
sudo chmod +x /opt/scripts/myscript.sh - 别把脚本放在
/home/xxx/下——systemd 默认不读取用户家目录,User=设为普通用户时,WorkingDirectory=必须显式指定,且该目录得存在、可访问 - 测试时别只跑
./myscript.sh,要用sudo -u appuser /opt/scripts/myscript.sh模拟 systemd 实际执行环境
为什么 systemctl enable 后脚本还是不运行
不是配置写错,就是流程没走全。最常卡在三个环节:重载没做、enable 没生效、日志没查。
- 改完
.service文件后,必须先运行sudo systemctl daemon-reload,否则systemctl enable找不到这个服务 -
systemctl enable只建软链接,不启动服务;当前想验证,得额外执行sudo systemctl start myscript.service - 看状态别只信
active (running)—— 有些脚本一秒就退出,Type=oneshot才合适;这时要看sudo systemctl status myscript.service里的ExitCode=和ActiveEnterTimestamp= - 查日志别
tail -f /var/log/syslog,直接用sudo journalctl -u myscript.service -n 50 --no-pager,它能精确过滤服务输出,包括 stdout/stderr 和 systemd 自身的启动信息
rc.local 和 crontab @reboot 的真实限制
它们能“跑起来”,但不可靠。尤其在新发行版(Ubuntu 24.04、Debian 12、RHEL 9)上,/etc/rc.local 默认禁用,@reboot 的环境比你想象中更空。
-
/etc/rc.local在 systemd 中只是个兼容层,执行时机早于network.target,脚本里用curl或ping很可能失败;必须手动启用rc-local.service,且首行#!/bin/bash缺不得 -
@reboot条目里,$PATH基本只有/usr/bin:/bin,$HOME是空的,ssh-agent、conda 环境、自定义 bin 目录全不可用;硬加sleep 10是赌运气,不如在脚本里轮询检查网络就绪 - 所有通过
rc.local或@reboot启动的脚本,都不能依赖 systemd 提供的日志、重启策略、资源限制(cgroup)和依赖管理——出问题只能自己 debug,systemd 不管
$DISPLAY、没 $XDG_RUNTIME_DIR、PATH 极短、umask 是 0022。哪怕脚本逻辑完全正确,少了 Environment=PATH=/usr/local/bin:/usr/bin:/bin 或 User= 配错,也会静默失败。











