内部服务器
OxPHP 会在一个专用端口上运行一个独立的 HTTP 服务器,用于健康检查、Prometheus 指标以及实时配置查看。它与主应用监听器完全隔离:没有 TLS,没有限流,没有请求 ID,也不做事件处理。
工作原理
将 INTERNAL_ADDR 设置为一个监听地址(例如 127.0.0.1:9090),OxPHP 就会在该地址上启动第二个 HTTP 监听器。内部服务器会暴露下列内置端点:
/health— 聚合的 JSON 状态/health/liveness、/healthz(别名)— 存活探针/health/readiness、/readyz(别名)— 就绪探针/health/startup、/startupz(别名)— 启动探针/metrics— Prometheus 格式输出/config— 当前生效的服务器配置 JSON
插件可以在 /__<plugin>/ 前缀下注册额外的端点。在优雅关闭期间,内部服务器会一直保持可用,直到主服务器完成连接排空。
只有在显式设置了 INTERNAL_ADDR 时,内部服务器才会启动。若不设置,健康检查、指标和配置端点将无法通过 HTTP 访问。
配置
| Variable | Default | Description |
|---|---|---|
INTERNAL_ADDR |
(unset) | 内部服务器的地址。未设置时不启动。仅指定端口的值(:9090 或 9090)会绑定到 127.0.0.1;要将其暴露到主机之外,请使用显式的 0.0.0.0:9090。示例:127.0.0.1:9090 |
INTERNAL_ALLOW_IPS |
(unset) | 以逗号分隔的 CIDR/IP 允许列表。列表之外的对端在访问 /metrics、/config 以及 /__<plugin>/ 路径时会收到 403;健康探针始终保持可达。未设置/为空 = 允许所有。回环地址不会被隐式包含——请列出 127.0.0.1/32 以保留 localhost 访问。列表格式错误会中止启动 |
端点
GET /health
返回 JSON 格式的健康状态。可将其用于 Kubernetes 的就绪探针和存活探针。
200 OK — 所有系统健康:
{
"status": "ok",
"uptime_secs": 3612,
"total_requests": 48203,
"active_connections": 7,
"executor_healthy": true,
"plugins": {
"otel": "ok"
}
}503 Service Unavailable — 某个插件报告了失败:
{
"status": "degraded",
"uptime_secs": 3612,
"total_requests": 48203,
"active_connections": 7,
"executor_healthy": true,
"plugins": {
"otel": "failed"
}
}plugins 对象会列出每个已加载的插件及其健康状态:"ok"、"degraded" 或 "failed"。当任意插件报告 "failed",或者脚本执行器不健康(executor_healthy: false)时,该端点会返回 503。"degraded" 的插件会出现在 JSON 响应体中,但 HTTP 状态码仍为 200。
GET /metrics
以文本格式(text/plain; version=0.0.4; charset=utf-8)返回 Prometheus 兼容的指标。始终返回 200。
curl http://localhost:9090/metrics# HELP oxphp_requests_total Total HTTP requests
# TYPE oxphp_requests_total counter
oxphp_requests_total 48203
# HELP oxphp_active_connections Current open connections
# TYPE oxphp_active_connections gauge
oxphp_active_connections 7
...有关可用指标的完整列表,请参阅 Metrics。
GET /config
以 JSON 形式返回当前生效的服务器配置。始终返回 200。
curl -s http://localhost:9090/config | jq .{
"listen_addr": "0.0.0.0:80",
"document_root": "/var/www/html/public",
"entry_file": "/var/www/html/public/index.php",
"log_level": "info",
"executor_type": "sapi",
"php_workers": "8",
"tokio_workers": 4,
"queue_capacity": 1024,
"max_connections": 10000,
"drain_timeout_seconds": 30,
"header_timeout_seconds": 5,
"rate_limit": 100,
"rate_window_seconds": 60,
"tls_enabled": true,
"tls_min_version": "1.2",
"compression_level": 4,
"access_log": "all",
"max_query_body": 524288,
"worker_mode_enabled": false,
"worker_max_memory_mib": 0,
"static_max_age": 2592000,
"static_revalidate": false,
"async_workers": 0,
"async_queue_capacity": 0,
"async_max_fibers": 256,
"async_in_flight_cap": 0,
"trace_context": false,
"superglobals_enabled": true,
"trusted_proxies": false,
"plugins": {}
}TLS 证书和密钥文件路径永远不会被输出(只暴露 tls_enabled 布尔值),而 internal_addr 和 error_pages_dir 也会从所返回的响应中被清除——这些部署拓扑和文件系统路径对攻击者有帮助,而抓取程序并不需要它们。
插件端点
插件可以在 /__<plugin_name>/ 前缀下注册自定义端点。例如,一个名为 otel 的插件可以暴露 /__otel/status。只有在对应的插件已加载并注册了处理器时,这些端点才可用。
任何既不匹配内置端点也不匹配插件端点的路径都会返回 404 Not Found。
Kubernetes 集成
就绪探针
使用 /health 来控制 Kubernetes 是否将流量路由到该 Pod:
readinessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 2
periodSeconds: 5当 /health 返回 503 时,Kubernetes 会将该 Pod 从 Service 的端点列表中移除。当该端点重新返回 200 时,流量恢复。
存活探针
使用同一个端点来重启变得无响应的 Pod:
livenessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3启动探针
适用于启动较慢的应用(大型框架、繁重的自动加载器):
startupProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 15安全
内部服务器没有 bearer-token 认证;访问控制取决于它绑定在何处以及 INTERNAL_ALLOW_IPS。要保护它:
- 绑定到 localhost — 仅指定端口的
INTERNAL_ADDR(:9090)已经会绑定到127.0.0.1;显式的127.0.0.1:9090可让该端口仅能从容器或主机内部访问 - 设置
INTERNAL_ALLOW_IPS— 当监听器必须能从主机之外访问时使用它——这是一个 CIDR/IP 允许列表,对列表之外的对端在访问/metrics、/config以及插件路径时返回403,同时健康探针保持可达。回环地址不会被隐式包含,因此如果你仍需要 localhost 访问,请加入127.0.0.1/32。如果监听器暴露到主机之外却未设置允许列表,服务器会在启动时发出警告 - 不要将其作为 Kubernetes Service 暴露 — 将该端口声明为
containerPort,但不要为它创建 Service。Kubernetes 探针会直接访问容器端口 - 使用网络策略 — 如果该端口必须暴露,请在网络层限制访问
/config 端点会泄露运维细节(文档根目录、限流参数、工作进程数量、超时值)。TLS 路径、internal_addr 和 error_pages_dir 会被清除,但仍需考虑其余内容是否应当能从 Pod 外部访问。
Docker 示例
要快速查看,你可以将内部端口发布出来;在生产环境中,请将内部服务器绑定到 localhost 并使用 Kubernetes 探针。
services:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "80:80"
- "9090:9090"
environment:
- DOCUMENT_ROOT=/var/www/html/public
- INTERNAL_ADDR=0.0.0.0:9090services:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "80:80"
environment:
- DOCUMENT_ROOT=/var/www/html/public
- INTERNAL_ADDR=127.0.0.1:9090故障排查
健康检查、指标和配置端点不可用
INTERNAL_ADDR 未设置。
解决方法: 添加该环境变量:
INTERNAL_ADDR=0.0.0.0:9090/health 返回 503 但应用正常工作
某个已加载的插件正在报告 PluginHealth::Failed。检查健康响应中的 plugins 对象以确定是哪个插件出了问题:
curl -s http://localhost:9090/health | jq '.plugins'无法从容器外部访问内部服务器
该服务器绑定到了 127.0.0.1,只能从容器内部访问。
解决方法: 改为 0.0.0.0 以供外部访问,或使用直接访问容器的 Kubernetes 探针。
指标中未显示工作进程模式或异步指标
工作进程模式的指标只有在启用了工作进程模式(WORKER_MODE_ENABLED=true)时才会出现。异步指标只有在 ASYNC_WORKERS > 0 且至少有一个任务被派发或被拒绝时才会出现。
另请参阅
- Metrics — 完整的 Prometheus 指标参考
- Health Checks — 详细的健康检查行为
- Configuration Reference — 全部环境变量
- Graceful Shutdown — 关闭序列与内部服务器生命周期