SERVER_NAME仅在dunglas/frankenphp官方镜像中生效,用于自动生成Caddy配置;非官方镜像或自定义Caddyfile时无效,且不自动映射到PHP的$_SERVER['SERVER_NAME']。

SERVER_NAME 环境变量只在 Docker 镜像中生效
当你用 dunglas/frankenphp 官方镜像启动容器时,SERVER_NAME 是唯一被镜像内启动脚本识别并自动注入到 Caddy 配置中的环境变量。它不会影响 PHP 运行时本身,而是用于生成默认的 Caddyfile 片段——比如把 localhost 替换成你填的值,或补全 :80 这类监听地址。
如果你不是用这个镜像(比如自己编译二进制、用 systemd 手动启、或基于 alpine 自定义基础镜像),SERVER_NAME 就完全不生效,Caddy 启动时会报错找不到站点配置,或者 fallback 到默认的 localhost。
- 用官方镜像:必须设,否则 Caddy 不知道该响应哪个域名,静态路由和 HTTPS 申请都会失败
- 自己写
Caddyfile并通过--config指定:可以不设,SERVER_NAME被忽略 - 用
docker-compose.yml但没挂载自定义 Caddyfile:必须设,且格式要对(如example.com或:80)
设成 :80 或 :443 时会发生什么
当 SERVER_NAME 设为 :80 或 :443,FrankenPHP 镜像会生成一个监听所有接口的站点块,不校验 Host 头。这适合本地开发、CI 构建测试、或反向代理后端(比如前面套了 Traefik/Nginx)。
但它会禁用 Let’s Encrypt 自动证书申请——因为 ACME 协议要求可公网解析的域名。如果你硬写 SERVER_NAME=:443 又没配 TLS 证书文件,Caddy 启动时会卡在 TLS 初始化,日志里反复打印 acme: error: 400 :: POST :: https://acme-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rejectedIdentifier。
立即学习“PHP免费学习笔记(深入)”;
- 开发/测试环境:用
:80最省事,跳过 HTTPS 和域名校验 - 生产环境暴露公网:必须设成真实域名,如
api.example.com - 想强制 HTTPS 但又不想自动申请:得手动挂载证书,并在 Caddyfile 里显式写
tls /path/to/cert.pem /path/to/key.pem
为什么不能靠 $_SERVER['SERVER_NAME'] 在 PHP 里读取它
SERVER_NAME 是容器启动时传给 Caddy 的配置参数,不是 PHP 的 CGI 环境变量。你在 PHP 代码里调用 $_SERVER['SERVER_NAME'] 拿到的,是 Caddy 实际传给 PHP 的 SERVER_NAME CGI 值——这个值默认是空,除非你在 Caddyfile 里显式用 php_server { env SERVER_NAME example.com } 注入。
换句话说:环境变量 SERVER_NAME ≠ PHP 的 $_SERVER['SERVER_NAME']。前者驱动 Caddy 配置,后者只是个普通 CGI 变量,两者无自动映射关系。
- 需要在 PHP 中获取当前服务域名?改用
$_SERVER['HTTP_HOST']或$_SERVER['SERVER_NAME'](需手动注入) - 依赖
$_SERVER['SERVER_NAME']做逻辑判断的旧代码?必须在 Caddyfile 里补env指令,不能指望环境变量自动透传 - worker 模式下更要注意:CGI 变量在常驻进程中只初始化一次,改环境变量不生效,必须重启 worker
多站点部署时 SERVER_NAME 不够用怎么办
一个容器只能设一个 SERVER_NAME,所以它天生不支持单容器跑多个不同域名的 PHP 应用。强行在一个 Caddyfile 里写多个域名块(如 site1.com { php_server } site2.com { php_server }),SERVER_NAME 只能控制第一个块的生成逻辑,其余块得手写。
真正可行的方案只有两个:
- 每个域名起一个独立容器,各自设自己的
SERVER_NAME(推荐,隔离性好) - 放弃
SERVER_NAME,直接提供完整Caddyfile,用import或多站点语法管理(适合有自动化配置生成能力的团队)
别试图用 SERVER_NAME=site1.com,site2.com 这种逗号分隔写法——镜像启动脚本不解析,Caddy 会把它当做一个非法主机名直接拒掉。



















