systemd 是 Ubuntu 20.04+ 唯一可靠控制启动时机、依赖和权限的机制;rc.local 和 @reboot crontab 因无依赖管理、环境缺失或执行时机不可控,易静默失败,应避免用于需网络、挂载点或服务依赖的场景。

systemd 是当前 Ubuntu(20.04+)唯一能可靠控制启动时机、依赖和权限的机制,其他方法要么失效,要么行为不可控。别用 rc.local 或用户级 crontab @reboot 去跑需要系统级资源的命令——它们大概率会因环境缺失、路径错误或权限不足而静默失败。
用 systemd 服务确保命令在网就绪后执行
这是最稳的方式,尤其当你执行的命令依赖网络(如 curl、git clone)、挂载点(如 /mnt/data)或特定服务(如 docker)时。
-
After=network.target保证网络已初始化,但不保证 DHCP 地址分配完成;若需更稳妥,加Wants=network-online.target并启用它:sudo systemctl enable systemd-networkd-wait-online.service -
User=推荐设为普通用户(如User=ubuntu),避免 root 权限滥用;若真需 sudo,直接在ExecStart=中调用/usr/bin/sudo,但必须确认该用户有免密权限(sudo visudo中加ubuntu ALL=(ALL) NOPASSWD: /path/to/cmd) -
WorkingDirectory=必须显式设置,否则脚本内相对路径(如./config.json)会从根目录开始找,直接报错 - 命令本身必须用绝对路径:
ExecStart=/usr/bin/bash /home/ubuntu/myscript.sh,不能写bash myscript.sh
@reboot crontab 只适合纯用户态、无依赖的简单命令
它本质是 cron 启动后扫一次 @reboot 行,不是“开机那一刻”,而是 cron 进程起来后才触发——这可能比你预期晚几十秒,且完全不感知网络或磁盘状态。
- 只对当前用户生效:
crontab -e编辑的是用户 crontab;要用 root 权限,得sudo crontab -e,而非普通用户加sudo在命令里 - 环境变量极简:PATH 默认只有
/usr/bin:/bin,~、$HOME不展开,所有路径必须绝对 - 常见失败现象:
@reboot /home/user/start.sh无声退出 → 检查grep CRON /var/log/syslog,十有八九是路径错或权限不足 - 若真要用,加延迟不是万能解:
@reboot sleep 20 && /home/user/start.sh仍可能因网卡未 up 而失败,不如换systemd+network-online.target
/etc/rc.local 在新版 Ubuntu 中默认禁用且不推荐
Ubuntu 18.04+ 已移除 rc-local service,默认不加载该文件。强行启用会绕过 systemd 的依赖管理,极易引发竞态——比如你的命令想读 /proc/mounts,但此时 NFS 尚未挂载完毕。
- 若坚持启用,先创建 service:
sudo systemctl enable rc-local;再确保/etc/rc.local以#!/bin/sh -e开头,末尾有exit 0 - 该文件内所有命令以 root 执行,但环境变量(如
$PATH)与交互式 shell 完全不同,which python3可能返回空 - 日志无处可查:
rc.local输出默认丢弃,加> /tmp/rclocal.log 2>&1才能看到失败原因
图形界面程序必须显式声明 DISPLAY 和桌面会话
想开机自动启动 firefox、gnome-terminal 或 Python 的 Tkinter 界面?systemd 服务默认没 GUI 上下文,会直接崩溃。
- 必须加两行:
Environment=DISPLAY=:0和Environment=XAUTHORITY=/home/username/.Xauthority(用户名替换成实际值) -
User=必须设为登录用户,不能是 root;否则.Xauthority文件权限拒绝访问 - 启动时机要延后:加
After=graphical-session.target,否则 X server 都没起来就去连:0 - 更稳妥的做法是放弃
systemd,改用桌面环境原生方式:~/.config/autostart/下放.desktop文件,它天然继承会话环境
systemctl status your-service 和 journalctl -u your-service -n 50 是唯二可信线索;其他方法失败时,你往往连日志在哪都不知道。


















