强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

systemd 教程 / 用户服务(systemd --user)

用户服务(systemd –user)

概述

systemd 不仅管理系统级服务,还支持用户级服务。用户服务以普通用户身份运行,单元文件存放在用户主目录下,通过 systemctl --user 命令管理。用户服务适用于开发环境、个人定时任务、桌面应用等场景,无需 root 权限即可配置和管理。


基本概念

用户服务 vs 系统服务

对比项系统服务用户服务
运行身份root 或指定用户当前用户
单元路径/etc/systemd/system/~/.config/systemd/user/
管理命令sudo systemctl ...systemctl --user ...
日志查看journalctl -u ...journalctl --user -u ...
开机启动systemctl enablesystemctl --user enable
运行时目录/run/$XDG_RUNTIME_DIR
默认限制较高较低

用户服务的生命周期

用户登录 ──▶ systemd --user 启动 ──▶ 用户服务运行
                                         │
用户注销 ──▶ systemd --user 退出 ──▶ 用户服务停止
                                         │
          linger 启用时 ──────────▶ 用户服务继续运行

用户 Unit 路径

搜索路径

用户服务的单元文件按以下路径搜索(优先级从高到低):

路径说明
~/.config/systemd/user/用户自定义单元(推荐)
/etc/systemd/user/系统管理员配置的用户单元
~/.local/share/systemd/user/应用安装的用户单元
/usr/lib/systemd/user/发行版提供的用户单元

创建用户服务目录

# 创建用户服务目录
mkdir -p ~/.config/systemd/user/

# 查看用户服务搜索路径
systemctl --user show -p UnitPath

# 查看所有用户单元路径
systemd-path user-unit

systemctl –user 命令

基本操作

# 查看所有用户服务
systemctl --user list-units --type=service

# 查看所有用户单元文件
systemctl --user list-unit-files

# 启动/停止/重启服务
systemctl --user start myapp.service
systemctl --user stop myapp.service
systemctl --user restart myapp.service

# 查看服务状态
systemctl --user status myapp.service

# 启用/禁用开机启动
systemctl --user enable myapp.service
systemctl --user disable myapp.service

# 查看用户服务日志
journalctl --user -u myapp.service

# 重新加载用户单元配置
systemctl --user daemon-reload

# 查看用户管理器状态
systemctl --user status

用户服务环境变量

用户服务的环境变量来源:

