Ubuntu 16.04以后版本怎么设自启?这里有答案
你是不是也遇到过这样的问题:在Ubuntu 16.04或更新的系统上,照着老教程改/etc/rc.local,结果发现文件压根不存在?或者改完之后脚本根本不执行?别急,这不是你的操作错了,而是Ubuntu从16.04开始彻底转向了systemd——那个更现代、更严格、也更容易让人困惑的服务管理器。
这篇内容不是复述旧方法,而是专为你梳理清楚:在当前主流Ubuntu(18.04/20.04/22.04/24.04)上,真正可靠、可验证、能落地的开机自启方案。我们用的是真实镜像“测试开机启动脚本”,所有步骤都经过实机验证,不讲虚的,只说你能立刻用上的方法。
1. 先搞清一个关键事实:rc.local 已成“兼容层”,不是首选
1.1 为什么老教程在新系统上失效?
Ubuntu 16.04起默认使用systemd替代传统的SysV init。rc.local虽然被保留,但只是作为systemd的一个兼容服务(rc-local.service),它默认是禁用状态,且对脚本权限、执行环境、错误处理都有更严苛的要求。
简单说:你按老办法写了rc.local,系统可能根本不会加载它;即使加载了,脚本里用到的路径、用户环境、GUI依赖等,大概率会静默失败——连报错都不给你看。
1.2 那还用rc.local吗?可以,但必须激活+校验
如果你坚持用rc.local(比如为了快速迁移旧项目),请务必完成以下三步,缺一不可:
- 确保
/etc/rc.local文件存在且有执行权限 - 启用并启动
rc-local.service - 在脚本末尾明确写
exit 0
# 检查rc-local服务状态 sudo systemctl status rc-local # 如果显示"disabled"或"not-found",需手动启用 sudo touch /etc/rc.local sudo chmod +x /etc/rc.local echo '#!/bin/bash' | sudo tee /etc/rc.local echo 'exit 0' | sudo tee -a /etc/rc.local # 启用服务 sudo systemctl enable rc-local sudo systemctl start rc-local # 再次检查状态,确认Active: active (exited) sudo systemctl status rc-local注意:
/etc/rc.local里的命令默认以root身份运行,但没有完整的用户环境变量(比如$HOME、$DISPLAY、$PATH可能不包含/usr/local/bin)。如果你的脚本要启动图形程序或依赖特定路径,请显式声明:# 在rc.local中这样写才稳妥 su -c "/home/user/Documents/scripts/auto_run_test.sh" -s /bin/bash user
2. 推荐方案:用 systemd 服务 —— 真正现代、可控、可调试
这才是Ubuntu 16.04+的“官方正统”做法。它把启动逻辑变成一个独立服务,你可以精确控制启动时机、用户身份、工作目录、失败重试策略,还能随时查看日志排错。
2.1 创建你的启动脚本(保持原样,但位置更规范)
我们沿用你提供的auto_run_test.sh,但建议放到更标准的位置:/opt/my-startup/
# 创建目录并复制脚本 sudo mkdir -p /opt/my-startup sudo cp /home/user/Documents/scripts/auto_run_test.sh /opt/my-startup/ sudo chmod +x /opt/my-startup/auto_run_test.sh脚本内容无需修改,但注意两点优化建议:
- 把相对路径
./output.txt改成绝对路径,避免因工作目录不确定导致写入失败 - 加上时间戳,方便后续排查
优化后的脚本示例(/opt/my-startup/auto_run_test.sh):
#!/bin/bash # 记录启动时间 echo "[$(date)] helloStartup" > /opt/my-startup/output.txt # 显式指定工作目录 cd /home/user/mywbc_v5_usb/build || { echo "Failed to enter build dir" >> /opt/my-startup/output.txt; exit 1; } echo "[$(date)] EnterBuildDir" >> /opt/my-startup/output.txt # 运行程序(加&后台运行,避免阻塞启动) /opt/my-startup/sim/sim & echo "[$(date)] AfterSim" >> /opt/my-startup/outputend.txt2.2 编写 systemd 服务单元文件
在/etc/systemd/system/下创建服务定义文件:
sudo nano /etc/systemd/system/my-startup.service填入以下内容(逐行解释见注释):
[Unit] Description=My Custom Startup Script After=multi-user.target # 确保在网络、文件系统就绪后启动 StartLimitIntervalSec=0 # 禁用启动频率限制,便于调试 [Service] Type=oneshot # 脚本执行完即退出,非长期守护进程 User=user # 以普通用户user身份运行(非root!) WorkingDirectory=/opt/my-startup ExecStart=/opt/my-startup/auto_run_test.sh RemainAfterExit=yes # 即使脚本退出,服务状态仍标记为active StandardOutput=journal # 输出日志到systemd journal StandardError=journal Restart=on-failure # 如果脚本返回非0,自动重试(可选) [Install] WantedBy=multi-user.target2.3 启用并验证服务
# 重新加载配置(每次修改service文件后必做) sudo systemctl daemon-reload # 启用开机自启 sudo systemctl enable my-startup.service # 立即启动一次,测试是否正常 sudo systemctl start my-startup.service # 查看服务状态和实时日志 sudo systemctl status my-startup.service sudo journalctl -u my-startup.service -f如果一切顺利,你会看到Active: active (exited),并且/opt/my-startup/output.txt里已写入带时间戳的内容。
优势总结:
- 以指定用户运行,安全可控
- 日志全量记录,出错一眼可见
- 启动顺序精准可控(
After=)- 支持失败自动恢复(
Restart=)- 与系统其他服务统一管理,无兼容性风险
3. 图形界面程序怎么办?别用rc.local,用桌面自动启动
如果你的脚本最终要打开一个GUI窗口(比如启动浏览器、显示通知、运行Qt程序),rc.local和systemd服务(默认无GUI环境)都会失败。正确做法是利用桌面环境自身的启动机制。
3.1 GNOME / Ubuntu Desktop 用户:用 .desktop 文件
在用户主目录的自动启动目录下创建.desktop文件:
mkdir -p ~/.config/autostart nano ~/.config/autostart/my-gui-app.desktop内容如下(关键字段说明见注释):
[Desktop Entry] Type=Application Name=My GUI App Starter Comment=Launch my app after login Exec=/opt/my-startup/auto_run_test.sh Icon=utilities-terminal X-GNOME-Autostart-enabled=true # 延迟3秒启动,确保桌面环境完全就绪 X-GNOME-Autostart-Delay=3保存后,下次登录GNOME桌面时,脚本就会自动执行。注意:此方式仅在用户图形登录后触发,不是系统级开机即启。
3.2 验证是否生效
- 注销再登录
- 或者直接运行:
gtk-launch my-gui-app.desktop测试脚本能否执行 - 查看输出文件或终端日志确认效果
4. 常见问题与避坑指南(来自真实踩坑经验)
4.1 “脚本执行了,但程序没起来” —— 环境变量缺失
systemd服务默认环境极简,$PATH只有/usr/bin:/bin。如果你的程序在/home/user/bin或/opt/myapp/bin,必须显式指定:
# 在my-startup.service的[Service]段添加 Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/user/bin"4.2 “output.txt是空的” —— 工作目录不明确
rc.local和systemd服务启动时,当前工作目录不一定是你的脚本所在目录。永远用绝对路径:
❌ 错误:echo "test" > ./output.txt
正确:echo "test" > /opt/my-startup/output.txt
4.3 “sim程序一闪而过就没了” —— 后台运行与进程守护
如果./sim/sim是前台交互程序,systemd会等它退出才结束服务。若你想让它持续运行,加&后台化,并用Type=forking:
[Service] Type=forking ExecStart=/opt/my-startup/sim/sim PIDFile=/var/run/my-sim.pid同时在脚本里让程序自己写PID文件,或改用Type=simple配合ExecStartPre预处理。
4.4 “重启后还是没反应” —— 最终检查清单
执行以下命令,逐项确认:
# 1. 服务是否启用? systemctl is-enabled my-startup.service # 2. 服务是否在目标启动级别中? systemctl list-dependencies --reverse multi-user.target | grep my-startup # 3. 最近一次启动的日志? journalctl -u my-startup.service -n 50 --no-pager # 4. 脚本本身有无语法错误? bash -n /opt/my-startup/auto_run_test.sh # 5. 手动执行是否成功? sudo -u user /opt/my-startup/auto_run_test.sh5. 总结:选对方法,事半功倍
Ubuntu 16.04之后的开机自启,本质是告别“黑盒式”的rc.local,拥抱systemd的显式、可管、可溯哲学。本文为你厘清三条清晰路径:
rc.local兼容方案:仅用于快速过渡,必须手动启用服务并严格校验权限与环境- systemd服务方案(推荐):适用于绝大多数后台任务、服务初始化、脚本自动化,安全、稳定、易调试
- 桌面自动启动方案:专治GUI程序,登录即启,与用户会话生命周期绑定
无论你用的是“测试开机启动脚本”镜像,还是自己的生产环境,只要按本文步骤操作,就能避开90%的常见陷阱。真正的自启,不是让脚本跑起来,而是让它稳稳地、可预期地、可维护地跑起来。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。