附完整命令:一步步搭建属于你的开机启动服务
你是否遇到过这样的问题:写好了自动化脚本,每次重启后却要手动运行?或者部署了一个后台服务,希望它像系统服务一样随机器启动自动拉起?别担心,这不是运维工程师的专属技能——只要掌握 systemd 的基本用法,你也能轻松为自己的脚本配置可靠的开机启动。
本文不讲抽象原理,不堆砌术语,只聚焦一件事:手把手带你从零配置一个真正可用的开机启动服务。无论你是刚接触 Linux 的开发者,还是想把 Python 小程序、Shell 工具或自定义任务变成“开机即用”的实用派用户,这篇教程都能让你在 10 分钟内完成部署,并且每一步都附带可直接复制粘贴的完整命令。
我们以 Ubuntu 22.04(及主流 Debian/Ubuntu 系统)为基准环境,所有操作均经过实测验证。文中提到的测试开机启动脚本镜像,正是基于这套流程构建的轻量级启动模板,开箱即用,但更重要的是——你知道它怎么来的。
1. 为什么不能直接改 rc.local?
在较老的 Ubuntu 版本(如 14.04)中,编辑/etc/rc.local是最常用的开机启动方式。但自 Ubuntu 18.04 起,systemd 成为默认初始化系统,rc.local不再默认启用,甚至不会被自动加载。简单说:它还在,但已“失联”。
如果你尝试直接往/etc/rc.local里加命令,大概率会发现:
- 重启后脚本没执行
cat /usr/local/test.log显示文件不存在或为空systemctl status rc-local提示Unit rc-local.service not found
这不是你的脚本有问题,而是系统根本没把它当回事。解决办法不是绕开 systemd,而是让 rc.local 重新成为 systemd 认可的服务——这正是本文要做的第一件事。
2. 创建 rc-local.service:给老朋友发一张新通行证
systemd 通过.service文件管理服务。我们要做的,就是为rc.local创建一个“身份认证文件”,告诉系统:“这个脚本值得被信任,应该在多用户模式下自动启动”。
2.1 创建服务定义文件
打开终端,执行以下命令创建服务单元文件:
sudo vim /etc/systemd/system/rc-local.service将以下内容完整复制进去(注意:不要漏掉空行和缩进):
[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存在时才启用该服务,避免误启Type=forking告诉 systemd 这是一个传统 SysV 风格的后台进程(适合 shell 脚本)RemainAfterExit=yes表示即使脚本执行完毕退出,systemd 仍认为服务处于“活跃”状态——这对启动类脚本至关重要WantedBy=multi-user.target指定服务应在标准多用户模式(即图形界面或纯命令行登录前)启动
2.2 启用并验证服务注册
保存退出后,刷新 systemd 配置,使新服务生效:
sudo systemctl daemon-reload此时服务已注册,但尚未启用。启用它,让系统记住“下次开机要运行这个”:
sudo systemctl enable rc-local.service验证是否注册成功:
systemctl is-enabled rc-local.service如果输出enabled,说明服务已成功加入开机启动列表。
3. 编写并配置 /etc/rc.local:你的启动总控台
rc.local在这里不再只是一个遗留文件,而是你整个开机启动逻辑的“总控台”。你可以直接在里面写命令,也可以把它当作一个跳转器,调用其他更清晰命名的脚本(推荐后者,便于维护)。
3.1 创建 rc.local 文件
sudo vim /etc/rc.local粘贴以下基础模板(注意首行#!/bin/sh -e必须存在,且不可修改):
#!/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必须注意的三个细节:
- 第一行
#!/bin/sh -e是硬性要求,-e表示任意命令失败立即退出,避免后续命令误执行 - 所有实际命令必须写在
exit 0之前 - 最后一行
exit 0不可省略,否则 systemd 会认为脚本执行失败
3.2 赋予执行权限
Linux 对脚本执行权限极为严格。没有x权限,systemd 根本不会尝试运行它:
sudo chmod +x /etc/rc.local验证权限是否正确:
ls -l /etc/rc.local应看到类似-rwxr-xr-x的输出,其中x字符表示可执行。
4. 启动服务并实时验证效果
现在服务已注册、脚本已就位、权限已赋予。是时候让它真正跑起来,并确认一切按预期工作。
4.1 立即启动服务(无需重启)
sudo systemctl start rc-local.service4.2 检查服务状态
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或inactive,请立即执行:
sudo journalctl -u rc-local.service -n 20 --no-pager这会显示最近 20 行服务日志,绝大多数问题(如路径错误、权限不足、语法错误)都能在这里快速定位。
4.3 验证脚本执行结果
检查我们写入的日志文件是否存在且内容正确:
cat /usr/local/test.log如果输出看到这行字,说明添加自启动脚本成功。,恭喜,你的开机启动服务已打通第一关!
5. 实战:用 rc.local 启动你的 Python 脚本
上面只是“Hello World”式验证。真正的价值在于:让任何你写的程序,在开机时自动运行。下面以一个典型场景为例——启动一个位于/home/yourname/下的 Python 小程序ce.py。
5.1 创建你的业务脚本
假设用户名为ubuntu(请替换成你自己的用户名),先创建存放目录和脚本:
mkdir -p /home/ubuntu/myapp cd /home/ubuntu/myapp创建 Python 测试脚本ce.py:
sudo vim ce.py内容如下(写入一个标记文件,便于验证):
#!/usr/bin/env python3 with open("/home/ubuntu/myapp/sb.txt", "w") as f: f.write("SB")注意:Python 脚本首行#!/usr/bin/env python3是关键,确保能被 shell 正确调用。
赋予执行权限:
sudo chmod +x ce.py5.2 创建封装 Shell 脚本(推荐做法)
直接在rc.local里写长命令易出错、难维护。更稳妥的方式是:用一个独立的.sh文件封装所有启动逻辑。
创建start_myapp.sh:
sudo vim /home/ubuntu/myapp/start_myapp.sh内容如下:
#!/bin/bash cd /home/ubuntu/myapp /usr/bin/python3 ce.py exit 0关键说明:
- 使用绝对路径
/usr/bin/python3而非python,避免因 PATH 环境变量在 systemd 上下文中缺失导致失败 cd切换到脚本所在目录,确保相对路径(如sb.txt)能正确解析
赋予执行权限:
sudo chmod +x /home/ubuntu/myapp/start_myapp.sh5.3 修改 rc.local,调用你的脚本
编辑/etc/rc.local,将原来的echo行替换为调用命令:
sudo vim /etc/rc.local修改后的内容应为:
#!/bin/sh -e # # rc.local # # 启动我的Python应用 /home/ubuntu/myapp/start_myapp.sh exit 0再次确认权限无误:
sudo chmod +x /etc/rc.local5.4 重新启动服务并验证
sudo systemctl restart rc-local.service sudo systemctl status rc-local.service检查输出文件是否生成:
cat /home/ubuntu/myapp/sb.txt如果看到SB,说明你的 Python 脚本已在 systemd 环境下成功启动。
6. 常见问题与避坑指南
即使严格按照步骤操作,也可能会遇到一些“看似奇怪”的失败。以下是高频问题及对应解法,帮你节省调试时间。
6.1 “No such file or directory” 错误
现象:systemctl status显示ExecStart=/etc/rc.local start failed: No such file or directory
原因:/etc/rc.local文件不存在,或路径拼写错误(如多了一个空格)
解法:
ls -l /etc/rc.local # 确认文件存在且路径准确 sudo systemctl daemon-reload # 修改文件后务必重载6.2 Python 脚本报编码错误(含中文)
现象:日志中出现SyntaxError: Non-UTF-8 code starting with '\xe4'
原因:.py文件保存为 GBK 或其他非 UTF-8 编码,而 Linux 默认使用 UTF-8
解法:
- 用
vim打开文件,输入:set fileencoding=utf-8后:wq保存 - 或用 VS Code 等编辑器另存为 UTF-8(无 BOM)
6.3 脚本执行了,但文件没生成/内容为空
原因:systemd 启动时的工作目录不是你预期的路径,或用户权限不足
解法:
- 在脚本开头显式
cd到目标目录(如上文start_myapp.sh所示) - 使用绝对路径写入文件(如
/home/ubuntu/myapp/sb.txt) - 检查目标目录权限:
ls -ld /home/ubuntu/myapp,确保root或对应用户有写权限
6.4 服务状态显示 “exited”,但不确定是否成功
解法:查看详细日志
sudo journalctl -u rc-local.service --since "1 hour ago" --no-pager重点关注stderr输出,它会告诉你 Python 报了什么错、哪个命令找不到。
7. 总结:你已掌握一套可复用的启动服务框架
回顾整个过程,你实际上完成了一套标准化、可迁移、易维护的开机启动方案:
- 为
rc.local注册了 systemd 服务,解决了新版 Ubuntu 的兼容性问题 - 掌握了服务启用、启动、状态检查、日志排查的完整闭环
- 学会了用独立 Shell 脚本封装业务逻辑,隔离环境差异
- 实现了 Python 程序的可靠开机自启,并规避了常见编码与路径陷阱
这套方法不仅适用于测试开机启动脚本镜像,也完全适配你本地的开发机、树莓派、云服务器等任何运行 systemd 的 Linux 环境。未来,无论是部署 Flask Web 服务、定时数据同步脚本,还是 AI 模型推理守护进程,你都可以基于此框架快速扩展。
最后提醒一句:永远先用systemctl start测试,再依赖enable开机启动。一次成功的即时启动,是开机自启最可靠的保障。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。