systemd 服务配置文件,xxx.service 编辑指南,自定义我们自己的服务。

一、systemd 服务配置文件(.service)完全指南

1. 配置文件存放目录(按优先级从高到低)

优先级 路径 说明
/etc/systemd/system/ 管理员自定义或覆盖。所有手动编写的服务应放此处。
/run/systemd/system/ 运行时动态生成(重启后丢失)。通常由其他工具或脚本创建。
/usr/lib/systemd/system/ 软件包安装时自带的默认配置(如 docker、nginx)。不要直接修改 ,应在 /etc 下覆盖。

💡 覆盖规则/etc/systemd/system/ 下的同名 .service完全替代低优先级目录中的同名文件,而非合并。


2. 配置文件结构(三个主要区块)

一个完整的 .service 文件通常包含以下三个区块:

[Unit] -- 通用信息与依赖

指令 说明
Description 服务的简短描述。
After 定义启动顺序(本服务这些服务之后启动)。不强制依赖。
Before 本服务在这些服务之前启动。
Requires 强依赖 ------ 依赖服务启动失败,本服务也不会启动。
Wants 弱依赖 ------ 依赖服务失败,本服务仍尝试启动。
Conflicts 冲突 ------ 与本服务不能同时运行的服务。

[Service] -- 核心运行配置

指令 说明
Type 启动类型: • simple(默认)-- 立即认为启动完成 • forking -- 父进程退出,子进程成为守护进程 • oneshot -- 执行一次即退出(常配 RemainAfterExit=yes) • notify -- 就绪后会通过 sd_notify() 通知 systemd • dbus -- 获得特定 D-Bus 名称后才算就绪
ExecStart 启动命令(绝对路径)。可以写多个,按顺序执行。
ExecStartPre/Post 启动前/后执行的命令。
ExecStop 停止命令(不写则 systemd 会发送 SIGTERM)。
ExecReload 重载配置的命令。
Restart 何时重启:no, on-success, on-failure, always, on-abnormal
RestartSec 自动重启前等待的秒数。
User / Group 运行服务的用户和组。
WorkingDirectory 工作目录。
Environment 设置环境变量,如 Environment="PATH=/usr/bin"
EnvironmentFile 从文件加载环境变量(适合敏感信息)。
StandardOutput 标准输出去向:journal, file:/path, null 等。
StandardError 标准错误去向,同上。

[Install] -- 安装与开机自启

指令 说明
WantedBy 服务被哪个 target 需要。常用 multi-user.target(多用户命令行模式)。
RequiredBy 强依赖的 target(较少用)。
Alias 服务的别名。
Also enable 本服务时,同时 enable 的其他服务。

3. 核心操作流程与常用命令

3.1 编写/修改服务文件后

bash 复制代码
# 1. 重新加载所有配置文件(必须执行)
sudo systemctl daemon-reload

# 2. 启动服务
sudo systemctl start myapp.service

# 3. 设置开机自启
sudo systemctl enable myapp.service

# 4. 查看状态(含最近日志)
sudo systemctl status myapp.service

# 5. 停止服务
sudo systemctl stop myapp.service

# 6. 重启服务(修改 ExecStart 等后需重启生效)
sudo systemctl restart myapp.service

# 7. 禁用开机自启
sudo systemctl disable myapp.service

3.2 查看服务日志(journalctl)

bash 复制代码
# 实时跟踪日志
sudo journalctl -u myapp.service -f

# 显示最近 50 行
sudo journalctl -u myapp.service -n 50

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

# 从最新日志开始显示(跳到末尾)
sudo journalctl -u myapp.service -e

# 按时间范围
sudo journalctl -u myapp.service --since "2025-01-01 10:00:00" --until "2025-01-01 12:00:00"

4. 典型示例

示例 1:简单 Python 服务(常驻)

ini 复制代码
[Unit]
Description=My Python Web App
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/main.py
Restart=on-failure
RestartSec=5
Environment="LOG_LEVEL=info"
EnvironmentFile=/etc/myapp/env.conf

[Install]
WantedBy=multi-user.target

示例 2:一次性任务(oneshot)

ini 复制代码
[Unit]
Description=Backup Script

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/backup.sh
User=backup

[Install]
WantedBy=multi-user.target

5. 易错点与进阶提醒

