FrankenPHP不管理私钥磁盘权限,安全依赖操作系统:私钥文件须设600权限、属主为运行用户(如www-data)、存放于Web不可达路径(如/etc/frankenphp/ssl/)、父目录权限700、禁用密码保护。

FrankenPHP 自身不接管证书私钥的磁盘权限管理,它只是读取你指定路径下的 ssl_certificate_key 文件。权限是否安全,完全取决于你如何在操作系统层面配置该文件及其父目录 —— 这和 Nginx 场景一致,但容易被误以为“FrankenPHP 更简单,所以权限也自动更安全”。
私钥路径必须隔离且禁止 Web 可访问
FrankenPHP 的 Caddy 配置中若用 tls 指令加载证书,例如:
tls /etc/frankenphp/ssl/example.com.pem /etc/frankenphp/ssl/example.com.key
那么 /etc/frankenphp/ssl/ 就是你的私钥存放根目录。这个路径必须满足:
- 不在任何
root、file_server或reverse_proxy的服务路径下 —— 否则可能被意外映射成静态资源暴露 - 绝对不能放在
/var/www/、/srv/http/、/usr/share/frankenphp/等 Web 可达路径内 - 验证方式:用 curl 或浏览器直接请求
https://yoursite.tld/ssl/example.com.key,应返回 404 或 403,绝不能返回 200 + 私钥内容
文件权限必须设为 600,属主为 frankenphp 运行用户
FrankenPHP 默认以当前用户身份启动(非 root),但它需要能打开私钥文件。常见错误是沿用 Nginx 习惯设为 root:root,结果 FrankenPHP 无法读取。
立即学习“PHP免费学习笔记(深入)”;
- 先确认 FrankenPHP 进程运行用户:
ps aux | grep frankenphp,看 USER 列(常见为www-data、frankenphp或当前登录用户) - 执行:
chmod 600 /etc/frankenphp/ssl/example.com.key - 执行:
chown www-data:www-data /etc/frankenphp/ssl/example.com.key(替换为你实际的运行用户) - 切勿用
umask 002生成私钥,否则默认可能是 640,组可读 —— 这等于把私钥半公开
父目录权限也要锁定,避免遍历或覆盖风险
即使私钥文件权限正确,如果父目录可写且宽松,攻击者仍可能:
- 删除并替换私钥文件(若目录对运行用户可写)
- 通过符号链接绕过路径检查(若目录可执行但未限制遍历)
因此必须收紧目录权限:
-
chmod 700 /etc/frankenphp/ssl/(仅 owner 可读、写、执行) -
chown www-data:www-data /etc/frankenphp/ssl/(与私钥文件属主一致) - 目录的
x权限不可省 —— 否则 FrankenPHP 进程无法进入该目录打开文件
不要给私钥加密码保护
FrankenPHP 不支持交互式输入密码,也无法从环境变量或密钥管理服务自动解密加密私钥。
- 若你用
openssl genrsa -aes256生成了带密码的私钥,FrankenPHP 启动时会报错:failed to load private key: unable to decrypt - 正确做法是生成无密码私钥:
openssl genrsa -out example.com.key 4096 - 安全性靠的是 OS 层面的
600权限 + 目录隔离,而非私钥密码
最容易被忽略的一点:FrankenPHP 启动后不会校验私钥权限是否合理,它只在 TLS 握手首次触发时才尝试读取 —— 所以权限问题往往出现在上线后第一个 HTTPS 请求,而不是启动阶段。务必在 reload 前用 sudo -u www-data cat /etc/frankenphp/ssl/example.com.key 手动模拟进程权限测试可读性。



















