Systemd Service 配置

Systemd Service 配置备忘录:从入门到生产级配置

技术博客 | Ubuntu 系统管理 | Systemd 服务配置
By GLM & MiniMax-M2.5
最后更新:2026-04-05

在 Linux 运维中,将程序封装为 Systemd 服务是标准操作。它不仅能实现开机自启,更重要的是提供了进程监控、日志管理和依赖控制。
本文将以一份标准配置为例,深入解析各个参数的含义与进阶用法。

1. 最小化模板 vs 生产级模板

极简模板(仅能启动)
如果你只是想临时跑一个程序,不需要自启和重启策略,只需要这几行:

1
2
3
4
5
6
7
8
[Unit]
Description=My Simple Service

[Service]
ExecStart=/path/to/your/program

[Install]
WantedBy=multi-user.target

生产级模板(推荐标准)
包含了网络依赖、自动重启、安全权限和日志配置,适合部署在服务器上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[Unit]
Description=My Production Service
Documentation=https://example.com/docs
# 网络就绪后启动
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
# 安全性:避免使用 root
User=www-data
Group=www-data
# 工作目录
WorkingDirectory=/var/www/app
# 启动命令(必须使用绝对路径)
ExecStart=/var/www/app/bin/start.sh
# 自动重启策略
Restart=on-failure
RestartSec=5s
# 资源限制(可选)
LimitNOFILE=65535
# 日志输出
StandardOutput=journal
StandardError=journal
# SyslogIdentifier 用于在日志中区分服务名
SyslogIdentifier=my-service

[Install]
WantedBy=multi-user.target

2. [Unit] 部分:启动条件与依赖

这部分决定了服务何时启动,以及启动顺序。

  • Description:服务的简短描述,systemctl status 时会显示。
  • After= vs Wants=:
    • After:决定顺序。After=network.target 表示网络启动后再启动本服务。
    • Wants:决定依赖。Wants=network.target 表示本服务依赖网络。通常两者配合使用。
      区别:如果只写 After,网络没启动好,你的服务也会启动(只是排在后面)。如果写了 Wants,网络服务启动失败,你的服务可能也会受影响(取决于依赖强度)。
  • Requires=:强依赖。如果依赖的服务挂了,本服务也会被停止。
    常用的启动依赖目标:
    • network.target:网络栈初始化完成(网卡启动)。
    • network-online.target:网络真正连通(获取到 IP,能联网)。对于 FRP、Web 服务等,建议用这个。
    • remote-fs.target:远程文件系统挂载完成(如 NFS)。

3. [Service] 部分:核心行为配置

3.1 进程类型 (Type)

  • simple (最常用):默认值。认为 ExecStart 启动的进程就是主进程。服务启动后,systemd 认为服务已就绪。
  • forking:经典 Unix 风格。ExecStart 会 fork 一个子进程后退出,父进程退出代表启动成功(如 Nginx 默认行为)。
  • notify:服务启动完成后,会主动向 systemd 发送信号。适合需要确信服务完全准备好才接收流量的场景。

3.2 自动重启策略 (Restart)

这是保证服务高可用的关键。
配合参数:

  • Restart=on-failure:如果服务退出非 0 状态,会自动重启。
  • Restart=always:如果服务退出非 0 状态,会自动重启。
  • Restart=on-abort:如果服务退出非 0 状态,会自动重启。
  • RestartSec=5s:重启前等待 5 秒,防止疯狂重启炸毁服务器。
  • StartLimitIntervalSec=60s 和 StartLimitBurst=3:与 RestartSec=5s 一起使用,防止服务持续重启,导致系统资源耗尽。
  • StartLimitIntervalSec=60s:60 秒内重启超过 3 次,则不再尝试重启,进入 failed 状态。

3.3 日志输出详解

Systemd 通过捕获标准输出来管理日志,不需要你在程序里自己写日志文件路径。

  • StandardOutput=:定义标准输出的去向。
  • StandardError=:定义标准错误的去向。
    常用配置值:
  • journal (推荐):
    输出到 Systemd Journal。
    优点:自动轮转,不会撑爆磁盘;支持 journalctl -u 服务名 快速查看;自动记录时间戳。
    自动获取 stdout 吗?:是的,程序里 print() 或 console.log() 输出的内容会被 systemd 捕获并写入 journal。
  • syslog:
    转发给系统 syslog 守护进程(如 rsyslog),可进一步配置转发到远程日志服务器。
  • file:/path/to/log.log:
    直接写入文件。
    缺点:需要自己处理日志轮转,文件权限问题容易出错。一般不推荐,除非有特殊需求。
  • append:/path/to/log.log:
    同上,但是以追加模式写入(不会覆盖旧文件)。
    如何查看日志?
1
2
3
4
5
# 查看所有日志
journalctl -u my-service.service

# 实时查看日志
journalctl -u my-service.service -f

4. [Install] 部分:随系统启动的原理

这部分只有在执行 systemctl enable 时才会被读取。

