现代 linux 系统必须用 systemctl enable 配合规范 .service 文件管理开机任务,禁用 rc.local 和 @reboot cron;服务文件须置于 /etc/systemd/system/、命名以 .service 结尾、权限 644,编辑后必执行 daemon-reload;[unit]、[service]、[install] 三段齐全,execstart 用绝对路径,type 与进程行为匹配,wantedby=multi-user.target 不可少;启用后需 is-enabled 验证并用 journalctl -u 查日志。

现代 Linux 系统(Ubuntu 20.04+、CentOS 7+、Debian 10+)必须用 systemctl enable 配合规范的 .service 文件来管理自定义开机任务,其他方式如 rc.local 或 @reboot cron 不可靠,尤其在服务依赖、环境变量、日志追踪和错误恢复方面严重缺失。
服务文件必须放对位置、命名规范、权限正确
自定义服务文件只能放在 /etc/systemd/system/ 目录下,不能放进 /lib/systemd/system/(那是包管理器专用路径,手动改会被覆盖),也不能建子目录(systemd 不扫描子目录)。
- 文件名必须以
.service结尾,例如mytask.service - 权限必须设为
644:sudo chmod 644 /etc/systemd/system/mytask.service - 每次编辑完必须立即执行:
sudo systemctl daemon-reload,否则enable会静默失败,无任何提示
Service 文件三段结构要写全、关键字段不能漏
[Unit] 描述服务意图与依赖;[Service] 定义如何运行;[Install] 决定是否开机启动。缺一不可。
-
[Unit]中至少要有Description=和启动时机控制,比如After=network.target或Wants=network-online.target -
[Service]中ExecStart=是唯一必需字段,且必须写绝对路径,例如ExecStart=/usr/bin/bash /opt/myscript.sh,不能写bash myscript.sh -
Type=要匹配脚本行为:一次性脚本用oneshot并加RemainAfterExit=yes;长期运行程序用simple,且主进程必须前台运行(不能后台化退出) -
[Install]中必须有WantedBy=multi-user.target,否则enable无效
常见执行失败原因和对应修复
服务卡在 activating (start) 或秒退报 failed with result 'exit-code',大概率是 ExecStart 写错或环境不完整。
- 脚本用了 Python 虚拟环境?必须显式声明:
Environment="PATH=/opt/myapp/venv/bin:/usr/local/bin:/usr/bin:/bin" - 脚本里有中文、没写 shebang(
#!/bin/bash)、或路径含空格未引号包裹,都会导致启动失败 - 脚本内部调用了
nohup & exit或systemctl start xxx?systemd 会认为主进程已退出,服务结束;应让主逻辑前台阻塞,或改用Type=forking+PIDFile= - 依赖网络但没等连通?把
After=network.target换成After=network-online.target并加上Wants=network-online.target
启用后验证是否真能开机自启
只写好 .service 文件 ≠ 开机自启。systemd 严格区分「配置存在」和「启用状态」。
- 执行
sudo systemctl enable mytask.service才算注册进启动流程 - 检查是否启用:
systemctl is-enabled mytask.service应返回enabled - 手动测试启动:
sudo systemctl start mytask.service,再用systemctl status mytask.service查看实时状态和错误 - 看日志最直接:
journalctl -u mytask.service -n 50 -f,所有 stdout/stderr 都在这里,不用自己重定向











