FrankenPHP 无内置 allow/deny 指令,必须通过 Caddyfile 的 handle + request.remote_ip + respond 实现 IP 白名单拦截,或在 PHP 入口文件开头校验 $_SERVER['REMOTE_ADDR'] 并支持 CIDR 匹配,其他位置配置均无效。

FrankenPHP 本身不提供 allow/deny 这类 Nginx 风格的 IP 访问控制指令,它没有内置的白名单/黑名单模块。想只让公司内网 IP 访问后台,必须把访问控制逻辑“前置”到 Caddy 层(FrankenPHP 的底层 Web 服务器),或“后置”到 PHP 应用层——不能指望 FrankenPHP 自己解析 allow 10.0.0.0/8 这种配置。
Caddyfile 中用 handle + respond 实现 IP 白名单拦截
FrankenPHP 启动时读的是 Caddyfile,而 Caddy 原生支持基于客户端 IP 的条件路由。关键不是写 allow,而是用 handle + request.remote_ip + respond 主动拦截非授权请求。
- 必须在匹配后台路径的
handle块最前面做判断,否则 PHP 已经开始执行了 -
request.remote_ip默认是直连 IP;如果前面有 SLB/CDN,需先配forwarded解析真实 IP - 网段匹配要用 CIDR 格式,比如
10.20.0.0/16,不能写10.20.*.* - 示例(限制
/admin和/api/v1/manager):
handle /admin* /api/v1/manager* {
@not_intranet {
not request.remote_ip 10.20.0.0/16
not request.remote_ip 172.16.100.0/24
not request.remote_ip 127.0.0.1
}
respond @not_intranet "Access denied" 403
php
}PHP 应用层校验更灵活但有绕过风险
如果你的后台入口是统一的 PHP 脚本(如 admin.php 或 Laravel 的 index.php),可以在脚本开头手动检查 $_SERVER['REMOTE_ADDR']。这比 Caddy 层更灵活(支持通配符、数据库查白名单、动态策略),但前提是请求已抵达 PHP —— 无法防扫描、爆破或恶意构造的请求头。
-
$_SERVER['REMOTE_ADDR']在 FrankenPHP 下是真实客户端 IP(无代理时),但若前端有反向代理,需确认是否透传了X-Forwarded-For并启用forwarded指令 - 别只用
in_array()简单比对,要支持 CIDR:可用ip_in_range()辅助函数,或直接调用filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)加ip2long()手动掩码计算 - 错误响应必须用
http_response_code(403),不能只 echo 文字,否则前端可能误判为成功
千万别在 FrankenPHP 的 PHP 配置里加 IP 限制
FrankenPHP 没有类似 Nginx 的 location 块或 Apache 的 .htaccess 支持,所有“服务器级”访问控制必须落在 Caddyfile 或 PHP 代码里。以下做法完全无效:
立即学习“PHP免费学习笔记(深入)”;
- 在
php.ini或frankenphp.yaml(如果存在)里写allow/deny—— 这些配置项 FrankenPHP 不识别 - 试图在
Caddyfile的php指令块里嵌套allow—— Caddy 语法不支持,nginx -t那套在这里不适用 - 依赖
$_SERVER['HTTP_X_REAL_IP']却没配forwarded—— 此时该字段为空或不可信,白名单形同虚设
真正起作用的只有两个位置:Caddyfile 的 handle 规则(推荐,早拦截)、或 PHP 入口文件开头的手动校验(备选,需补全 IP 解析逻辑)。其他任何地方加的“IP 限制”,都是幻觉。



















