DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

Caddy 手动启动正常,systemd 读取证书报 permission denied

root手动启动正常而systemd加载手动证书失败,核对实际服务身份、证书私钥路径与更新后的读取条件。

以 root 手动运行 Caddy 可以启动,改由 systemd 启动却出现 loading certificates、open ...: permission denied,通常需要先核对服务身份能否读取配置中手动指定的证书与私钥。root 能读文件,不代表服务进程也能读。

本文处理证书加载阶段的文件访问失败。服务已正常运行、客户端提示证书不可信时,应另查证书链和客户端信任;把根证书加入信任库不会让服务获得读取私钥的权限。

以实际 unit 和报错路径为准

先查看当前服务的完整 unit、覆盖项和启动日志:

systemctl cat caddy
systemctl show caddy -p User -p Group -p ExecStart -p ExecReload
journalctl -u caddy --since '15 minutes ago' --no-pager

核对服务调用的 Caddy 二进制、配置路径及运行用户。官方 unit 使用 caddy 用户与组;发行版包、自定义服务和 drop-in 可以改变这些值,不能仅凭服务名推断。

再看日志中被拒绝的路径究竟是证书、私钥还是配置文件。如果配置仍指向个人家目录,服务可能在父目录就被挡住。符号链接还需要检查最终目标所在的路径。不要把整份私钥打印到终端或贴入排错记录。

当前官方 unit 有 PrivateTmp 和 ProtectSystem 等限制,并未设置 ProtectHome。实际安装的服务可能另有覆盖项,应检查完整结果,不能看到 /home 下的报错就认定是某个沙箱选项导致。

把手动证书放到服务可管理的位置

对长期服务,使用管理员维护的专用证书目录,让服务身份具有必要的目录搜索权限及文件读取权限。证书续期或替换后,新文件也必须继续满足这些条件;只修正当前文件,下一次原子替换可能再次失败。

例如计划把手动证书放在 /etc/caddy/certs/,应先确认这与现有部署、备份和访问策略相容,再同步修改 tls 中的路径。这里的目录是部署选择,并非 Caddy 强制要求。手动证书不需要迁入内部 CA 的数据目录,私钥也不应开放给所有用户。

对已确认的实际文件,以服务用户做只读可访问检查。以下仅示意服务确实使用 caddy 用户、证书路径也已确认的情况:

sudo -u caddy -- test -r /etc/caddy/certs/site.crt
sudo -u caddy -- test -r /etc/caddy/certs/site.key

检查退出码。它们不会输出文件内容,但只能验证当前命令环境中的文件访问;systemd 沙箱、容器挂载或 SELinux、AppArmor 仍可能产生额外限制。若命令成功而服务仍报拒绝,应对照服务环境及系统拒绝日志继续定位,不要反复放宽权限。

adapt 成功不足以证明证书可以加载

caddy adapt 主要把配置转换为 JSON。路径已经被正确写入 JSON,不等于服务运行身份可以打开这些文件。

caddy validate 会加载并 provision 配置中的模块,能够发现更多初始化错误,但执行身份和环境仍要与服务对应。它会实际初始化模块;部分模块占用排他资源,在已有实例运行时用第二个进程验证可能产生资源冲突,不能一概当成无副作用的语法检查。

已有服务正在运行时,按实际配置工作流进行受控 reload;加载失败时,Caddy 会保留原来的活动配置。服务尚未成功启动,则需在访问权限修正后重新尝试启动。不要为了读取证书把服务改成 root。

连同下一次证书替换一起验收

保留原证书、受限权限的私钥及配置备份,再修改路径或权限。验收要同时确认服务加载成功、日志不再拒绝文件访问,以及启用正常校验的客户端拿到预期域名、有效期和证书链。

还应检查续期程序的用户、文件所有者和替换方式,确保新证书与私钥仍可被服务读取。若需要回退路径,应先确认旧文件仍在且仍有效;恢复旧配置不会自动恢复已经删除或替换的证书。