Traefik Health Check: Ping, Backends and the Edge
A traefik health check means two different things: the proxy's own ping endpoint and the backend checks that drain a server. Here is how to wire both.
Ask five people about a traefik health check and you get two different answers. One group means the proxy's own liveness, exposed at /ping and wrapped by the traefik healthcheck command. The other means the per-backend checks that pull a failing server out of the load balancing rotation. They are separate features, configured in separate places.
Which traefik health check do you mean?
The two layers answer different questions and neither substitutes for the other. The ping endpoint says the proxy process is alive and accepting connections. The service health check says a particular backend behind the proxy is still worth sending requests to.
| Layer | Configured in | Answers | Failure behaviour |
|---|---|---|---|
| Ping endpoint | Static configuration | Is Traefik itself alive? | The container orchestrator restarts the proxy |
| Service health check | Dynamic configuration or labels | Is this backend usable? | Traefik stops routing to that server |
| External probe | Outside your infrastructure | Can a user reach the site? | An alert reaches a human |
Most of the confused forum threads come from expecting one layer to do the job of another. A restarted proxy will not fix a dead backend, and a drained backend will not fix an expired certificate at the edge.
Enabling the ping entrypoint
Ping is off by default. Turn it on in the static configuration and give it a dedicated entrypoint so it never appears on port 443:
# traefik.yml
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
traefik:
address: ":8080"
ping:
entryPoint: "traefik"
terminatingStatusCode: 503
GET :8080/ping now returns 200 with the body OK. The terminatingStatusCode field is the interesting one. During a graceful shutdown, ping switches to that code so an upstream load balancer drains connections before the process exits. Traefik's health check reference documents both halves.
Running the CLI command inside the container
Traefik's official image carries no shell tooling, so the usual curl or wget healthcheck line fails outright. Use the built-in subcommand instead:
services:
traefik:
image: traefik:v3.5
command:
- "--ping=true"
- "--ping.entryPoint=traefik"
- "--entryPoints.traefik.address=:8080"
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 15s
The error people hit is "you need to enable ping". The subcommand reads your static configuration and calls the ping endpoint itself, so it fails when ping is not enabled in the same place. Passing --ping to the healthcheck alone does not switch the feature on for the running server. Docker's HEALTHCHECK reference covers the surrounding fields.
Pulling unhealthy backends out of rotation
The second layer lives on the service, not the router. With the Docker provider it is a set of labels on the application container:
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.services.api.loadbalancer.server.port=8000"
- "traefik.http.services.api.loadbalancer.healthcheck.path=/healthz"
- "traefik.http.services.api.loadbalancer.healthcheck.interval=10s"
- "traefik.http.services.api.loadbalancer.healthcheck.timeout=3s"
Traefik treats any 2xx or 3xx reply as healthy unless you pin an expected code. Point the path at a cheap dependency check, not at your home page, and keep the timeout well under the interval. The services documentation lists every option, including the scheme, hostname and header overrides.
One label is worth adding early. Setting healthcheck.hostname makes Traefik send a Host header the backend recognises, which matters when the application refuses requests for unknown hosts. Without it the check arrives with the container IP as the host and gets a 404 or a redirect, and Traefik drains a server that was perfectly fine.
Kubernetes users get this layer twice over. A readiness probe already removes a pod from the Service endpoints, so a Traefik service check on top of it is usually redundant. Pick one and document which, because two independent drain mechanisms make a partial outage very hard to read.
What happens when every server fails its check?
Traefik answers 503 Service Unavailable. There is no last-resort behaviour that keeps sending traffic to a server that failed its check, which surprises teams migrating from other proxies. A health endpoint that is stricter than it needs to be can therefore take the whole service down on its own.
We prefer a deliberately narrow backend check for this reason. Verify the database connection and nothing else, and leave the broker, object storage and third-party APIs to their own alerts. A Redis health probe belongs in that second category, since a cold cache degrades a service rather than breaking it.
Checking the edge from the public internet
Both layers run on the machine that fails. When the host disappears, or DNS moves, or the certificate expires, nothing inside the cluster is left to notice. A check that begins on the open internet is the layer that survives:
curl -X POST https://uptimeroom.com/api/v1/monitors \
-H "Authorization: Bearer urm_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "edge router api.example.com",
"type": "http",
"target": "https://api.example.com/healthz",
"intervalSec": 30,
"expectedStatus": [200],
"regions": ["london", "singapore"]
}'
Send it to the public hostname rather than the container IP. That path exercises your DNS record, the TLS certificate, the router rule and the backend in one request, which is the whole point. Thirty-second intervals need a paid plan as of September 2026, and the pricing page lists the interval for each tier. Probe egress addresses for any firewall allowlist are on the probe IP page, and the request fields are in the API reference.
Run it from more than one region. A routing problem at one transit provider looks exactly like an outage from a single vantage point, which is the argument blackbox monitoring makes in more detail.
Where these checks mislead you
Exposing the ping entrypoint publicly. Bind it to an internal address or a port your firewall blocks. It confirms the proxy is alive to anyone who asks, which is free reconnaissance.
Pointing the backend check at a page that loads everything. Each server gets hit every interval. A check that renders a dashboard turns your health endpoint into your heaviest route.
Trusting a green proxy. The ping endpoint answers fine while every router rule is broken by a bad label. Only a request through the real hostname proves routing still works.
Leaving the interval and timeout equal. A backend check with a three second interval and a three second timeout has no slack at all. One slow response and the server is drained, which shifts load onto its neighbours and makes them slow too.
A traefik health check is really three checks. Ping covers the proxy, load balancer checks cover the backends, and an external probe covers everything the first two cannot see. Set up the first two in your configuration, then add the outside view. You can start on the free plan, which covers 10 monitors at a one-minute interval as of September 2026.
FAQ
It is /ping, and it is disabled until you enable the ping feature in the static configuration. Once enabled it returns 200 with the body OK while the proxy is serving. Bind it to its own entrypoint on an internal port so it is not reachable from the public internet alongside your real routes.
The official image has no curl or wget, so use the binary's own subcommand: test set to CMD with traefik, healthcheck and --ping. Give it a ten second interval, a short timeout, three retries and a start period, and make sure ping is enabled in the server configuration as well.
The healthcheck subcommand reads the same static configuration the server uses and then calls the ping endpoint. Passing the flag to the subcommand does not enable the feature on the running proxy. Add ping to the static file or pass --ping=true in the server command, then the check succeeds.
It returns 503 Service Unavailable to the client. Traefik does not keep a last-resort server in rotation, so an overly strict backend check can take the whole service offline by itself. Keep the checked path narrow, covering only the dependencies a request genuinely cannot proceed without.
No. Both the ping endpoint and the load balancer checks run on the same host as the proxy, so they vanish with it. They also see nothing about DNS records, certificate expiry or router rules that stopped matching. Those failures need a probe that starts outside your infrastructure.
Related reading
- Redis Health Check: PING, Compose and the Lies - A redis health check built on PING alone misses eviction, replication and failed saves. Here is the compose config and the probe that catch them.
- Blackbox Monitoring: What the Outside View Sees - Blackbox monitoring tests a service from outside with no access to its internals, which is how you catch DNS, TLS and routing failures.