Skip to content
← All posts

Launching Laravel Health

I released cboxdk/laravel-health today. Installed it on cbox.dk, opened the dashboard, and immediately found two bugs. The OS version showed "unknown" and my Hetzner VM was detected as a container. Dogfooding works.

· 5 min read · Sylvester Damgaard
Launching Laravel Health

I released cboxdk/laravel-health today. Health checks, Kubernetes probes, Prometheus metrics, and a live dashboard for Laravel applications. Built on top of System Metrics for the system-level data.

I installed it on this site, opened the dashboard, and immediately found two bugs.

The package

One composer require gives you:

  • /health - liveness probe (database connectivity)

  • /health/ready - readiness probe (database, cache, storage)

  • /health/metrics - Prometheus format with system metrics

  • /health/ui - live dashboard with auto-refresh

10 built-in checks (database, cache, queue, storage, Redis, CPU, memory, disk space, environment, schedule), token and IP-based auth, response caching, and an extensible architecture for custom checks. 113 tests, PHPStan level 9.

The bugs

I deployed it on cbox.dk, which runs on a Hetzner CAX arm64 VM with Ubuntu 24.04. Opened the dashboard and saw this:

Laravel Health dashboard showing OS version as unknown and environment incorrectly detected as Container on a Hetzner VM
The health dashboard on first deploy. OS version "unknown" and environment incorrectly showing "Container".

Two problems. OS version showing "unknown" when it should show "24.04". And environment showing "Container" when it's a plain VM.

Bug 1: OS version "unknown"

System Metrics reads /etc/os-release for OS information. On Ubuntu, that file exists and contains VERSION_ID="24.04". So why "unknown"?

The FileReader has a security whitelist for allowed paths. It also uses realpath() to resolve symlinks and re-validates the resolved path against the whitelist. On systemd distros, /etc/os-release is a symlink to /usr/lib/os-release. The whitelist had /etc/os-release but not /usr/lib/os-release. The read silently failed and fell through to the "unknown" fallback.

One-line fix: add /usr/lib/os-release to the whitelist.

Bug 2: VM detected as container

The container detection in System Metrics was checking if cgroup data existed. If the system had cgroup v1 or v2, it assumed container. But cgroup v2 is the default on modern Linux - Ubuntu 22.04+, Debian 12+, Fedora 31+ - even on bare metal. Every modern VM reports cgroup v2. That isn't the same as being in a container.

I went through three iterations before getting this right. First I tried checking PID 1's cgroup path, assuming root / means VM. On the Hetzner box, PID 1 is in /init.scope - not root. Then I added an exclusion for init.scope, but that's systemd-specific and wouldn't work on OpenRC, runit, or other init systems.

The correct approach: stop trying to prove a negative. Instead of "this doesn't look like a container," only detect containers by checking for known container indicators. An allowlist, not heuristics.

The final detection checks three things, in order of reliability:

  1. Sentinel files: /.dockerenv (Docker), /run/.containerenv (Podman)

  2. PID 1 environment: container= variable set by LXC and systemd-nspawn

  3. Cgroup keywords: kubepods, docker, containerd, crio, lxc in cgroup paths

No match means not a container. No heuristics, no exclusion lists, no edge cases to maintain.

Dogfooding

Both bugs were found within minutes of deploying on my own site. The OS detection bug had been there since v2.0 - over a year. Nobody reported it because the library worked correctly everywhere else: inside Docker containers (no symlink resolution needed for /proc files) and on macOS (different detection path entirely). It took running on a plain Linux VM to surface it.

The container detection bug was more fundamental. The assumption that "cgroup = container" was baked into the architecture. It required rethinking the detection strategy entirely, not just patching edge cases.

Both are fixed in system-metrics v2.3.1 and laravel-health v1.0.1. The dashboard now correctly shows Ubuntu 24.04.3 LTS, no container section, and environment "Host":

Laravel Health dashboard correctly showing Ubuntu 24.04.3 LTS with Host environment on Hetzner VM
After the fix. Ubuntu 24.04.3 LTS, version 24.04, environment "Host". No container section.

Install

bash
composer require cboxdk/laravel-health

Full documentation: laravel-health docs.