核心内容摘要
白鹿哭着喊着不能再快乐了是什么意
手把手教你配置/etc/rc.local让脚本随系统启动你是不是也遇到过这样的问题写好了自动化脚本每次重启后却要手动运行或者部署了一个后台服务总得登录服务器再敲一遍命令其实Linux系统早就为你准备好了“开机自动执行”的能力——通过/etc/rc.local文件就能轻松实现。
但很多新手会发现在较新版本的 Ubuntu比如
1
04 及之后上直接编辑/etc/rc.local并不能生效。
这不是你的脚本有问题而是系统启动机制变了。
别担心这不是功能被删掉了只是换了一种更规范、更可控的方式启用它。
本文不讲抽象原理不堆术语就用最直白的语言、最完整的步骤、最容易复现的操作带你从零开始配置好rc.local让它真正“随系统一起醒来”。
无论你是刚接触 Linux 的运维新人还是需要快速落地一个自启任务的开发者只要照着做15 分钟内就能看到/usr/local/test.log里那行成功的提示。
全文基于真实环境验证Ubuntu
2
04 LTS所有命令可直接复制粘贴每一步都说明“为什么这么做”和“不做会怎样”还会提前告诉你几个新手踩过的坑——比如中文路径报错、权限遗漏、服务状态误判等。
现在我们就开始吧。
为什么 /etc/rc.local 默认不工作了在 Ubuntu
1
04 之前系统使用传统的 SysV init 启动方式/etc/rc.local是一个被默认加载的“万能启动入口”。
但从 Ubuntu
1
04 开始系统全面转向 systemd而 systemd 默认不再主动读取或执行 rc.local。
它不是被删除了而是被“雪藏”了——就像一个老工具被收进抽屉需要你亲手拿出来、擦干净、装上手柄才能继续用。
所以你编辑了/etc/rc.local却没反应并不是脚本写错了而是 systemd 根本没去调用它。
解决办法很简单告诉 systemd“请把这个旧文件当作一个正式服务来管理”。
这个过程只需要两步核心操作创建一个 systemd 服务单元文件rc-local.service定义如何运行 rc.local确保/etc/rc.local本身存在、可执行、且内容规范。
下面我们就一步步完成这两件事。
创建并配置 rc-local.service 服务单元systemd 通过.service文件来定义服务行为。
我们要创建一个专门用于兼容rc.local的服务让它在多用户模式下自动启动。
1 创建服务文件打开终端执行以下命令创建服务定义文件sudo vim /etc/systemd/system/rc-local.service小提示如果你不熟悉 vim可以用sudo nano /etc/systemd/system/rc-local.service替代nano 更易上手。
将以下完整内容粘贴进去注意逐字复制包括空行和缩进[Unit] Description/etc/rc.local Compatibility ConditionPathExists/etc/rc.local [Service] Typeforking ExecStart/etc/rc.local start TimeoutSec0 StandardOutputtty RemainAfterExityes SysVStartPriority99 [Install] WantedBymulti-user.target
2 关键字段说明不用死记看懂就行ConditionPathExists/etc/rc.local表示只有当/etc/rc.local文件真实存在时这个服务才允许启动。
这是安全机制避免服务找不到目标文件而报错。
Typeforking告诉 systemd这个脚本会“派生子进程”即自己启动后就退出把任务交给后台进程。
这是传统 rc.local 的典型行为。
ExecStart/etc/rc.local start明确指定执行命令。
注意这里带了start参数是因为老式 rc.local 脚本通常支持start/stop等参数。
RemainAfterExityes最关键的一行。
它让 systemd 认为即使/etc/rc.local执行完了、进程退出了这个服务“依然处于运行状态”。
否则 systemd 会立刻标记服务为“已停止”后续依赖它的服务可能出错。
WantedBymulti-user.target表示该服务应在标准的多用户命令行模式下启动也就是你日常使用的非图形界面状态。
这一步完成后systemd 就知道了“有这么一个服务它负责运行 rc.local”但还缺一个真正的rc.local文件。
创建并初始化 /etc/rc.local 文件现在我们来创建那个被 systemd 监控的“启动索引文件”。
1 创建空白文件并添加基础模板执行命令sudo vim /etc/rc.local粘贴以下标准模板内容#!/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. echo 看到这行字说明添加自启动脚本成功。
/usr/local/test.log exit
0
2 为什么必须包含这些内容#!/bin/sh -e声明这是 shell 脚本且-e表示“任一命令失败则立即退出”防止错误被忽略。
exit 0绝对不能省略。
systemd 依赖这个返回值判断脚本是否成功执行。
如果忘了写服务状态会显示failed即使日志看起来正常。
echo ... /usr/local/test.log这是我们的“心跳检测”。
它会在/usr/local/test.log中写入一行文字方便你重启后快速验证是否真的生效。
3 设置可执行权限Linux 不会执行没有“执行权限”的文件。
必须显式赋予sudo chmod x /etc/rc.local正确做法chmod x常见错误只改了内容忘了加权限结果服务启动失败。
启用并启动 rc-local 服务现在systemd 已经认识这个服务rc.local文件也准备就绪。
接下来就是“通电开机”的最后一步。
1 启用服务开机自启让 systemd 在每次启动时自动加载这个服务sudo systemctl enable rc-local这条命令的本质是创建一个软链接/etc/systemd/system/multi-user.target.wants/rc-local.service → /etc/systemd/system/rc-local.service这样系统一进入multi-user.target就会顺带启动它。
2 立即启动服务无需重启你可以马上测试效果不用等重启sudo systemctl start rc-local.service
3 检查服务状态运行以下命令查看是否成功sudo systemctl status rc-local.service成功状态特征第一行显示active (exited)或active (running)取决于RemainAfterExit设置最后几行有Started /etc/rc.local Compatibility没有红色的failed或error字样常见失败原因/etc/rc.local没有x权限 → 运行sudo chmod x /etc/rc.local文件里漏了exit 0→ 用sudo vim /etc/rc.local补上脚本里有语法错误比如中文引号、未闭合括号→ 用sudo bash -n /etc/rc.local检查语法确认状态正常后再检查日志文件cat /usr/local/test.log如果输出看到这行字说明添加自启动脚本成功。
恭喜你的rc.local已经活过来了。
把真正想运行的脚本“挂”进 rc.local现在rc.local是个空壳它只负责执行自己内部的几行命令。
但我们的目标是让它成为所有自启任务的统一入口。
就像一个总开关按下它就自动打开你家所有的灯。
1 创建你自己的业务脚本以 Python 为例假设你想开机自动运行一个 Python 程序ce.py它会在当前目录生成一个sb.txt文件。
先创建存放脚本的目录推荐放在/opt或/usr/local/bin避免权限问题sudo mkdir -p /opt/mystartup cd /opt/mystartup创建 Python 脚本sudo vim ce.py内容如下注意不要用中文路径不要在脚本里写中文注释或字符串除非你明确设置了 UTF-8 环境with open(/opt/mystartup/sb.txt, w) as f: f.write(SB)再创建一个 shell 包装器test.sh用来调用 Pythonsudo vim test.sh内容#!/bin/bash cd /opt/mystartup python3 ce.py exit 0重要提醒使用python3而不是python避免因系统默认 Python 版本不一致导致失败cd切换到脚本所在目录确保相对路径正确同样必须以exit 0结尾。
赋予执行权限sudo chmod x ce.py test.sh
2 修改 rc.local调用你的脚本编辑/etc/rc.localsudo vim /etc/rc.local把原来的echo行替换成调用你脚本的命令放在exit 0之前#!/bin/sh -e # ...前面的注释保持不变 # 在这里添加你的启动命令 /opt/mystartup/test.sh exit 0保存退出。
再次确认权限sudo chmod x /etc/rc.local
3 重新加载并测试因为修改了服务定义文件需要通知 systemd 重载配置sudo systemctl daemon-reload然后重启服务sudo systemctl restart rc-local.service检查是否成功sudo systemctl status rc-local.service cat /opt/mystartup/sb.txt如果sb.txt里出现了SB说明你的 Python 脚本已成功随系统启动。
排查
常见问题的实用技巧即使严格按照步骤操作也可能遇到意外。
以下是几个高频问题和对应解法帮你少走弯路。
1 服务状态显示 active but failed运行sudo systemctl status rc-local.service后看到active (exited)但紧接着又出现failed大概率是rc.local内部某条命令执行出错但脚本仍返回了 0。
解决方法临时关闭-e选项让错误暴露出来。
编辑/etc/rc.local把第一行改成#!/bin/sh然后重启服务并查看详细日志sudo systemctl restart rc-local.service sudo journalctl -u rc-local.service -n 20 --no-pager日志里会清晰显示哪一行报错比如command not found、Permission denied。
2 脚本执行了但生成的文件不在预期位置这是因为rc.local是在 root 用户上下文中运行的它的“当前工作目录”是/root而不是你编辑脚本时所在的目录。
解决方法所有路径务必写绝对路径如/opt/mystartup/test.sh而不是./test.sh在 shell 脚本开头强制cd到目标目录如cd /opt/mystartupPython 脚本中写文件时也用绝对路径如/opt/mystartup/sb.txt。
3 中文字符导致脚本崩溃如果你的 Python 脚本里写了中文比如f.write(你好)而系统 locale 没设置好就会报UnicodeEncodeError。
解决方法二选一方案 A推荐避免在开机脚本中使用中文用英文或 ASCII 字符替代方案 B在test.sh中显式设置语言环境#!/bin/bash export LANGen_US.UTF-8 export LC_ALLen_US.UTF-8 cd /opt/mystartup python3 ce.py exit
07.
总结你已经掌握了一个可靠的系统级自动化入口到这里你已经完成了整个流程理解了 systemd 下rc.local失效的原因亲手创建了服务单元初始化了启动脚本挂载了业务逻辑并掌握了排错的核心方法。
这不是一个“一次性的技巧”而是一个可复用的工程能力——今后任何需要开机自启的任务无论是备份脚本、监控程序、数据库初始化还是 Web 服务预热你都可以用同样的模式接入。
回顾一下关键动作rc-local.service是 systemd 的“翻译官”把老式脚本变成现代服务/etc/rc.local是你的“总控台”所有启动命令都从这里出发chmod x和exit 0是两个看似微小、实则致命的细节绝对路径、显式cd、python3替代python是避免环境差异的黄金习惯。
最后提醒一句虽然rc.local很方便但对于长期运行的服务比如 Web 服务器更推荐为它单独编写 systemd service 文件。
rc.local最适合做“一次性初始化”或“轻量级调度入口”。
它的价值不在于替代专业方案而在于给你一个简单、稳定、随时可用的起点。