Why Does a Container Health Check Fail While the App Still Opens?

Eva Wong is the Technical Writer and resident tinkerer at ZimaSpace. A lifelong geek with a passion for homelabs and open-source software, she specializes in translating complex technical concepts into accessible, hands-on guides. Eva believes that self-hosting should be fun, not intimidating. Through her tutorials, she empowers the community to demystify hardware setups, from building their first NAS to mastering Docker containers.

A container can remain usable while its health check fails because the probe tests a different command, address, user, or readiness condition than the path your browser uses.

On a home server, the app may open through a reverse proxy even though Docker runs the health command inside the container against localhost, a missing utility, the wrong port, or a dependency that is temporarily unavailable. Start by reproducing the exact probe inside the container, then compare its target and expected result with the real user path before increasing retries or disabling the health check.

Compare What the Browser Tests With What the Health Check Tests

Record the URL and network path that successfully open the application. Note whether the browser reaches a reverse proxy, a published host port, a local IP, or the container directly.

Docker executes the configured probe inside the container, so it may test a different endpoint than the browser. A Docker community case showed a health check failing because the image did not contain the curl command used by the probe even though the service process itself could still run.

If the successful browser path passes through another proxy or port, do not treat that result as proof that the internal probe target is correct. Write down both paths and identify the first component that differs.

Run the Exact Health Command Inside the Container

Copy the health-check command exactly, including its shell form, URL, flags, credentials, and environment variables. Execute it inside the running container as the same user and capture the exit code and output.

A container marked unhealthy can still have a running process because health status reflects the probe result, not whether users can load one page. Netdata’s diagnostic workflow distinguishes probe failure from process failure before changing restart behavior.

If the command succeeds manually, compare the execution user, shell, working directory, environment, and timing used by the automatic check. If it fails manually, the error now identifies the next layer without waiting for another health interval.

Check the Probe Tool, Shell, PATH, and User

Confirm that every executable in the health command exists inside the current image and can be run by the container user. Minimal images may omit curl, wget, bash, DNS tools, or certificate stores.

Shell-form and exec-form probes behave differently. Quoting, pipes, variable expansion, and compound commands require an available shell, while a direct command needs the full executable path when the health-check environment has a limited PATH.

Run the command with an absolute path and the intended service user. Fix the image or probe rather than installing tools interactively, because a manual container change disappears after the next rebuild.

Verify the Internal Address, Port, and Protocol

Inspect the application listener inside the container and compare it with the probe URL. A published host port such as 8080:80 does not mean the service listens on port 8080 inside the container.

Health checks should test the application state the container controls. Dash0’s practical guide notes that a probe may call an HTTP endpoint or inspect a process, but the endpoint must reflect the actual container readiness state rather than a route available only through an external proxy.

Test 127.0.0.1, the container listener address, and the service name only where each is appropriate. If the app binds only to a Unix socket or another interface, change the probe to the real internal entry point.

Separate Slow Startup From a Permanent Failure

Measure how long the application, database migration, cache warm-up, or model load takes before the correct endpoint responds. Compare that time with start_period, interval, timeout, and retries.

Compose can block dependent services when a dependency is still marked unhealthy even though it later becomes ready. A reported Compose regression showed a service becoming healthy only after the dependency failure had already stopped the stack, exposing an overly narrow health-check startup window.

Increase timing only when logs prove the app is making normal progress. Longer retries should not hide a bad port, failed migration, missing certificate, or unreachable database.

Keep the Probe Narrow and Verify Recovery

Decide whether the health check should represent process liveness, local application readiness, or a deeper dependency chain. Do not make a local container unhealthy merely because an optional external API is unavailable.

The ZimaSpace guide to finding the first failed dependency is the next step when the application itself cannot become ready without a database, cache, or network service.

The issue is resolved when the exact automatic probe succeeds after normal startup, the container stays healthy through dependency restarts, and the real app workflow remains available. Keep the probe strict enough to detect a broken service but narrow enough to avoid false failures from unrelated systems.

Support & Tips

More to Read

Get More Builds Like This

Stay in the Loop

Get updates from Zima - new products, exclusive deals, and real builds from the community.

Stay in the Loop preferences

We respect your inbox. Unsubscribe anytime.