Health Check
Every instance answers a public health endpoint, so a monitor can tell whether it is really working rather than merely running.
GET /api/health
It needs no authentication and no key, because it says nothing worth protecting: two words about the instance and nothing about what is on it.
{ "status": "ok", "database": "ok" }
That is a 200. If the database cannot be reached the answer is a 503:
{ "status": "error", "database": "unreachable" }
While the server is still starting — applying migrations after an update,
creating the first administrator from the environment — it answers 503 too:
{ "status": "starting" }
The process is listening by then and would answer other requests, but against a
database that is still being changed. A monitor or a load balancer that waits for
the 200 sends nobody there too early. If the migrations fail, it answers
{ "status": "error" } and stays that way until the server is restarted; the
reason is in the log.
The check is not a ping. It runs a SELECT 1 against the database before
answering, which catches the failure that matters and that a plain HTTP check
misses entirely: the process is alive, the port is open, and every page is
broken because the database went away underneath it.
Nothing about the failure reaches the caller — no host, no driver message, no stack. The reason is in your server log.
Docker
The published image already declares its own HEALTHCHECK against this
endpoint, so a container reports its state without you configuring anything:
docker ps
# STATUS Up 2 minutes (healthy)
It probes every 30 seconds and gives the container 90 seconds to start before the first probe counts — enough for the server to boot and apply any outstanding migrations, so a slow first start is not mistaken for a broken one. Three consecutive failures mark it unhealthy.
The probe uses Node's own fetch, so nothing extra — no curl, no wget —
has to be installed in the image for it.
Docker Compose
Compose picks the image's health check up on its own. It is also what to hang a dependency on, so something that needs LokalBoards does not start against a server whose database is not up yet:
services:
app:
image: florianstrasser/lokalboards:latest
# ...
reverse-proxy:
depends_on:
app:
condition: service_healthy
Uptime monitoring
Point whatever you use — UptimeRobot, Better Stack, a Kubernetes readiness
probe, a load balancer — at https://boards.example.com/api/health and treat
anything other than 200 as down.
For a load balancer this is the right endpoint to poll rather than the homepage: an instance that cannot reach its database drops out of rotation instead of serving errors to whoever lands on it.