不用再搜了!这才是Ubuntu开机启动脚本的正确写法
1. 开机自启没你想的那么简单
你是不是也遇到过这种情况:写了个脚本,想让它开机自动运行,结果重启后发现根本没执行?或者明明配置好了rc.local,却始终不生效?
别急,这在 Ubuntu 上太常见了。尤其是从 16.04 开始,systemd 成为默认初始化系统后,很多老方法都失效或变得不稳定。网上搜一圈,各种教程五花八门,有的说改rc.local,有的教写 service 文件,还有的推荐用cron @reboot——但真正能稳定工作的少之又少。
今天这篇文章就是来终结混乱的。我会手把手带你实现一个稳定、可靠、可维护的开机启动方案,并告诉你为什么其他方式容易翻车。
我们以一个实际需求为例:
假设你有一个 Python 程序放在/home/ubuntu/myapp/start.py,希望它在每次开机时自动启动,并且有日志记录、失败能自动重启。
接下来,我会介绍三种主流方式,重点分析它们的优缺点,最后给出强烈推荐的最佳实践。
2. 方法一:通过 /etc/rc.local 启动(兼容性尚可,但已过时)
2.1 原理简介
/etc/rc.local是传统的 Unix/Linux 开机脚本,在系统进入多用户模式前执行。虽然 Ubuntu 已转向 systemd,但仍保留了对它的兼容支持。
2.2 操作步骤
- 编辑文件:
sudo nano /etc/rc.local- 在
exit 0之前添加你的命令:
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # 任务开始 /home/ubuntu/myapp/start.py & echo "My app started via rc.local" >> /var/log/rc-local.log exit 0- 给予执行权限:
sudo chmod +x /etc/rc.local- 确保服务启用(某些版本需要):
sudo systemctl enable rc-local2.3 存在的问题
- 执行时机不确定:网络、挂载点可能还没准备好。
- 无进程管理:程序崩溃后不会自动重启。
- 权限问题多:普通用户路径下的脚本可能因环境变量缺失而失败。
- Ubuntu 20.04+ 默认不启用:必须手动创建
rc-local.service才能生效。
小贴士:如果你看到
rc.local根本没运行,大概率是因为rc-local.service没被激活。可以用systemctl status rc-local查看状态。
3. 方法二:使用 cron 的 @reboot(简单但局限大)
3.1 原理说明
Cron 支持一种特殊语法@reboot,表示“仅在系统重启后运行一次”。适合轻量级任务。
3.2 配置方法
- 编辑当前用户的 cron 表:
crontab -e- 添加一行:
@reboot /usr/bin/python3 /home/ubuntu/myapp/start.py >> /home/ubuntu/logs/boot.log 2>&13.3 优点与缺陷
| 优点 | 缺点 |
|---|---|
| 配置简单,无需 root 权限 | 只运行一次,无法监控进程 |
| 用户级配置,灵活 | 脚本崩溃后不会重启 |
| 自带日志重定向方便 | 环境变量可能不完整 |
实测反馈:这种方式看似简单,但在桌面环境或 GUI 登录前,GUI 相关操作会失败;服务器环境下倒是可用,但缺乏健壮性。
4. 方法三:编写 Systemd Service(强烈推荐!这才是正确姿势)
4.1 为什么这是最佳选择?
Systemd 是现代 Linux 的核心组件,具备以下优势:
- 精确控制启动顺序(比如等网络就绪后再启动)
- 自动重启机制
- 资源隔离和限制
- 完整的日志追踪(journalctl)
- 状态管理(start/stop/status/restart)
这才是符合当前技术趋势的正规军打法。
4.2 创建服务文件
- 新建服务配置:
sudo nano /etc/systemd/system/myapp.service- 写入以下内容(请根据实际情况修改路径和用户名):
[Unit] Description=My Custom Startup Application After=network.target syslog.target Wants=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/myapp ExecStart=/usr/bin/python3 /home/ubuntu/myapp/start.py Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=myapp [Install] WantedBy=multi-user.target参数解释:
After=network.target:确保网络已启动User=ubuntu:指定运行用户,避免权限问题Restart=always:崩溃后自动重启RestartSec=10:每次重启间隔 10 秒StandardOutput=journal:日志由 systemd 统一收集
4.3 启用并测试服务
- 重载 systemd 配置:
sudo systemctl daemon-reexec sudo systemctl daemon-reload- 启动服务:
sudo systemctl start myapp- 查看状态:
sudo systemctl status myapp- 设置开机自启:
sudo systemctl enable myapp- 实时查看日志:
journalctl -u myapp -f你会发现输出非常清晰,包括时间戳、PID、错误信息等,调试起来极其方便。
5. 常见坑点与避坑指南
5.1 路径问题导致脚本找不到
很多人写的脚本里用了相对路径或~,但在 systemd 环境下工作目录不一定是家目录。
正确做法:
- 使用绝对路径
- 显式设置
WorkingDirectory
❌ 错误示例:
ExecStart=python3 ~/myapp/start.py正确写法:
WorkingDirectory=/home/ubuntu/myapp ExecStart=/usr/bin/python3 start.py5.2 权限不足无法访问设备或端口
如果程序要绑定 80 端口、访问 GPIO 或 USB 设备,可能会因权限不足失败。
解决方案:在[Service]中添加能力声明。
例如允许绑定低端口:
AmbientCapabilities=CAP_NET_BIND_SERVICE或访问串口设备:
ReadWritePaths=/dev/ttyUSB05.3 依赖服务未就绪就启动
比如数据库还没启动完,你的应用就开始连接,必然失败。
解决方案:合理使用After和Wants。
常见组合:
After=network.target postgresql.service Wants=postgresql.service5.4 日志看不见?学会用 journalctl
别再盲目查.log文件了!systemd 提供强大的日志工具:
# 查看服务最新日志 journalctl -u myapp -n 50 # 实时跟踪日志 journalctl -u myapp -f # 查看某次启动的日志 journalctl -u myapp --since today # 查看上次启动的日志 journalctl -u myapp -b -1这些命令比 grep 文本高效得多。
6. 总结:这才是你应该掌握的正确姿势
6.1 三种方式对比一览表
| 方式 | 是否推荐 | 适用场景 | 稳定性 | 可维护性 |
|---|---|---|---|---|
/etc/rc.local | ❌ 不推荐 | 快速验证、临时任务 | 中 | 低 |
cron @reboot | 谨慎使用 | 用户级简单脚本 | 中 | 低 |
| systemd service | 强烈推荐 | 所有生产级应用 | 高 | 高 |
6.2 最佳实践清单
- 优先使用 systemd service,这是现代 Linux 的标准方式
- 写清楚
Description和After,提升可读性和可靠性 - 设置
Restart=always,让程序具备自愈能力 - 用
journalctl查日志,告别分散的日志文件 - 测试时先手动
start,确认无误再enable - 避免在服务中调用 GUI 程序(除非是桌面服务)
6.3 给新手的建议
如果你刚接触 Linux 自启动,记住一句话:
“凡是能用 systemd service 实现的,就不要再碰
rc.local和cron @reboot。”
这不是炫技,而是为了系统的长期稳定。你现在花半小时学会写 service 文件,未来能省下无数个凌晨爬起来修故障的时间。
而且一旦掌握,你会发现它比那些“简单”的方法更直观、更可控、更专业。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。