优先用systemd,它是现代Linux发行版的事实标准,支持依赖管理、日志集成、自动重启;rc.local次之,但需手动启用且缺乏环境与依赖保障;@reboot crontab因无依赖等待、无网络就绪、无环境变量而极易静默失败。

直接说结论:优先用 systemd,其次用 /etc/rc.local,别碰 @reboot crontab 做开机启动——它根本不管依赖、不等网络、不设环境变量,重启后静默失败是常态。
为什么 systemd 是首选(不是“推荐”,是事实标准)
几乎所有主流发行版(Ubuntu 16.04+、Debian 8+、CentOS/RHEL 7+、Fedora)都以 systemd 为 init 系统。它不是“让脚本跑一下”,而是把脚本当服务管:能定义启动顺序、检查依赖、捕获日志、崩溃后可选重试。
-
After=network.target表示等网络就绪后再运行,避免curl或ssh直接超时 -
Type=oneshot+RemainAfterExit=yes适合只执行一次但需“长期存在状态”的脚本(如挂载、初始化) - 日志统一归到
journalctl -u myjob.service,不用自己重定向到文件 - 路径必须写全:
ExecStart=/usr/local/bin/myscript.sh,不能写./myscript.sh或省略.sh
/etc/rc.local 还能用吗?能,但有硬性前提
它在系统基础服务启动完后执行,简单直接,但 CentOS 7+/Ubuntu 18.04+ 默认不启用,且容易因权限或路径失效。
- 必须先加执行权限:
sudo chmod +x /etc/rc.d/rc.local(注意路径是/etc/rc.d/rc.local,不是/etc/rc.local;后者在某些系统里只是软链) - 文件首行必须是
#!/bin/bash,且不能被注释掉 - 所有命令必须用绝对路径:
/usr/bin/python3 /opt/myapp/start.py,不能只写python3 start.py - 必须插在
exit 0之前,否则整段被跳过 - 如果脚本依赖数据库或远程服务,得自己加等待逻辑,比如
until nc -z localhost 5432; do sleep 2; done
@reboot crontab 是最危险的“快捷方式”
它在内核初始化刚完成、用户空间服务几乎都没起来时就触发,看似简单,实则埋雷最多。
- 环境变量极简:
$PATH通常只有/usr/bin:/bin,python3、node、jq等很可能找不到 - 网络未就绪:网卡可能刚 up,但 DHCP 没完成、DNS 未加载,
wget或ping必然失败 - 无日志捕获:命令出错不会输出到任何地方,除非你手动重定向
> /tmp/cron-boot.log 2>&1 - 只执行一次:脚本中途崩溃或 exit 非 0,crontab 不会重试,也不会告警
最容易被忽略的三个细节
无论用哪种方式,以下三点不做,90% 的自启脚本都会“看似配置成功,实则从未运行”:
- 脚本第一行必须是
#!/bin/bash(不是#!/bin/sh,尤其用了$(date)这类 bash 特性时) - 所有路径写绝对路径,包括脚本里调用的命令(
/bin/echo、/usr/bin/curl)、日志文件(/var/log/myscript.log)、工作目录(用cd /opt/myapp显式切换) - 验证不能只看“有没有报错”,要查真实执行痕迹:用
sudo journalctl -b | grep myscript(systemd),或sudo tail -20 /var/log/syslog | grep rc.local(rc.local),或sudo systemctl status myjob.service











