Serwer wewnętrzny

OxPHP uruchamia osobny serwer HTTP na dedykowanym porcie do kontroli stanu, metryk Prometheus oraz podglądu aktywnej konfiguracji. Pozostaje całkowicie odizolowany od głównego listenera aplikacji: bez TLS, bez ograniczania liczby żądań, bez ID żądań i bez przetwarzania zdarzeń.

Jak to działa

Ustaw INTERNAL_ADDR na adres nasłuchu (np. 127.0.0.1:9090), a OxPHP uruchomi drugi listener HTTP pod tym adresem. Serwer wewnętrzny udostępnia wbudowane endpointy wymienione poniżej:

  • /health — zbiorczy status w formacie JSON
  • /health/liveness, /healthz (alias) — sonda liveness
  • /health/readiness, /readyz (alias) — sonda readiness
  • /health/startup, /startupz (alias) — sonda startup
  • /metrics — ekspozycja Prometheus
  • /config — aktywna konfiguracja serwera w formacie JSON

Wtyczki mogą rejestrować dodatkowe endpointy pod prefiksem /__<plugin>/. Podczas łagodnego zamknięcia serwer wewnętrzny pozostaje dostępny, dopóki główny serwer nie zakończy opróżniania połączeń.

Note

Serwer wewnętrzny uruchamia się tylko wtedy, gdy INTERNAL_ADDR jest jawnie ustawiony. Bez niego endpointy health, metrics i config nie są dostępne przez HTTP.

Konfiguracja

Zmienna Wartość domyślna Opis
INTERNAL_ADDR (nieustawione) Adres serwera wewnętrznego. Nie uruchamia się, gdy nieustawiony. Wartość zawierająca tylko port (:9090 lub 9090) wiąże się z 127.0.0.1; użyj jawnego 0.0.0.0:9090, aby udostępnić go poza hostem. Przykład: 127.0.0.1:9090
INTERNAL_ALLOW_IPS (nieustawione) Lista dozwolonych adresów CIDR/IP rozdzielona przecinkami. Hosty spoza listy otrzymują 403 na ścieżkach /metrics, /config oraz /__<plugin>/; sondy stanu pozostają zawsze osiągalne. Nieustawione/puste = zezwól na wszystkie. Loopback nie jest domyślnie uwzględniony — wpisz 127.0.0.1/32, aby zachować dostęp z localhost. Nieprawidłowa lista przerywa uruchamianie

Endpointy

GET /health

Zwraca status stanu w formacie JSON. Używaj go dla sond readiness i liveness w Kubernetes.

200 OK — wszystkie systemy sprawne:

json
{ "status": "ok", "uptime_secs": 3612, "total_requests": 48203, "active_connections": 7, "executor_healthy": true, "plugins": { "otel": "ok" } }

503 Service Unavailable — wtyczka zgłosiła awarię:

json
{ "status": "degraded", "uptime_secs": 3612, "total_requests": 48203, "active_connections": 7, "executor_healthy": true, "plugins": { "otel": "failed" } }

Obiekt plugins wymienia każdą załadowaną wtyczkę wraz z jej statusem stanu: "ok", "degraded" lub "failed". Endpoint zwraca 503, gdy dowolna wtyczka zgłasza "failed" lub gdy executor skryptów jest niesprawny (executor_healthy: false). Wtyczki "degraded" pojawiają się w ciele JSON, ale status HTTP pozostaje 200.

GET /metrics

Zwraca metryki zgodne z Prometheus w formacie tekstowym (text/plain; version=0.0.4; charset=utf-8). Zawsze zwraca 200.

bash
curl http://localhost:9090/metrics
text
# 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 ...

Pełną listę dostępnych metryk znajdziesz w Metryki.

GET /config

Zwraca aktywną konfigurację serwera w formacie JSON. Zawsze zwraca 200.

bash
curl -s http://localhost:9090/config | jq .
json
{ "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": {} }

Ścieżki do certyfikatu i klucza TLS nigdy nie są ujawniane (udostępniana jest tylko wartość logiczna tls_enabled), a internal_addr oraz error_pages_dir są usuwane z serwowanej odpowiedzi — to topologia wdrożenia i ścieżki w systemie plików, które pomagają atakującemu, a nie są potrzebne scraperom.

Endpointy wtyczek

Wtyczki mogą rejestrować własne endpointy pod prefiksem /__<plugin_name>/. Na przykład wtyczka o nazwie otel mogłaby udostępniać /__otel/status. Te endpointy są dostępne tylko wtedy, gdy odpowiednia wtyczka jest załadowana i zarejestrowała handler.

