Ubuntu如何创建自定义systemd服务实现开机自启动?

来源:前端技术作者:李修然头衔:网络博主
导读:本期聚焦于李修然创作的《Ubuntu如何创建自定义systemd服务实现开机自启动?》,敬请观看详情。想让Shell脚本或自研程序在Ubuntu上开机自动运行、崩溃后自动拉起吗?本文完整讲解systemd服务的创建方法,从编写unit配置文件、存放目录规范,到使用systemctl命令启用、启动、查看日志的全流程操作,并附上带环境变量、工作目录、自动重启等常用配置的完整示例。同时介绍服务状态排查、journalctl日志分析以及常见报错的原因和解决办法,帮助你快速搭建稳定可靠的Linux后台服务。

在Ubuntu服务器上部署自己的程序时,很多人习惯用nohup或者crontab的@reboot来让程序在后台运行。这些方式虽然简单,但缺点也很明显:程序挂掉后不会自动重启,开机启动的时机不可控,日志散落各处难以查询。systemd作为Ubuntu默认的初始化系统,提供了完善的守护进程管理能力,只需编写一个配置文件,就能让程序获得自动启动、故障重启、日志收集等企业级特性。本文将从零开始,手把手演示如何在Ubuntu上创建一个自定义的systemd服务。

Ubuntu如何创建自定义systemd服务实现开机自启动?

一、编写systemd服务配置文件

systemd管理的每一个服务都对应一个unit文件,自定义服务一般存放在/etc/systemd/system/目录下,文件名以.service结尾。系统自带的服务则放在/lib/systemd/system/中,两个目录不要混用,自定义服务统一放前者便于管理。

下面以运行一个Python脚本为例,创建文件/etc/systemd/system/myapp.service,写入如下内容:

[Unit]
Description=My Custom Application Service
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/main.py
Restart=on-failure
RestartSec=5
Environment=APP_ENV=production
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

配置分为三个段。[Unit]段描述服务的基本信息,Description是服务的说明文字,After=network.target表示在网络就绪之后再启动,如果程序依赖数据库或网络,这一行必不可少,否则开机时可能因为网络未就绪而启动失败。

[Service]段是核心。Type=simple表示主进程就是前台运行的那个进程,这是最常用的类型;如果程序会自动fork到后台,则需要改用Type=forking。ExecStart指定启动命令,注意必须写绝对路径,systemd不会加载用户的PATH环境变量,直接写python3会报找不到命令的错误。Restart=on-failure让程序异常退出后5秒自动重启,Environment用来注入环境变量,避免把敏感信息硬编码到代码里。

[Install]段的WantedBy=multi-user.target定义了服务的安装位置,multi-user.target对应常见的多用户命令行运行级别,绝大多数服务都用这个值。如果希望服务随图形界面启动,可以改成graphical.target,但一般没有必要。

二、启用服务并设置开机自启动

配置文件写好后,需要先让systemd重新加载所有unit文件,然后再启动服务并设置为开机自启。完整的命令流程如下:

# 重新加载systemd配置,每次修改service文件后都要执行
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start myapp.service

# 设置开机自启动(建立软链接到multi-user.target.wants目录)
sudo systemctl enable myapp.service

# 查看服务当前状态
sudo systemctl status myapp.service

这里需要特别说明start和enable的区别,很多初学者容易混淆。start是立即启动服务,只影响当前这一次;enable是设置开机自动启动,它并不会启动服务,只是在/etc/systemd/system/multi-user.target.wants/目录下创建一个指向unit文件的软链接。想让服务立刻运行并且重启后也自动启动,两条命令都要执行。也可以用sudo systemctl enable --now myapp.service一步到位。

对应的关闭操作也有两组:stop停止服务、disable取消开机自启。如果修改了service文件内容,除了daemon-reload之外,还需要restart才能让新配置生效。日常排查时可以用systemctl is-active myapp快速判断服务是否在运行,返回active说明正常,返回failed则需要进一步看日志。

三、日志查看与常见问题排查

systemd统一接管了服务的标准输出和标准错误,查看日志不再需要翻找nohup.out文件,直接使用journalctl命令即可:

# 查看服务的全部日志
sudo journalctl -u myapp.service

# 实时追踪日志输出,类似tail -f的效果
sudo journalctl -u myapp.service -f

# 只看最近100行日志
sudo journalctl -u myapp.service -n 100

# 查看今天的日志
sudo journalctl -u myapp.service --since today

服务启动失败时,status命令的输出通常会给出关键提示,比如exit-code和status后面的数字对应程序退出码。常见的几类错误包括:第一,ExecStart路径写错或者使用了相对路径,报错一般显示no such file or directory;第二,User指定的用户对WorkingDirectory没有访问权限,导致启动即退出,可以检查目录属主或者临时把User改成root测试;第三,Python脚本缺少虚拟环境依赖,因为systemd不会自动激活venv,解决办法是在ExecStart中直接写虚拟环境中的解释器绝对路径,例如/opt/myapp/venv/bin/python3。

还有一种情况是服务状态显示active但程序实际没有工作,这多半是Type配置和程序行为不匹配造成的。比如程序启动后立即fork子进程然后父进程退出,Type=simple下systemd会跟踪错误的进程。此时可以改用Type=forking并配合PIDFile指定pid文件,或者干脆修改程序让它保持前台运行,后者是更推荐的做法,systemd体系下前台化才是主流设计。

另外提醒一点,如果服务以普通用户身份运行,日志默认持久化在/var/log/journal/,Ubuntu默认已经开启。磁盘空间紧张时可以通过sudo journalctl --vacuum-size=100M清理旧日志,控制日志占用的空间。

四、进阶配置技巧

掌握了基本用法后,还可以通过一些进阶配置让服务更加健壮。比如限制服务占用的资源,防止程序失控拖垮整机:

[Service]
# 限制内存使用上限为512M,超出后被系统终止
MemoryMax=512M
# 限制CPU使用率为单核的50%
CPUQuota=50%
# 限制能打开的文件描述符数量
LimitNOFILE=65535
# 无论何种退出原因都重启,包括正常退出
Restart=always
# 禁止服务获得额外权限
NoNewPrivileges=true
# 使用私有临时目录,避免与其他服务互相干扰
PrivateTmp=true

服务之间还可以建立依赖关系。假设myapp依赖Redis,可以在Unit段写Requires=redis-server.service和After=redis-server.service,这样启动myapp时systemd会先把Redis拉起来。反向的场景则可以用BindsTo,当Redis停止时myapp也跟着停止,避免程序在依赖缺失的状态下空转。

对于需要执行一次性任务的场景,比如开机初始化脚本,可以定义Type=oneshot并加上RemainAfterExit=yes,这样脚本执行完服务状态仍显示为active,便于后续判断初始化是否已完成。如果是定时任务,则应该使用timer类型的unit配合OnCalendar字段,比crontab更灵活且日志更完整,这里不再展开,有兴趣的话可以参考systemd.timer的官方文档。

总结

创建自定义systemd服务的关键步骤可以归纳为四步:在/etc/systemd/system/下编写service文件、执行daemon-reload、start启动服务、enable设置开机自启。核心配置集中在Service段,注意命令写绝对路径、合理选择Type、配置Restart实现故障自愈。遇到问题时优先用status和journalctl定位原因,绝大多数启动失败都能从这两处输出中找到答案。把后台程序交给systemd管理后,服务器的稳定性和可维护性会有明显提升,这也是生产环境的标准做法。

systemd服务Ubuntu开机自启动修改时间:2026-09-16 13:44:38

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0916/57976.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。