不能用 root 启动 FrankenPHP,因其不降权,会以 root 身份读写 .env、runtime、上传临时目录等,导致敏感信息泄露、权限冲突及文件覆盖风险。

必须用非 root 用户启动 FrankenPHP,否则存在严重权限越界风险;root 运行时,.env 文件、runtime 目录、上传临时文件等都可能被意外覆盖或读取。
为什么不能用 root 启动
FrankenPHP 本身不 drop privileges,它会以启动用户身份访问所有文件。一旦以 root 运行:
-
.env文件若权限为600,root 可读可写,但若误设为644,其他用户也能读取数据库密码 -
runtime/、storage/等目录会被 root 创建,后续 PHP 进程(如 cron 或 worker)若以www-data身份运行,将因权限不足无法写入日志或缓存 - 上传的临时文件(
php://temp或磁盘 fallback)默认归属 root,导致框架后续 move_uploaded_file 失败 - Docker 中若用
--user root挂载宿主机.env,容器内继承的 uid/gid 仍为 root,绕过所有权限隔离
systemd 服务中正确指定用户
不要依赖 User=www-data 后再 chown -R www-data:www-data /app —— 这样做无法保证 .env 的初始权限。必须在服务定义里显式声明运行上下文:
sudo tee /etc/systemd/system/frankenphp.service <<'EOF'
[Unit]
Description=FrankenPHP
After=network.target
<p>[Service]
Type=exec
User=www-data
Group=www-data
WorkingDirectory=/app
ExecStart=/usr/local/bin/frankenphp server --document-root /app/public --router /app/public/.frankenphp.router.php
Restart=always
RestartSec=10
Environment=APP_ENV=production</p><h1>关键:禁止继承 root 环境变量,避免污染</h1><p>UnsetEnvironment=PATH HOME TERM</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/7fc7563c4182" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">PHP免费学习笔记(深入)</a>”;</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站"><img
src="https://img.php.cn/upload/skill/000/000/081/179040786932301.jpg" alt="btpanel phpsite 宝塔面板PHP网站" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站">btpanel phpsite 宝塔面板PHP网站</a>
<p>宝塔面板 PHP 网站管理:站点创建、删除、启停、PHP 版本切换、域名管理、SSL证书管理、伪静态管理、数据库管理</p>
</div>
<a href="/xiazai/skill5233" title="btpanel phpsite 宝塔面板PHP网站" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><h1>强制 umask,确保新建文件默认 600/755</h1><p>UMask=0022</p><p>[Install]
WantedBy=multi-user.target
EOF启用前务必检查:
-
ls -l /app/.env→ 必须是-rw------- 1 www-data www-data -
ls -ld /app/runtime→ 必须是drwxr-xr-x 1 www-data www-data(或更宽松的755,但不能是777) -
sudo systemctl daemon-reload && sudo systemctl start frankenphp后,用ps aux | grep frankenphp确认 UID 是www-data,不是root
Docker 中对齐 UID/GID
Docker 默认以 root 启动,即使镜像里声明了 USER www-data,bind mount 的宿主机文件权限仍按宿主机 uid/gid 解析。常见错误是:
- 宿主机
.env属主为root:root,权限644→ 容器内www-data用户无法读取(uid 不匹配) - 用
docker run -u www-data但未提前在宿主机chown 33:33 .env(假设 www-data uid=33)→ 容器内仍无权读
安全做法只有两种:
- 宿主机先改权限:
sudo chown 33:33 .env && chmod 600 .env,再docker run -u 33:33 ... - 或用
docker run --user $(id -u):$(id -g),前提是容器内存在对应 uid/gid 的用户(dunglas/frankenphp镜像已预建www-data用户,uid=33)
容易被忽略的隐性 root 依赖点
有些配置看似和用户无关,实则暗藏 root 陷阱:
-
php_ini opcache.preload:预加载脚本若路径在/root/下,非 root 用户根本打不开 -
file_put_contents('/tmp/cache.bin'):若应用硬编码绝对路径且未检查权限,root 写的文件其他用户无法覆盖 - Caddy 自动申请证书时,默认把
/data存到 root 权限目录;必须通过CADDY_DATA_HOME=/var/lib/caddy并chown caddy:caddy /var/lib/caddy显式转移 - worker 模式下,
--script参数指向的worker.php若属主是 root,FrankenPHP 会因无法 stat 而报failed to open stream,错误信息里不提示权限问题,只显示文件不存在


















