PHP cookbook · Beginner

Add health check endpoints to a PHP app

Let load balancers and Kubernetes know whether a PHP instance is alive and ready for traffic.

Approach

Expose two endpoints: a cheap liveness check (/healthz) that only confirms PHP is responding, and a readiness check (/readyz) that verifies critical dependencies (database, cache) with short timeouts. Return JSON with status per dependency and 503 when not ready. Exclude them from auth and access logs.

Solution

<?php
declare(strict_types=1);

if ($_SERVER['REQUEST_URI'] === '/healthz') {
    header('Content-Type: application/json');
    echo '{"status":"ok"}';
    exit;
}

if ($_SERVER['REQUEST_URI'] === '/readyz') {
    $checks = [];
    try {
        $pdo = new PDO(getenv('DB_DSN'), getenv('DB_USER'), getenv('DB_PASSWORD'), [PDO::ATTR_TIMEOUT => 2, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
        $pdo->query('SELECT 1');
        $checks['database'] = 'ok';
    } catch (Throwable) {
        $checks['database'] = 'fail';
    }
    try {
        $redis = new Redis();
        $redis->connect(getenv('REDIS_HOST'), 6379, 1.0);
        $checks['redis'] = $redis->ping() ? 'ok' : 'fail';
    } catch (Throwable) {
        $checks['redis'] = 'fail';
    }
    $ready = !in_array('fail', $checks, true);
    http_response_code($ready ? 200 : 503);
    header('Content-Type: application/json');
    echo json_encode(['status' => $ready ? 'ready' : 'not_ready', 'checks' => $checks]);
    exit;
}

Pitfalls

  • Liveness depending on the database (an outage restarts every pod).
  • Slow checks without timeouts making probes fail.
  • Leaking internal hostnames or errors in health responses.

Variations

  • PHP-FPM's own ping.path and pm.status_path for process-level checks.
  • Laravel 11+: built-in /up route.

Further reading: Kubernetes: Configure probes

Reference: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

More PHP recipes