易错点 说明
绝对路径要求 ExecStart 等指令中的所有命令 必须使用绝对路径(如 /usr/bin/python3),不能用 python3~/script.sh
管道与重定向失效 不能在 ExecStart 中直接写 `
环境变量隔离 systemd 服务不会继承用户 shell 的环境变量(如 .bashrc)。必须通过 Environment=EnvironmentFile= 显式提供。
引号与空格处理 若路径包含空格,需用反斜杠转义:/path/with\ space/app。 不要试图用双引号包裹整个命令(会失败)。
Type 选择不当导致启动状态错误 守护进程化程序(如 fork())必须用 Type=forking,否则 systemd 会认为启动失败。 使用 Type=notify 的程序需要调用 sd_notify(),否则 systemd 会一直等待。
修改服务文件后未重启服务 daemon-reload 只让 systemd 重新读取配置,不会自动重启 已运行的服务。必须手动 restart 才能使新 ExecStart 等生效。
日志查看权限 普通用户查看服务日志可能需要 sudo,除非将用户加入 systemd-journal 组。
Restart=always 的危险性 如果服务因配置错误反复崩溃,Restart=always 会导致疯狂重启。可设置 StartLimitBurst=5StartLimitIntervalSec=10s 限制重启次数。

6. 调试小技巧

  • 模拟启动检查systemd-analyze verify /etc/systemd/system/myapp.service 可提前发现语法错误。
  • 查看服务环境变量systemctl show myapp.service --property=Environment 或运行 systemctl exec myapp env(需服务支持)。
  • 临时覆盖配置 :使用 systemctl edit myapp.service 会创建 /etc/systemd/system/myapp.service.d/override.conf,无需手动创建目录。

这份指南既保留了原格式的清晰性,又补充了常见遗漏点,适合系统管理员和开发者快速上手。

二、相关案例

1. tomcat 压缩包安装配置

现在我把tomcat相关的软件包解压到了/usr/local/tomcat目录中他的启动脚本路径在/usr/local/tomcat/bin/startup.sh

  1. 编写systemd文件,从而实现systemctl命令控制,比如
  2. systemctl stop tomcat
  3. systemctl start tomcat
  4. systemctl restart tomcat
  5. systemctl enable tomcat
  6. systemctl status tomcat
    从而可以用上述命令对这个安装包产生的服务进行控制。
提问:
  1. 还需要指定PIDFile以便systemd跟踪主进程。
    • PIDFile 文件的作用是什么?
    • systemd跟踪主进程,这里的主进程指的的是tomcat的服务主进程吗?
    • 跟踪主进程的原理是什么?
  2. 下面这些环境变量的变量名是固定的吗?必须这样写吗?
    Environment="JAVA_HOME=/usr/lib/jvm/default-java"
    Environment="CATALINA_HOME=/usr/local/tomcat"
    Environment="CATALINA_BASE=/usr/local/tomcat"
  3. 这一行为什么要说"让 Tomcat 将 PID 写入指定文件"
    Environment="CATALINA_PID=/usr/local/tomcat/tomcat.pid"
answer
  1. 还需要指定PIDFile以便systemd跟踪主进程。
    • PIDFile 的作用是存储服务主进程的pid,为systemd管理服务的启动和停止提供条件。
    • systemd跟踪主进程,这里的主进程指的就是tomcat的服务主进程。
    • systemd通过PIDFile中存储的服务主进程pid从而对服务进行管理。
  2. 下面这些环境变量的变量名是固定的吗?必须这样写吗?
    • 对的环境变量的变量名字是固定的,必须要这样写。
    • 这些环境变量的名字根据不同的服务有不同的名字,具体参考软件包自带的说明文档。
      其中:
      JAVA_HOME 变量是存储JDK环境的文件路径。
      CATALINA_HOME存储的是tomcat的工作目录。
      CATALINA_BASE 一般情况下与CATALINA_HOME的内容相同。
  3. CATALINA_PID环境变量存储的是包含服务主进程pid文件路径。

配置文件解析

配置模板

config 复制代码
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target
# 可选:如果 Tomcat 依赖某些文件系统挂载,可以加上 After=remote-fs.target nss-lookup.target

[Service]
Type=forking
# Tomcat 的启动脚本和停止脚本
ExecStart=/usr/local/tomcat/bin/startup.sh
ExecStop=/usr/local/tomcat/bin/shutdown.sh
# 重启策略:非正常退出时尝试重启
Restart=on-failure
RestartSec=10

# 指定 PID 文件路径(需要 Tomcat 能够写入该文件)
PIDFile=/usr/local/tomcat/tomcat.pid

# 运行服务的用户和组(建议创建专用的 tomcat 用户,避免使用 root)
User=tomcat
Group=tomcat

# 工作目录
WorkingDirectory=/usr/local/tomcat

# 设置环境变量(根据你的实际 Java 环境调整)
Environment="JAVA_HOME=/usr/lib/jvm/default-java"
Environment="CATALINA_HOME=/usr/local/tomcat"
Environment="CATALINA_BASE=/usr/local/tomcat"
# 让 Tomcat 将 PID 写入指定文件
Environment="CATALINA_PID=/usr/local/tomcat/tomcat.pid"

# 可选:限制资源使用
# LimitNOFILE=65536

# 日志输出(如果不希望日志混入 systemd journal,可以注释掉)
# StandardOutput=journal
# StandardError=journal

[Install]
WantedBy=multi-user.target
1. 重启策略
shell 复制代码
# 重启策略:非正常退出时尝试重启
Restart=on-failure
RestartSec=10

含义:

  • Restart=on-failure:表示非正常退出时才会出发重启。
  • RestartSec=10:表示重启前等待10秒。
2. 指定PIDFile的位置
shell 复制代码
# 指定 PID 文件路径(需要 Tomcat 能够写入该文件)
PIDFile=/usr/local/tomcat/tomcat.pid

含义:

  • systemd管理服务根据这个文件获取主服务的pid
3. 工作目录
shell 复制代码
# 工作目录
WorkingDirectory=/usr/local/tomcat

含义:

  • 指定服务的工作目录。
  • 如果不指定,systemd默认以/目录作为工作目录。
  • 服务的配置中可能有相对路径位置,这个相对路径的起点由工作目录决定。
4. 环境变量
shell 复制代码
# 设置环境变量(根据你的实际 Java 环境调整)
Environment="JAVA_HOME=/usr/lib/jvm/default-java"
Environment="CATALINA_HOME=/usr/local/tomcat"
Environment="CATALINA_BASE=/usr/local/tomcat"
# 让 Tomcat 将 PID 写入指定文件
Environment="CATALINA_PID=/usr/local/tomcat/tomcat.pid"

含义:

  • systemd 启动的服务运行在一个干净、隔离的环境中 ,不会继承用户 shell 或登录会话中设置的环境变量,但是它可以读取PATH指定的位置的全局命令。
  • 服务运行的必要环境变量必须在这里进行声明。
  1. Environment="JAVA_HOME=/usr/lib/jvm/default-java": 指定javajdk目录。
  2. Environment="CATALINA_HOME=/usr/local/tomcat": 指定tomcat的家目录。
  3. Environment="CATALINA_BASE=/usr/local/tomcat": 指定tomcat的家目录,在单实例的情况下,这两个环境变量存储的值相同。
  4. Environment="CATALINA_PID=/usr/local/tomcat/tomcat.pid": 指定tomcat服务存储主服务进程的pid的文件的环境变量。如果不指定,systemd不能够通过/usr/local/tomcat/tomcat.pid获取主服务的pid

实操验证

编辑tomcat.service文件及相关配置
  1. /etc/systemd/system/tomcat.service文件中编写下面的内容。
shell 复制代码
[Unit]
Description=Tomcat start script
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/tomcat-11.0.18/bin/startup.sh
ExecStop=/usr/local/tomcat-11.0.18/bin/shutdown.sh

Restart=on-failure
RestartSec=5

PIDFile=/usr/local/tomcat-11.0.18/tomcat.pid

User=tomcat
Group=tomcat

WorkingDirectory=/usr/local/tomcat-11.0.18/ 

Environment="JAVA_HOME=/usr/local/jdk-21.0.10"
Environment="CATALINA_HOME=/usr/local/tomcat-11.0.18/"
Environment="CATALINA_PID=/usr/local/tomcat-11.0.18/tomcat.pid"



[Install]
WantedBy=multi-user.target
  1. 创建tomcat用户和用户组
    如果需要复习用户及用户组管理相关知识请跳转
shell 复制代码
# 分别修改/etc/passwd,/etc/shadow,/etc/group,/etc/gshadow文件
echo "tomcat:888:888:tomcat service user:/usr/local/tomcat-11.0.18/:/sbin/nologin" >> /etc/passwd
echo "tomcat:!!:20478::::::" >> /etc/shadow
echo "tomcat:x:888:" >> /etc/group
echo "tomcat:!::" >> /etc/gshadow
  1. 修改/usr/local/tomcat-11.0.18所属组和所有者。
shell 复制代码
chown -R tomcat:tomcat /usr/local/tomcat-11.0.18
  1. 创建文件/usr/local/tomcat-11.0.18/tomcat.pid
shell 复制代码
touch /usr/local/tomcat-11.0.18/tomcat.pid
chown tomcat:tomcat /usr/local/tomcat-11.0.18/tomcat.pid
  1. 重新加载全部的xxx.service文件
shell 复制代码
systemctl daemon-reload
验证
shell 复制代码
# 检测 systemctl start tomcat.service 是否能够正常启动tomcat服务。
[root@tomcat1 tomcat-11.0.18]# systemctl status tomcat.service 
○ tomcat.service - Tomcat start script
     Loaded: loaded (/etc/systemd/system/tomcat.service; disabled; preset: disabled)
     Active: inactive (dead)

4月 10 11:57:43 tomcat1 systemd[1]: Stopped Tomcat start script.
4月 10 11:57:43 tomcat1 systemd[1]: tomcat.service: Consumed 4.701s CPU time.
4月 10 11:58:07 tomcat1 systemd[1]: Starting Tomcat start script...
4月 10 11:58:07 tomcat1 startup.sh[2193]: Tomcat started.
4月 10 11:58:07 tomcat1 systemd[1]: Started Tomcat start script.
4月 10 12:12:45 tomcat1 systemd[1]: Stopping Tomcat start script...
4月 10 12:12:46 tomcat1 shutdown.sh[2337]: Tomcat stopped.
4月 10 12:12:46 tomcat1 systemd[1]: tomcat.service: Deactivated successfully.
4月 10 12:12:46 tomcat1 systemd[1]: Stopped Tomcat start script.
4月 10 12:12:46 tomcat1 systemd[1]: tomcat.service: Consumed 7.051s CPU time.
[root@tomcat1 tomcat-11.0.18]# systemctl start tomcat.service 
[root@tomcat1 tomcat-11.0.18]# systemctl status tomcat.service 
● tomcat.service - Tomcat start script
     Loaded: loaded (/etc/systemd/system/tomcat.service; disabled; preset: disabled)
     Active: active (running) since Fri 2026-04-10 12:13:03 CST; 6s ago
    Process: 2401 ExecStart=/usr/local/tomcat-11.0.18/bin/startup.sh (code=exited, status=0/SUCCESS)
   Main PID: 2408 (java)
      Tasks: 35 (limit: 12251)
     Memory: 84.7M
        CPU: 3.663s
     CGroup: /system.slice/tomcat.service
             └─2408 /usr/local/jdk-21.0.10/bin/java -Djava.util.logging.config.file=/usr/local/tomcat-11.0.18//>

4月 10 12:13:03 tomcat1 systemd[1]: Starting Tomcat start script...
4月 10 12:13:03 tomcat1 startup.sh[2401]: Tomcat started.
4月 10 12:13:03 tomcat1 systemd[1]: Started Tomcat start script.

# 检测服务是否可以使用。
[root@tomcat1 tomcat-11.0.18]# curl 192.168.122.17:8080
tomcat1 192.168.122.17 
# 检测 systemctl stop tomcat.service 是否可以正常停止服务。
[root@tomcat1 tomcat-11.0.18]# systemctl stop tomcat.service 
[root@tomcat1 tomcat-11.0.18]# systemctl status tomcat.service 
○ tomcat.service - Tomcat start script
     Loaded: loaded (/etc/systemd/system/tomcat.service; disabled; preset: disabled)
     Active: inactive (dead)

4月 10 12:12:46 tomcat1 systemd[1]: Stopped Tomcat start script.
4月 10 12:12:46 tomcat1 systemd[1]: tomcat.service: Consumed 7.051s CPU time.
4月 10 12:13:03 tomcat1 systemd[1]: Starting Tomcat start script...
4月 10 12:13:03 tomcat1 startup.sh[2401]: Tomcat started.
4月 10 12:13:03 tomcat1 systemd[1]: Started Tomcat start script.
4月 10 12:13:27 tomcat1 systemd[1]: Stopping Tomcat start script...
4月 10 12:13:27 tomcat1 shutdown.sh[2478]: Tomcat stopped.
4月 10 12:13:27 tomcat1 systemd[1]: tomcat.service: Deactivated successfully.
4月 10 12:13:27 tomcat1 systemd[1]: Stopped Tomcat start script.
4月 10 12:13:27 tomcat1 systemd[1]: tomcat.service: Consumed 4.643s CPU time.

全部正常,实验完毕。

相关推荐
senijusene2 小时前
i.MX6ULL 平台 Linux 字符设备驱动:LED 驱动解析
linux·运维·服务器
木心术12 小时前
Web安全攻防实战:常见漏洞分析与防御策略
网络·数据库·web安全
海特伟业2 小时前
校园IPTV电视系统:基于TCP/IP协议的新一代交互式校园IPTV电视系统的需求锚定和方案设计
网络
熬夜的咕噜猫2 小时前
LVS+Keepalived高可用群集
大数据·网络·数据库·mysql·mysql高可用
魈十三2 小时前
进程与线程:从独立空间到协调的深度解析
linux
北漂Zachary2 小时前
Laravel 6.x:高效开发与云原生的完美结合
云原生·php·laravel
TechWayfarer2 小时前
RSAC 2026启示录:从IP归属到IP风险画像,风控系统如何防御住宅代理与AI攻击?
网络·人工智能·python·tcp/ip·ip
HYNuyoah2 小时前
Ubuntu一键安装Docker和Docker Compose
linux·ubuntu·docker
dddddppppp1232 小时前
arm32段+页映射 手撕mmu的行为之软件模拟
linux·服务器·网络