核心是定位被拒系统调用并精准补权限:先用journalctl -u service -n 50查operation not permitted后紧随的调用(如bind、setuid、openat),再依需配置capabilityboundingset与ambientcapabilities、检查user/group可行性或调整protectsystem等沙箱参数。

遇到 systemd 服务因权限不足启动失败,核心是搞清“进程想做什么”和“systemd 允许它做什么”之间的 gap。不是盲目加 sudo 或改 root,而是按线索精准补权限。
先看 journalctl 日志,定位具体被拒的系统调用
运行 journalctl -u your-service.service -n 50 --no-pager,重点找含 Operation not permitted 或 Permission denied 的行,并留意紧随其后的系统调用名,比如:
-
bind(2)→ 尝试绑定 80/443 等低端口,缺CAP_NET_BIND_SERVICE -
setuid(2)或setgid(2)→ 想切换用户/组,但降权太早或目标用户配置异常 -
openat(2)后跟路径 → 文件或目录不可读/不可执行,可能受ProtectHome=、ProtectSystem=或路径权限限制 -
capget(2)失败 → capability 配置不完整,如只设了CapabilityBoundingSet没配AmbientCapabilities
检查 User/Group 配置是否实际可行
报 Failed at step USER spawning 不是权限问题,而是用户环境缺失:
yuanfang-skills 的共享设计系统,提供 token CSS 变量、12+ 主题以及可复用的布局类型 HTML 块,供 yuanfang-html-image(以及 fu...)使用。
- 用
id www-data确认用户存在 - 检查该用户 home 目录是否存在且权限正确:
ls -ld /var/www(若未启用DynamicUser=yes) - 确认
/etc/passwd中对应用户的 Shell 字段 是有效登录 shell(如/bin/bash),不能是/usr/sbin/nologin或/bin/false - 更稳妥的做法是启用
DynamicUser=yes,让 systemd 自动创建临时用户,绕过系统用户依赖
验证 capability 配置是否真正生效
Capability 不是“开了就灵”,它有层级和继承规则:
-
CapabilityBoundingSet=只设上限,不自动授予;必须配合AmbientCapabilities=才能让进程在降权后仍保有该能力 - 例如绑定 80 端口:需同时写
CapabilityBoundingSet=CAP_NET_BIND_SERVICE和AmbientCapabilities=CAP_NET_BIND_SERVICE - 如果二进制本身被加过
setcap,systemd 默认会清空 ambient caps,所以 unit 文件里仍要显式声明 - 避免滥用
CapabilityBoundingSet=CAP_ALL,应按需最小授权
排除 systemd 安全沙箱的隐性限制
很多报错表面是权限不足,实则是沙箱策略挡路:
-
ProtectSystem=strict会挂载/usr为只读,此时连加载动态库都可能失败 -
ProtectHome=true会让/home、/root、/run/user不可见,若服务试图读取用户配置就会失败 -
NoNewPrivileges=true(默认开启)会阻止 setuid 程序提权,也影响 capability 继承 - 临时验证:在 unit 文件中加
ProtectSystem=false和ProtectHome=false测试是否恢复,再针对性放开