4.1 WantedBy=multi-user.target 是什么?

Target 概念:Systemd 用 “Target” 代替了传统的运行级别。

  • poweroff.target: 关机状态。
  • rescue.target: 单用户救援模式。
  • multi-user.target: 多用户命令行模式(对应旧版 Runlevel 3)。这是服务器的标准运行状态。
  • graphical.target: 图形界面模式(依赖 multi-user.target)。

4.2 为什么随系统启动?

当你执行 systemctl enable my-service 时,Systemd 会根据 [Install] 里的配置,在 /etc/systemd/system/multi-user.target.wants/ 目录下创建一个软链接,指向你的服务文件。
系统启动时,Systemd 会启动 multi-user.target,而 multi-user.target “想要” 所有在那个目录下的服务,于是就把你的服务拉起来了。

4.3 其他 [Install] 常用选项

  • RequiredBy=target:
    与 WantedBy 类似,但这是强依赖。
    区别:如果服务启动失败,WantedBy 不会报错继续启动系统;RequiredBy 会导致系统启动流程报错或进入紧急模式。
  • Alias=servicename:
    给服务起别名。比如 systemctl enable servicename 也可以用别名来操作。
  • Also=another.service:
    联动操作。当你 enable 这个服务时,也会自动 enable 另一个服务。

5. 进阶配置:还能加什么?

5.1 环境变量

程序往往需要数据库密码或 API Key,不要写在命令行里。

1
2
3
4
5
6
[Service]
# 方式一:直接定义
Environment="DB_HOST=127.0.0.1"
Environment="DB_PORT=3306"
# 方式二:从文件加载(更安全,文件权限设为 600)
EnvironmentFile=/etc/my-service/config.env

5.2 执行前置与后置

ExecStartPre=:在主进程启动前执行的命令。常用于检查配置文件、创建临时目录。
ExecStartPost=:启动后执行的命令。
ExecStopPost=:停止后执行的命令(无论是否正常停止)。常用于清理残留文件。

示例:启动前检查目录

1
2
ExecStartPre=/bin/mkdir -p /var/run/my-service
ExecStartPre=/usr/bin/test -f /etc/my-service/config.ini

5.3 资源限制

防止程序内存泄漏拖垮系统。

1
2
3
4
5
6
7
8
# 限制最大打开文件数(解决 "Too many open files" 报错)
LimitNOFILE=65535
# 限制最大进程数
LimitNPROC=4096
# 内存软限制(超过会警告)
MemorySoft=infinity
# 内存硬限制(超过会被 OOM Killer 杀死)
MemoryMax=2G

5.4 安全加固

如果服务暴露在公网,建议开启安全隔离:

1
2
3
4
5
6
# 保护系统目录(只读挂载 /usr /boot 等)
ProtectSystem=full
# 保护 Home 目录
ProtectHome=true
# 禁止服务获取 root 权限(即使以 root 运行)
NoNewPrivileges=true

6. 服务管理常用命令

保存配置后,需要执行以下命令使服务正常运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 重载配置
sudo systemctl daemon-reload

# 设置开机自启
sudo systemctl enable your-service-name

# 立即启动
sudo systemctl start your-service-name

# 查看状态(确认 Active: active (running))
sudo systemctl status your-service-name

# 实时查看日志
sudo journalctl -u your-service-name -f

# 查看最近 50 行
sudo journalctl -u your-service-name -n 50

# 停止服务
sudo systemctl stop your-service-name

# 禁用开机自启
sudo systemctl disable your-service-name

# 重启服务
sudo systemctl restart your-service-name

# 查看服务详细信息(含 PID、内存等)
systemctl show your-service-name

其他常用日志命令

1
2
3
4
5
6
7
8
9
10
11
# 查看今天的日志
journalctl --since today -u your-service-name

# 查看指定时间范围的日志
journalctl --since "2024-01-01 00:00:00" --until "2024-01-01 23:59:59" -u your-service-name

# 查看错误级别的日志
journalctl -p err -u your-service-name

# 清空该服务的旧日志(谨慎使用)
sudo journalctl --vacuum-time=7d -u your-service-name

常见问题排查

1
2
3
4
5
6
7
8
9
# 查看服务失败原因
sudo systemctl status your-service-name
journalctl -xe -u your-service-name

# 检查配置文件语法
systemd-analyze verify /etc/systemd/system/your-service-name.service

# 查看服务启动耗时
systemd-analyze blame | grep your-service-name

总结

一个健壮的服务配置应包含:

  • 网络依赖 (After=network-online.target)
  • 故障自愈 (Restart=on-failure)
  • 日志管理 (StandardOutput=journal)
  • 权限最小化 (User=non-root)

保存配置后,记得执行以下命令使其生效:

1
2
sudo systemctl daemon-reload
sudo systemctl enable --now my-service

Systemd Service 配置
https://bhm-bob.github.io/2026/04/05/tech_notes/Ubuntu/systemd.service/
作者
BHM-Bob G
发布于
2026年4月5日
许可协议