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.