Opyntel

Why a Docker container keeps restarting, and how to find the cause

A container keeps restarting because its main process exits and the restart policy starts it again. Docker waits a little longer before each try, so the loop can run for hours without anyone noticing. The exit code usually tells you which cause you have.

Run docker ps -a to see the status, docker inspect for the exit code and restart count, and docker logs for the last lines before the exit.

Confirm the loop

bash
docker ps -a --filter name=myapp
docker inspect -f '{{.RestartCount}} {{.State.ExitCode}} {{.State.OOMKilled}}' myapp
docker logs --tail 100 myapp

A status of Restarting (1) 5 seconds ago and a growing RestartCount mean the container is looping. OOMKilled set to true means the kernel killed it for memory.

Read the exit code

Exit codeMeaningUsual cause
0The process finishedA one-off task under restart: always, or an app that went to the background so the shell exited
1Application errorA missing env var, bad config, a failed migration or a crash on boot
126 / 127Command not runnable / not foundA wrong CMD or entrypoint, a missing binary, a script without execute permission or with Windows line endings
137Killed (SIGKILL)Out of memory, or a stop that ran past its grace period
139Segmentation faultA bug in a native module, or a library built for another libc (musl or glibc)
143Terminated (SIGTERM)A stop that the app handled, or a liveness probe that failed on Kubernetes

Exit code 137 has its own guide: exit code 137 and OOM killed.

Fix the common causes

  • A crash on start. The last log lines show the error. Start the image with a shell (docker run -it --entrypoint sh myimage) and run the command by hand.
  • Out of memory. Compare memory use with the container’s limit. Raise the limit, or look for a leak if memory climbs steadily before each restart.
  • The wrong port or address. The app starts but listens on 127.0.0.1 instead of 0.0.0.0, or on another port. Docker itself keeps such a container running, but a platform health check or a Kubernetes liveness probe fails and restarts it.
  • A dependency that is not ready. The app exits when the database is not up yet. Retry the connection in the app, or use depends_on with condition: service_healthy in Compose.
  • The wrong restart policy. A container that is meant to finish should not run under always or unless-stopped.

Docker restart policies

PolicyRestarts the container when
noNever. This is the default.
on-failure[:N]It exits with a code other than 0, up to N times
alwaysIt exits for any reason, and when the Docker daemon starts
unless-stoppedLike always, except after you stopped it yourself

Docker doubles the wait between restarts, starting at 100 milliseconds. The wait goes back to 100 milliseconds once the container stays up for 10 seconds.

Kubernetes: “Back-off restarting failed container”

This is the Kubernetes event behind the CrashLoopBackOff status. The pod’s container keeps exiting, and Kubernetes waits longer before each restart, up to five minutes. The causes are the same as above.

bash
kubectl describe pod <pod>
kubectl logs <pod> --previous

describe shows the last exit code and its reason, such as OOMKilled or Error. logs --previous shows the logs of the run that crashed, not the one that just started.

On an app platform or self-hosted PaaS

App platforms restart a crashed service the same way, each with its own limits and its own place to look. Each platform has its own guide: Railway service keeps restarting, Render service keeps restarting and Fly.io Machine keeps restarting.

On Coolify, the application’s Logs show the error before each exit, and Sentinel’s memory chart shows an out-of-memory climb. Coolify stops the resource once it reaches its restart limit. It notifies on status changes and on the restart limit, but keeps no history of restarts next to memory.

On Dokploy, containers follow the Docker restart policy. Dokploy alerts on CPU and memory for the whole server, but not when a container restarts.

How Opyntel catches a restart loop

Docker tells no one that a container restarted. The Opyntel agent runs on your server with one docker run and reports CPU, memory and restart counts for every container. Opyntel also reads the restart count of every Coolify application and database.

Restarts land on one activity timeline next to memory, so you can tell an out-of-memory loop from a crash on boot. When a container restarts more often than your threshold, or goes down, Opyntel alerts you by email, Slack or SMS depending on your plan. Your Railway, Render, Fly.io and Coolify services sit in the same table, in one dashboard.

FAQ

Container restart questions, answered

Restart loops, restart policies and CrashLoopBackOff.

Run docker inspect for the exit code, the OOMKilled flag and the restart count, then docker logs for the last lines before the exit.

Run docker update --restart=no <container> and then docker stop. In Compose, change restart in the service and run docker compose up -d again.

The process finished normally and the restart policy is always or unless-stopped. Run one-off tasks without a restart policy, and keep servers in the foreground.

Kubernetes is restarting a container that keeps exiting, and waits longer before each try. It is the event behind the CrashLoopBackOff status.

Docker sends no notification. You need a tool that reads the restart count and alerts on it, such as the Opyntel agent.

The alerts your platform doesn’t send.

One dashboard for everything you run, with the alerts your platforms leave out. Read-only, nothing to install in your apps.

See how it works