Każda ścieżka niepasująca do wbudowanego endpointu ani do endpointu wtyczki zwraca 404 Not Found.

Integracja z Kubernetes

Sonda readiness

Użyj /health, aby kontrolować, czy Kubernetes kieruje ruch do poda:

yaml
readinessProbe: httpGet: path: /health port: 9090 initialDelaySeconds: 2 periodSeconds: 5

Gdy /health zwraca 503, Kubernetes usuwa poda z listy endpointów Service. Ruch wznawia się, gdy endpoint ponownie zwróci 200.

Sonda liveness

Użyj tego samego endpointu, aby restartować pody, które przestają odpowiadać:

yaml
livenessProbe: httpGet: path: /health port: 9090 initialDelaySeconds: 5 periodSeconds: 10 failureThreshold: 3

Sonda startup

Dla aplikacji z wolnym rozruchem (duże frameworki, ciężkie autoloadery):

yaml
startupProbe: httpGet: path: /health port: 9090 initialDelaySeconds: 1 periodSeconds: 2 failureThreshold: 15

Bezpieczeństwo

Serwer wewnętrzny nie ma uwierzytelniania za pomocą tokenu bearer; dostęp jest kontrolowany przez to, gdzie się wiąże, oraz przez INTERNAL_ALLOW_IPS. Aby go zabezpieczyć:

  • Powiąż z localhostINTERNAL_ADDR zawierający tylko port (:9090) już wiąże się z 127.0.0.1; jawne 127.0.0.1:9090 sprawia, że port jest osiągalny tylko z wnętrza kontenera lub hosta
  • Ustaw INTERNAL_ALLOW_IPS, gdy listener musi być osiągalny poza hostem — lista dozwolonych adresów CIDR/IP, która zwraca 403 na ścieżkach /metrics, /config oraz ścieżkach wtyczek hostom spoza niej, podczas gdy sondy stanu pozostają osiągalne. Loopback nie jest domyślnie uwzględniony, więc dodaj 127.0.0.1/32, jeśli nadal potrzebujesz dostępu z localhost. Serwer ostrzega przy uruchamianiu, jeśli listener jest wystawiony poza hostem bez ustawionej listy dozwolonych
  • Nie udostępniaj jako Service w Kubernetes — zadeklaruj port jako containerPort, ale nie twórz dla niego Service. Sondy Kubernetes mają bezpośredni dostęp do portów kontenera
  • Używaj polityk sieciowych — ogranicz dostęp na warstwie sieciowej, jeśli port musi być wystawiony
Warning

Endpoint /config ujawnia szczegóły operacyjne (document root, limity liczby żądań, liczby workerów, wartości limitów czasu). Ścieżki TLS, internal_addr oraz error_pages_dir są usuwane, ale zastanów się, czy reszta powinna być dostępna spoza poda.

Przykład Docker

Aby szybko rzucić okiem, możesz opublikować port wewnętrzny; w środowisku produkcyjnym powiąż serwer wewnętrzny z localhost i korzystaj z sond Kubernetes.

compose.yaml
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:9090

Rozwiązywanie problemów

Endpointy health, metrics i config są niedostępne

INTERNAL_ADDR nie jest ustawiony.

Rozwiązanie: Dodaj zmienną środowiskową:

bash
INTERNAL_ADDR=0.0.0.0:9090
/health zwraca 503, ale aplikacja działa

Załadowana wtyczka zgłasza PluginHealth::Failed. Sprawdź obiekt plugins w odpowiedzi health, aby zidentyfikować, która wtyczka zawodzi:

bash
curl -s http://localhost:9090/health | jq '.plugins'
Nie można połączyć się z serwerem wewnętrznym spoza kontenera

Serwer jest powiązany z 127.0.0.1, który jest dostępny tylko z wnętrza kontenera.

Rozwiązanie: Zmień na 0.0.0.0 dla dostępu z zewnątrz lub użyj sond Kubernetes, które mają bezpośredni dostęp do kontenera.

Metryki nie pokazują metryk trybu worker ani async

Metryki trybu worker pojawiają się tylko wtedy, gdy tryb worker jest włączony (WORKER_MODE_ENABLED=true). Metryki async pojawiają się tylko wtedy, gdy ASYNC_WORKERS > 0 i co najmniej jedno zadanie zostało wysłane lub odrzucone.

Zobacz też