打包前必须剥离所有环境密钥文件,包括移出项目树、禁用硬编码路径、改用环境变量或运行时挂载,并通过.gitignore、.dockerignore和构建验证确保敏感文件不残留。

打包前必须剥离所有环境密钥文件
FrankenPHP 打包成单文件时,frankenphp 二进制本身不读取也不嵌入任何密钥文件——但如果你把 .env、config/ 下的证书或私钥直接 COPY 进项目目录,它们就会随 PHP 源码一起被打包进去。这不是 FrankenPHP 的行为,而是你构建流程没做隔离。
- 禁止在
/app或public/目录下存放.env、ssl/、certs/等含密钥的目录 - 把密钥文件移出项目树,改用运行时挂载(Docker volumes)或环境变量注入(如
DB_PASSWORD) - 若用
composer install安装依赖,确认未把.env.example重命名为.env并提交进源码 - 检查
git ls-files | grep -i '\.key\|\.pem\|\.env',确保敏感路径不在 Git 索引中
Caddyfile 中不能硬编码密钥路径
很多人把 tls /etc/ssl/private/my.key 写死在 Caddyfile 里,误以为“路径只是字符串”,其实这等于暴露了密钥所在位置逻辑——攻击者只要拿到二进制并解压出 Caddyfile,就能反向定位服务器上该路径是否可读。
- 改用环境变量插值:
tls {env.SSL_CERT_PATH} {env.SSL_KEY_PATH} - 启动时通过
SSL_CERT_PATH=/run/secrets/cert.pem SSL_KEY_PATH=/run/secrets/key.pem ./frankenphp注入 - 避免在 Caddyfile 里出现
.key、.pem字样;若必须写路径,统一设为占位符如/secrets/tls.key,再靠部署层绑定真实路径 - Docker 场景下,用
secrets而非volumes加载私钥,防止被其他容器窥探
PHP 代码里别用 file_get_contents 读本地密钥文件
FrankenPHP 打包后,PHP 文件仍以明文形式存在。如果代码里写 file_get_contents('/app/config/api.key'),那这个路径和意图就全暴露了——哪怕文件实际不在包里,攻击者也能猜到你要去哪找。
- 改用
getenv('API_KEY')或$_SERVER['API_KEY'],密钥由操作系统或容器运行时注入 - 若必须读文件,路径不要写死,从环境变量读取:$path = $_ENV['SECRET_FILE_PATH'] ?? '/dev/null';
- 验证
file_exists($path)前先检查is_readable($path),避免报错泄露路径 - 禁用
allow_url_include=Off(默认已是),防止通过伪协议加载远程密钥
构建镜像时记得清理临时密钥副本
常见陷阱:CI 流程里为了测试 HTTPS,临时生成自签名证书放进构建上下文,最后忘了删——这些文件会残留在最终镜像的某一层里,用 docker history --no-trunc 能查到。
立即学习“PHP免费学习笔记(深入)”;
- Dockerfile 中避免
COPY certs/ /app/certs/;改用docker build --secret传入,再用mount=type=secret在运行时挂载 - 使用
.dockerignore明确排除.env、*key*、*pem*、config/*.yml - 构建后执行
docker run --rm <image> find /app -name "*.key" -o -name ".env" 2>/dev/null验证是否残留 - UPX 压缩不能掩盖密钥泄露——它只压缩二进制,不解密或过滤内容



















