Serveur interne
OxPHP exécute un serveur HTTP distinct sur un port dédié pour les contrôles de santé, les métriques Prometheus et l'inspection de la configuration en direct. Il reste totalement isolé de l'écouteur de l'application principale : pas de TLS, pas de limitation de débit, pas d'ID de requête et aucun traitement d'événements.
Fonctionnement
Définissez INTERNAL_ADDR avec une adresse d'écoute (par exemple 127.0.0.1:9090) et OxPHP démarre un second écouteur HTTP sur cette adresse. Le serveur interne expose les endpoints intégrés ci-dessous :
/health— statut JSON agrégé/health/liveness,/healthz(alias) — sonde de vivacité/health/readiness,/readyz(alias) — sonde de disponibilité/health/startup,/startupz(alias) — sonde de démarrage/metrics— exposition Prometheus/config— configuration active du serveur au format JSON
Les plugins peuvent enregistrer des endpoints supplémentaires sous le préfixe /__<plugin>/. Pendant l'arrêt gracieux, le serveur interne reste disponible jusqu'à ce que le serveur principal ait terminé de vider ses connexions.
Le serveur interne ne démarre que lorsque INTERNAL_ADDR est explicitement défini. Sans cette variable, les endpoints de santé, de métriques et de configuration ne sont pas accessibles via HTTP.
Configuration
| Variable | Valeur par défaut | Description |
|---|---|---|
INTERNAL_ADDR |
(non défini) | Adresse du serveur interne. Non démarré lorsqu'il n'est pas défini. Une valeur ne comportant qu'un port (:9090 ou 9090) se lie à 127.0.0.1 ; utilisez explicitement 0.0.0.0:9090 pour l'exposer hors de l'hôte. Exemple : 127.0.0.1:9090 |
INTERNAL_ALLOW_IPS |
(non défini) | Liste d'autorisation CIDR/IP séparée par des virgules. Les pairs en dehors de la liste reçoivent 403 sur les chemins /metrics, /config et /__<plugin>/ ; les sondes de santé restent toujours accessibles. Non défini/vide = tout autoriser. Le loopback n'est pas implicite — indiquez 127.0.0.1/32 pour conserver l'accès depuis localhost. Une liste mal formée interrompt le démarrage |
Endpoints
GET /health
Renvoie un statut de santé au format JSON. Utilisez-le pour les sondes de disponibilité et de vivacité de Kubernetes.
200 OK — tous les systèmes fonctionnent :
{
"status": "ok",
"uptime_secs": 3612,
"total_requests": 48203,
"active_connections": 7,
"executor_healthy": true,
"plugins": {
"otel": "ok"
}
}503 Service Unavailable — un plugin a signalé une défaillance :
{
"status": "degraded",
"uptime_secs": 3612,
"total_requests": 48203,
"active_connections": 7,
"executor_healthy": true,
"plugins": {
"otel": "failed"
}
}L'objet plugins liste chaque plugin chargé avec son statut de santé : "ok", "degraded" ou "failed". L'endpoint renvoie 503 lorsqu'un plugin signale "failed" ou lorsque l'exécuteur de scripts est défaillant (executor_healthy: false). Les plugins "degraded" apparaissent dans le corps JSON mais le statut HTTP reste 200.
GET /metrics
Renvoie des métriques compatibles Prometheus au format texte (text/plain; version=0.0.4; charset=utf-8). Renvoie toujours 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
...Pour la liste complète des métriques disponibles, voir Métriques.
GET /config
Renvoie la configuration active du serveur au format JSON. Renvoie toujours 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": {}
}Les chemins des fichiers de certificat et de clé TLS ne sont jamais émis (seul le booléen tls_enabled est exposé), et internal_addr ainsi que error_pages_dir sont expurgés de la réponse servie — topologie de déploiement et chemins du système de fichiers qui aideraient un attaquant et dont les collecteurs n'ont pas besoin.
Endpoints de plugins
Les plugins peuvent enregistrer des endpoints personnalisés sous le préfixe /__<plugin_name>/. Par exemple, un plugin nommé otel pourrait exposer /__otel/status. Ces endpoints ne sont disponibles que si le plugin correspondant est chargé et a enregistré un gestionnaire.
Tout chemin ne correspondant ni à un endpoint intégré ni à un endpoint de plugin renvoie 404 Not Found.
Intégration Kubernetes
Sonde de disponibilité
Utilisez /health pour déterminer si Kubernetes achemine le trafic vers le pod :
readinessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 2
periodSeconds: 5Lorsque /health renvoie 503, Kubernetes retire le pod de la liste des endpoints du Service. Le trafic reprend lorsque l'endpoint renvoie de nouveau 200.
Sonde de vivacité
Utilisez le même endpoint pour redémarrer les pods qui deviennent non réactifs :
livenessProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3Sonde de démarrage
Pour les applications au démarrage lent (frameworks volumineux, autoloaders lourds) :
startupProbe:
httpGet:
path: /health
port: 9090
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 15Sécurité
Le serveur interne n'utilise aucune authentification par jeton bearer ; l'accès est contrôlé par l'adresse sur laquelle il se lie et par INTERNAL_ALLOW_IPS. Pour le protéger :
- Liez-le à localhost — un
INTERNAL_ADDRne comportant qu'un port (:9090) se lie déjà à127.0.0.1; un127.0.0.1:9090explicite maintient le port accessible uniquement depuis l'intérieur du conteneur ou de l'hôte - Définissez
INTERNAL_ALLOW_IPSlorsque l'écouteur doit être accessible hors de l'hôte — une liste d'autorisation CIDR/IP qui renvoie403sur/metrics,/configet les chemins de plugins aux pairs qui n'en font pas partie, tandis que les sondes de santé restent accessibles. Le loopback n'est pas implicite, incluez donc127.0.0.1/32si vous avez encore besoin d'un accès depuis localhost. Le serveur émet un avertissement au démarrage si l'écouteur est exposé hors de l'hôte sans liste d'autorisation définie - Ne l'exposez pas en tant que Service Kubernetes — déclarez le port comme un
containerPortmais ne créez pas de Service pour lui. Les sondes Kubernetes accèdent directement aux ports du conteneur - Utilisez des network policies — restreignez l'accès au niveau réseau si le port doit être exposé
L'endpoint /config révèle des détails opérationnels (document root, limites de débit, nombre de workers, valeurs des délais d'expiration). Les chemins TLS, internal_addr et error_pages_dir sont expurgés, mais demandez-vous si le reste devrait être accessible depuis l'extérieur du pod.
Exemple Docker
Pour un aperçu rapide, vous pouvez publier le port interne ; en production, liez le serveur interne à localhost et utilisez les sondes 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:9090Dépannage
Les endpoints de santé, de métriques et de configuration ne sont pas accessibles
INTERNAL_ADDR n'est pas défini.
Correction : Ajoutez la variable d'environnement :
INTERNAL_ADDR=0.0.0.0:9090/health renvoie 503 mais l'application fonctionne
Un plugin chargé signale PluginHealth::Failed. Vérifiez l'objet plugins dans la réponse de santé pour identifier le plugin défaillant :
curl -s http://localhost:9090/health | jq '.plugins'Impossible d'atteindre le serveur interne depuis l'extérieur du conteneur
Le serveur est lié à 127.0.0.1, qui n'est accessible que depuis l'intérieur du conteneur.
Correction : Passez à 0.0.0.0 pour un accès externe, ou utilisez des sondes Kubernetes qui accèdent directement au conteneur.
Les métriques n'affichent pas le mode worker ou les métriques async
Les métriques du mode worker n'apparaissent que lorsque le mode worker est activé (WORKER_MODE_ENABLED=true). Les métriques async n'apparaissent que lorsque ASYNC_WORKERS > 0 et qu'au moins une tâche a été distribuée ou rejetée.
Voir aussi
- Métriques — référence complète des métriques Prometheus
- Contrôles de santé — comportement détaillé des contrôles de santé
- Référence de configuration — toutes les variables d'environnement
- Arrêt gracieux — séquence d'arrêt et cycle de vie du serveur interne