内部サーバー
OxPHP は、ヘルスチェック、Prometheus メトリクス、ライブ設定の確認のために、専用ポート上で別個の HTTP サーバーを実行します。このサーバーはメインのアプリケーションリスナーから完全に分離されており、TLS もレート制限もリクエストID もイベント処理もありません。
仕組み
INTERNAL_ADDR にリッスンアドレス(例: 127.0.0.1:9090)を設定すると、OxPHP はそのアドレス上で 2 つ目の HTTP リスナーを起動します。内部サーバーは以下の組み込みエンドポイントを公開します。
/health— 集約された JSON ステータス/health/liveness、/healthz(エイリアス) — liveness プローブ/health/readiness、/readyz(エイリアス) — readiness プローブ/health/startup、/startupz(エイリアス) — startup プローブ/metrics— Prometheus 形式の出力/config— 有効なサーバー設定の JSON
プラグインは /__<plugin>/ プレフィックスの下に追加のエンドポイントを登録できます。グレースフルシャットダウンの間、内部サーバーはメインサーバーが接続のドレインを完了するまで利用可能な状態を保ちます。
内部サーバーは INTERNAL_ADDR が明示的に設定されている場合にのみ起動します。設定されていない場合、ヘルス、メトリクス、設定の各エンドポイントは HTTP 経由で利用できません。
設定
| Variable | Default | Description |
|---|---|---|
INTERNAL_ADDR |
(未設定) | 内部サーバーのアドレス。未設定の場合は起動しません。ポートのみの値(:9090 または 9090)は 127.0.0.1 にバインドします。ホスト外へ公開するには明示的に 0.0.0.0:9090 を使用してください。例: 127.0.0.1:9090 |
INTERNAL_ALLOW_IPS |
(未設定) | カンマ区切りの CIDR/IP 許可リスト。リスト外のピアは /metrics、/config、/__<plugin>/ パスに対して 403 を受け取ります。ヘルスプローブは常に到達可能なままです。未設定または空の場合はすべて許可されます。ループバックは暗黙的に含まれません。localhost からのアクセスを維持するには 127.0.0.1/32 を列挙してください。不正な形式のリストは起動を中断させます |
エンドポイント
GET /health
JSON のヘルスステータスを返します。Kubernetes の readiness プローブと liveness プローブにこれを使用してください。
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
Prometheus 互換のメトリクスをテキスト形式(text/plain; version=0.0.4; charset=utf-8)で返します。常に 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
...利用可能なメトリクスの完全な一覧については、メトリクスを参照してください。
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 との統合
readiness プローブ
Kubernetes が Pod にトラフィックをルーティングするかどうかを制御するには、/health を使用します。
readinessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 2
periodSeconds: 5/health が 503 を返すと、Kubernetes は Service のエンドポイント一覧から Pod を除外します。エンドポイントが再び 200 を返すと、トラフィックが再開されます。
liveness プローブ
応答しなくなった Pod を再起動するには、同じエンドポイントを使用します。
livenessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3startup プローブ
起動が遅いアプリケーション(大規模なフレームワーク、重いオートローダーなど)向け:
startupProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 15セキュリティ
内部サーバーにはベアラートークン認証がありません。アクセスは、どこにバインドするかと 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 かつ少なくとも 1 つのタスクがディスパッチまたは拒否された場合にのみ表示されます。
関連項目
- メトリクス — Prometheus メトリクスの完全なリファレンス
- ヘルスチェック — ヘルスチェックの詳細な挙動
- 設定リファレンス — すべての環境変数
- グレースフルシャットダウン — シャットダウンシーケンスと内部サーバーのライフサイクル