必须用 systemd 服务文件实现可靠开机自启,关键在于正确配置 ExecStart 绝对路径、User、WorkingDirectory、After=network-online.target、Type 及权限与重载验证,/etc/rc.local 和 @reboot cron 因环境缺失仅适用于临时验证。

现代 Linux(Ubuntu 20.04+、CentOS 7+、Debian 10+)必须用 systemd 服务文件实现可靠开机自启;/etc/rc.local 和 @reboot cron 都有严重环境缺失,只适合临时验证或极轻量任务。
怎么写一个能真正跑起来的 .service 文件
关键不是“写完就完事”,而是让 systemd 知道它该什么时候、以谁的身份、用什么环境跑。常见失败是因为 ExecStart 写成 shell 命令行,或漏掉依赖声明。
-
ExecStart=必须是绝对路径:写ExecStart=/usr/bin/python3 /opt/myapp/start.py,不能写ExecStart=python3 start.py - 脚本需要用户环境?显式加
User=www-data和WorkingDirectory=/opt/myapp,否则~/.ssh或相对路径全失效 - 依赖网络?
After=network-online.target比After=network.target更稳妥,但得配套启用systemd-networkd-wait-online.service - 启动后不退出?别用
nohup & exit,改用Type=simple并确保主进程前台阻塞,或设Type=forking+PIDFile=
为什么 systemctl enable 了还是不启动
enable 只是创建软链接,不代表服务就一定能跑。最常被忽略的三个环节:权限、重载、启用状态验证。
- 服务文件权限必须是
644:sudo chmod 644 /etc/systemd/system/myscript.service - 改完文件后必须执行
sudo systemctl daemon-reload,否则enable和start都读不到新内容 - 启用后检查真实状态:
systemctl is-enabled myscript.service返回enabled才算成功;WantedBy=multi-user.target是服务器默认目标,别写成graphical.target
/etc/rc.local 看似简单,为什么总失败
它不是“系统服务启动完才跑”,而是“init 进程扫到就执行”,网络、挂载、DNS 常未就绪,且环境变量几乎为零。
- 必须先启用
rc-local服务:sudo systemctl enable rc-local,否则该文件压根不执行 - 脚本里所有命令用绝对路径:
/usr/bin/curl而不是curl,/bin/date而不是date - 首行必须是
#!/bin/bash,且文件本身要有可执行权限:sudo chmod +x /etc/rc.local - 日志别省:
/path/to/script.sh >> /var/log/rclocal.log 2>&1,否则出错完全没线索
@reboot cron 的隐蔽陷阱
它由 crond 触发,不是系统级启动机制,没有 $HOME、$PATH 极窄、无 ssh-agent、不等网络就绪——看似能跑,实则脆弱。
- 必须手动补环境:
@reboot PATH=/usr/local/bin:/usr/bin:/bin HOME=/home/username /path/to/script.sh - 依赖网络?别靠
sleep 30碰运气,脚本内应轮询:while ! ping -c1 -W1 google.com >/dev/null; do sleep 5; done - 用户级 crontab(
crontab -e)比系统级(/etc/crontab)更安全,避免误用 root 权限 - 输出重定向不能省:
@reboot /path/to/script.sh >> /var/log/reboot.log 2>&1,否则 stderr 丢失,debug 无从下手
真正难的不是“怎么写”,而是“怎么验证它在 reboot 后真的一次性跑对”。journalctl -u myscript.service -n 50 -f 是唯一可信依据,别信重启后手动 systemctl start 成功就等于开机自启成功。


