来源说明
~/.config/environment.d/*.conf用户级环境变量文件
~/.pam_environmentPAM 环境变量(已弃用)
~/.bash_profile不被用户服务读取

environment.d 配置

# ~/.config/environment.d/myenv.conf
# 每行一个 KEY=VALUE
EDITOR=vim
GOPATH=/home/user/go
NODE_ENV=development
# 应用环境变量
systemctl --user daemon-reexec

# 验证
systemctl --user show-environment

⚠️ 注意:用户服务不会读取 ~/.bashrc~/.bash_profile,需要通过 environment.d 设置环境变量。


linger 机制

什么是 linger?

默认情况下,用户的所有服务在用户注销后会停止。启用 linger 后,用户服务可以在用户无登录会话时持续运行。

启用 linger

# 为当前用户启用 linger
loginctl enable-linger

# 为特定用户启用 linger
sudo loginctl enable-linger username

# 禁用 linger
loginctl disable-linger

# 查看 linger 状态
loginctl show-user username -p Linger

检查 linger

# 查看所有启用了 linger 的用户
ls /var/lib/systemd/linger/

# 查看当前用户的 linger 状态
loginctl show-user $USER -p Linger

💡 提示:如果需要在服务器上运行用户服务(如开发服务器、数据库),必须启用 linger,否则在 SSH 断开后服务会停止。

linger 与 SSH 会话

场景 1:无 linger
  SSH 登录 ──▶ 启动服务 ──▶ SSH 断开 ──▶ 服务停止

场景 2:有 linger
  SSH 登录 ──▶ 启动服务 ──▶ SSH 断开 ──▶ 服务继续运行

实际案例

案例 1:用户定时任务

使用用户定时器替代 crontab:

# ~/.config/systemd/user/backup.timer
[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=1800

[Install]
WantedBy=timers.target
# ~/.config/systemd/user/backup.service
[Unit]
Description=Daily backup

[Service]
Type=oneshot
ExecStart=/home/%u/scripts/backup.sh
StandardOutput=journal
StandardError=journal
# 启用定时器
systemctl --user enable --now backup.timer

# 查看定时器状态
systemctl --user list-timers

# 手动触发
systemctl --user start backup.service

案例 2:开发环境服务

运行本地开发服务器:

# ~/.config/systemd/user/dev-server.service
[Unit]
Description=Development Server
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/%u/projects/myapp
Environment=NODE_ENV=development
Environment=PORT=3000
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=default.target
# 启用并启动
systemctl --user enable --now dev-server.service

# 查看日志
journalctl --user -fu dev-server.service

# 查看状态
systemctl --user status dev-server.service

案例 3:用户级 Redis

# ~/.config/systemd/user/redis-dev.service
[Unit]
Description=User Redis Server

[Service]
Type=notify
ExecStart=/usr/bin/redis-server --port 6380 --daemonize no
ExecStop=/usr/bin/redis-cli -p 6380 shutdown
Restart=on-failure
RestartSec=3s

[Install]
WantedBy=default.target

案例 4:文件监控自动处理

# ~/.config/systemd/user/watch-downloads.path
[Unit]
Description=Watch Downloads Directory

[Path]
DirectoryNotEmpty=%h/Downloads
Unit=process-downloads.service

[Install]
WantedBy=default.target
# ~/.config/systemd/user/process-downloads.service
[Unit]
Description=Process Downloaded Files

[Service]
Type=oneshot
ExecStart=/home/%u/scripts/process-downloads.sh
systemctl --user enable --now watch-downloads.path

用户服务的 Specifier

用户服务中可以使用以下特殊占位符:

Specifier说明示例值
%u用户名john
%U用户 ID1000
%h用户主目录/home/john
%t运行时目录/run/user/1000
[Service]
WorkingDirectory=%h/projects
ExecStart=%h/bin/myapp
RuntimeDirectory=myapp

XDG 规范与用户服务

XDG Base Directory

用户服务遵循 XDG Base Directory 规范:

变量默认值用途
XDG_CONFIG_HOME~/.config配置文件
XDG_DATA_HOME~/.local/share数据文件
XDG_RUNTIME_DIR/run/user/$UID运行时文件
XDG_CACHE_HOME~/.cache缓存文件

RuntimeDirectory

systemd 提供 RuntimeDirectory 指令,自动在 $XDG_RUNTIME_DIR 下创建目录:

[Service]
ExecStart=/opt/myapp/bin/server
RuntimeDirectory=myapp
RuntimeDirectoryMode=0755
# 等价于创建 /run/user/1000/myapp

⚠️ 注意$XDG_RUNTIME_DIR(通常为 /run/user/$UID)在用户注销后会被清理(除非启用 linger)。


用户服务资源限制

内置限制

用户服务有默认的资源限制:

# 查看当前用户的默认限制
systemctl --user show -p DefaultMemoryMax
systemctl --user show -p DefaultTasksMax

# 查看用户管理器限制
systemctl --user show user@$(id -u).service -p MemoryMax,MemoryHigh,TasksMax

修改限制

# 临时修改(重启后失效)
systemctl --user set-property myapp.service MemoryMax=2G

# 永久修改(使用 drop-in 文件)
mkdir -p ~/.config/systemd/user/myapp.service.d/
cat > ~/.config/systemd/user/myapp.service.d/override.conf << 'EOF'
[Service]
MemoryMax=2G
CPUQuota=200%
EOF

# 重新加载
systemctl --user daemon-reload

增加用户服务默认限制

# 系统管理员可以修改用户服务默认限制
sudo loginctl set-property username MemoryMax=8G
sudo loginctl set-property username TasksMax=4096

# 或者修改 /etc/systemd/logind.conf
# [Login]
# UserTasksMax=4096

PAM 与用户服务

PAM 配置

用户服务的启动与 PAM(Pluggable Authentication Modules)密切相关:

用户登录 → PAM session → pam_systemd.so → 启动 systemd --user

查看用户会话

# 查看当前用户会话
loginctl list-sessions

# 查看会话详情
loginctl show-session $(loginctl | grep $USER | awk '{print $1}')

/etc/systemd/logind.conf 关键配置

[Login]
# 用户最大任务数
UserTasksMax=33%

# 用户会话超时(秒)
StopIdleSessionSec=infinity

# 是否在所有会话结束时杀死用户进程
KillUserProcesses=no

⚠️ 注意KillUserProcesses=no 是大多数发行版的默认设置,确保用户进程在注销后继续运行。但某些发行版(如 Ubuntu)可能默认设为 yes


调试用户服务

常用调试命令

# 查看用户管理器状态
systemctl --user status

# 查看用户服务日志
journalctl --user -u myapp.service
journalctl --user -fu myapp.service

# 查看用户服务配置
systemctl --user cat myapp.service

# 查看用户服务依赖
systemctl --user list-dependencies myapp.service

# 查看用户环境变量
systemctl --user show-environment

# 进入用户管理器的调试 shell
systemctl --user shell

常见问题排查

问题原因解决方案
用户服务在注销后停止未启用 lingerloginctl enable-linger
服务启动失败环境变量缺失使用 environment.d 配置
$DISPLAY$WAYLAND_DISPLAY 未设置图形会话未正确传递在服务中使用 Environment=
Failed to connect to busD-Bus 会话不可用检查 $DBUS_SESSION_BUS_ADDRESS
用户管理器未运行用户未登录启用 linger 或手动启动 systemd --user

手动启动用户管理器

# 如果用户管理器未运行,手动启动
systemctl --user daemon-reexec

# 或通过 lingering 触发
sudo loginctl enable-linger $USER

实用命令汇总

# 服务管理
systemctl --user start myapp.service
systemctl --user stop myapp.service
systemctl --user restart myapp.service
systemctl --user status myapp.service
systemctl --user enable myapp.service
systemctl --user disable myapp.service

# 查看
systemctl --user list-units
systemctl --user list-unit-files
systemctl --user list-timers
systemctl --user show myapp.service

# 日志
journalctl --user -u myapp.service
journalctl --user -fu myapp.service

# 环境
systemctl --user show-environment
systemctl --user set-environment KEY=VALUE
systemctl --user unset-environment KEY

# Linger
loginctl enable-linger
loginctl disable-linger
loginctl show-user $USER -p Linger

# 重新加载
systemctl --user daemon-reload
systemctl --user daemon-reexec

扩展阅读