初学者福音:图文并茂讲解开机自启全流程
你是不是也遇到过这样的问题:写好了Python脚本,想让它开机自动运行,结果重启后发现什么都没发生?试了网上各种方法,不是报错就是没反应,最后只能手动点开终端再执行一遍……别急,这篇文章就是为你准备的。我会用最直白的语言、最清晰的步骤、最贴近真实操作的截图逻辑(文字描述代替图片),带你从零搞定Linux系统下的开机自启——不讲虚的,不堆术语,每一步都可复制、可验证、可排查。
全文基于Ubuntu 20.04/22.04等现代systemd系统(兼容18.04及以上),完全避开老旧rc.local失效的坑,手把手带你重建一个稳定、可靠、易维护的开机启动机制。哪怕你刚接触Linux三天,只要会敲几行命令,就能顺利完成。
1. 为什么老办法不管用了?
在Ubuntu 14.04时代,大家习惯直接编辑/etc/rc.local文件,加一行脚本就完事。但自16.04起,Ubuntu全面转向systemd管理服务,rc.local默认被禁用,不是文件不存在,而是它根本不被执行。
你可能会看到这些典型现象:
- 编辑完
/etc/rc.local并加了chmod +x,重启后cat /var/log/syslog | grep rc.local却查不到任何记录 - 手动运行
sudo /etc/rc.local能成功,但开机时就是不触发 systemctl status rc-local显示inactive (dead)或failed
这不是你写错了,是系统底层机制变了。我们不再“修复”rc.local,而是给它配一个systemd服务容器,让它重新被系统识别和调度——这才是现代Linux的正确打开方式。
2. 核心思路:用systemd“托住”你的启动脚本
整个流程其实就三件事:
- 写一个systemd服务单元文件(告诉系统:“这个脚本我需要开机跑”)
- 写一个真正的启动脚本(比如
test.sh,里面调用你的Python程序) - 把脚本和权限、路径、执行环境都配对(避免“找不到python”“路径不对”“中文乱码”等新手高频雷)
下面所有操作,我都按真实终端顺序展开,命令可直接复制粘贴,关键位置我会说明“为什么这么写”。
2.1 创建systemd服务文件:rc-local.service
打开终端,执行:
sudo nano /etc/systemd/system/rc-local.service推荐用
nano而非vim,对新手更友好(按Ctrl+O保存,Ctrl+X退出)
把以下内容完整粘贴进去(注意:不要删减空行和缩进):
[Unit] Description=/etc/rc.local Compatibility ConditionPathExists=/etc/rc.local [Service] Type=forking ExecStart=/etc/rc.local start TimeoutSec=0 StandardOutput=tty RemainAfterExit=yes SysVStartPriority=99 [Install] WantedBy=multi-user.target重点解释这几句:
ConditionPathExists=/etc/rc.local:只有当/etc/rc.local文件存在时,这个服务才启动——避免误启Type=forking:因为rc.local本身会fork子进程,必须声明类型,否则systemd会误判为“启动失败”RemainAfterExit=yes:表示即使rc.local执行完了,服务状态仍保持“active”,方便后续依赖判断WantedBy=multi-user.target:这是Linux多用户模式的目标,相当于“系统准备好后就运行它”
2.2 创建并配置 /etc/rc.local 启动索引文件
现在创建真正的启动入口文件:
sudo nano /etc/rc.local粘贴以下内容(第一行必须是#!/bin/sh -e,结尾必须有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. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # 下面这行是测试用:重启后检查 /usr/local/test.log 是否生成 echo "开机自启服务已激活" > /usr/local/test.log # 这里是你真正要运行的脚本(推荐放在这里统一调度) # 注意:路径必须写绝对路径,不能用 ~ 或 $HOME sh /home/yourusername/test.sh exit 0重要提醒:
- 把上面的
yourusername换成你自己的用户名(如ubuntu、john),可用whoami命令确认 sh /home/.../test.sh是调用你自己的脚本,不是直接写Python命令——这样更安全、更易调试
2.3 给rc.local加执行权限
sudo chmod +x /etc/rc.local这一步不能省!Linux下任何脚本要被执行,必须有x权限。没有这行,systemd会静默跳过。
2.4 启用并启动服务
启用服务(让系统记住“下次开机要运行它”):
sudo systemctl enable rc-local.service立即启动一次(不用重启也能验证):
sudo systemctl start rc-local.service检查是否成功:
sudo systemctl status rc-local.service正常输出中应包含:
Active: active (exited)或active (running)Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled)- 最后一行类似
Started /etc/rc.local Compatibility
❌ 如果显示failed,别慌——直接看下一条。
3. 常见失败原因与排查指南(新手必读)
90%的开机自启失败,都出在这几个地方。我们逐个击破:
3.1 日志查看:第一手线索
无论状态显示如何,最准的判断方式是看日志:
sudo journalctl -u rc-local.service -n 50 --no-pager-n 50:显示最近50行--no-pager:不翻页,直接输出到终端
你会看到类似这样的关键信息:
Mar 15 10:22:33 ubuntu systemd[1]: Starting /etc/rc.local Compatibility... Mar 15 10:22:33 ubuntu rc.local[1234]: /etc/rc.local: 15: sh: /home/ubuntu/test.sh: Permission denied→ 看到Permission denied?说明test.sh没加执行权限,回退到2.5节补上。
再比如:
Mar 15 10:22:33 ubuntu rc.local[1234]: /etc/rc.local: 15: sh: python: not found→ 说明脚本里写的python命令系统找不到,可能是没装,或该用python3。
3.2 脚本路径与环境变量陷阱
你在终端里能运行python3 ce.py,不代表开机时也能。原因有两个:
- 路径是相对的:开机时当前目录是
/,不是你的家目录 - PATH环境变量不同:systemd服务默认PATH极简(通常只有
/usr/bin:/bin),不包含你.bashrc里加的路径
正确做法:
- 所有路径写绝对路径(
/home/xxx/test.sh,不是./test.sh) - Python脚本里,用
#!/usr/bin/env python3开头,或直接写python3 /home/xxx/ce.py - 不要依赖
source ~/.bashrc—— 它在systemd环境下根本不会加载
3.3 中文字符与编码问题(隐藏杀手)
参考博文里提到:“我犯得错误就是py文件存在中文,而无法运行”。这是真事。
Python 2默认ASCII,Python 3虽支持UTF-8,但systemd启动时LANG可能未设置,导致读取含中文的.py文件报错:
SyntaxError: Non-UTF-8 code starting with '\xe4' in file /home/xxx/ce.py解决方案(二选一):
- 推荐:Python脚本里第一行加编码声明:
# -*- coding: utf-8 -*- with open("sb.txt", "w") as f: f.write("SB") - 或者:彻底避免脚本中出现中文(变量名、注释、字符串都用英文)
4. 实战:部署你的第一个开机脚本(以Python为例)
我们来走一遍完整闭环:从写代码 → 写shell → 配置启动 → 验证结果。
4.1 写一个简单的Python程序
假设你想开机自动创建一个标记文件:
nano /home/$(whoami)/ce.py内容如下(注意:无中文,路径绝对):
#!/usr/bin/env python3 import os # 写入当前时间戳,证明是开机时运行的 with open("/tmp/autostart_marker.txt", "w") as f: f.write(f"Auto-started at {os.popen('date').read().strip()}\n") print(" Python脚本已执行")
os.popen('date')是为了演示动态内容,实际项目中建议用datetime.now()更规范
4.2 写调用它的shell脚本
nano /home/$(whoami)/test.sh内容如下(注意:指定python3,用绝对路径):
#!/bin/bash # 切换到脚本所在目录(可选,但推荐) cd /home/$(whoami) # 执行Python脚本 /usr/bin/python3 /home/$(whoami)/ce.py # 可选:记录日志便于排查 echo "$(date): ce.py executed" >> /tmp/autostart.log加执行权限:
chmod +x /home/$(whoami)/test.sh4.3 更新rc.local,指向你的脚本
回到/etc/rc.local,确保最后一段是:
sh /home/$(whoami)/test.sh exit 0(再次确认:$(whoami)已替换为真实用户名)
4.4 验证与重启测试
先手动触发一次:
sudo /etc/rc.local检查结果:
cat /tmp/autostart_marker.txt # 应输出类似:Auto-started at Mon Mar 15 10:30:22 CST 2024 cat /tmp/autostart.log # 应有时间戳记录一切正常后,重启验证终极效果:
sudo reboot等待系统起来后,直接运行:
cat /tmp/autostart_marker.txt如果看到带时间戳的内容,恭喜你——开机自启已稳稳落地。
5. 进阶建议:让启动更健壮、更可控
你已经掌握了核心流程,下面这几个小技巧,能让日常维护事半功倍:
5.1 用systemd原生方式替代rc.local(更推荐)
如果你只启动一个脚本,其实可以直接写专属service,无需绕路rc.local:
sudo nano /etc/systemd/system/myapp.service内容示例:
[Unit] Description=My Python App Auto Start After=network.target [Service] Type=simple User=yourusername WorkingDirectory=/home/yourusername ExecStart=/usr/bin/python3 /home/yourusername/ce.py Restart=always RestartSec=10 [Install] WantedBy=multi-user.target启用它:
sudo systemctl daemon-reload sudo systemctl enable myapp.service sudo systemctl start myapp.service优势:
- 每个应用独立管理,互不影响
Restart=always自动崩溃恢复User=指定运行用户,避免root权限滥用- 日志统一归集:
journalctl -u myapp.service
5.2 启动延迟与依赖控制
有些脚本依赖网络、数据库或GPU驱动,需等它们就绪再运行:
After=network.target:等网络通了再启动After=postgresql.service:等PostgreSQL启动后再运行Wants=network.target:声明强依赖
查看系统所有target:systemctl list-units --type=target
5.3 日志轮转与清理(防磁盘占满)
长期运行的脚本,日志容易暴涨。加一行到service文件里:
[Service] ... StandardOutput=append:/var/log/myapp.log StandardError=append:/var/log/myapp.log再配个logrotate(新建/etc/logrotate.d/myapp):
/var/log/myapp.log { daily missingok rotate 30 compress delaycompress notifempty }6. 总结:你已掌握的不仅是“开机自启”,更是Linux服务思维
回顾一下,你今天完成了:
- 理解了systemd与传统init的本质区别
- 搭建了可复用的rc-local兼容服务框架
- 成功部署并验证了Python脚本的开机自启
- 掌握了三大高频故障(权限、路径、编码)的定位与解决方法
- 学会了用journalctl看日志、用systemctl管服务、用logrotate护日志
这不是一个“一次性技巧”,而是一套可迁移的能力:以后部署Flask网站、启动TensorFlow训练、挂载NAS存储……底层逻辑一脉相承。
最后送你一句实操口诀:
“脚本写绝对路径,权限必须加x,日志先看journal,报错别猜靠证据。”
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。