Skip to main content
Why Your Docker Container Exits Immediately (and How to Fix It)

Why Your Docker Container Exits Immediately (and How to Fix It)

KU
• 7 min read•Updated •51 views

You run the container, check docker ps, and it's already gone. Nine times out of ten it's PID 1 doing its job. Here's how to read it.

Key takeaways

  • A Docker container runs only as long as its PID 1 process.
  • If it exits immediately, your CMD finished, daemonized itself, or crashed.
  • Run docker ps -a to read the exit code (0 finished, 127 command not found, 137 killed), then docker logs for the reason, and keep the main process in the foreground.

A Docker container exits immediately because its PID 1 process ended: the command finished, forked into the background, or crashed. Read the exit code with docker ps -a, read the reason with docker logs, and keep your main process in the foreground (for nginx, daemon off;).

You run docker run my-image, the prompt comes back, then you check:

bash.bash
docker ps -a
CONTAINER ID   IMAGE      STATUS                     NAMES
a1b2c3d4e5f6   my-image   Exited (0) 2 seconds ago   sleepy_hopper

Gone. The confusing part is that Exited (0) means success. Nothing crashed. The container did exactly what you told it to; that just took two seconds.

The one rule that explains all of this

A container lives exactly as long as its PID 1. That's it. When you start a container, Docker runs your CMD (or ENTRYPOINT) as process ID 1 inside the namespace. When that process exits, the container stops. There is no background. There is no "keep it warm." PID 1 returns, the container is dead, exit code and all.

So the question is never "why did my container stop?" It's "why did PID 1 finish?"

Cause 1: your main process actually finished

This is Exited (0) land. Your CMD ran a command that completes and returns.

dockerfile.dockerfile
CMD ["python", "setup_db.py"]

That script sets up a schema and exits. Container's done its job, so it stops. Same thing if your CMD is echo hello or ls or a one-shot migration. People hit this constantly with base images: docker run ubuntu exits instantly because the default command is bash, and with no TTY attached bash has no input, reaches EOF, and returns.

The fix depends on intent. If it was supposed to be a one-shot job, congratulations, it worked. If you wanted a service, you need a process that stays in the foreground and doesn't return until you kill it:

dockerfile.dockerfile
CMD ["python", "app.py"]        # app.py runs a server loop, blocks forever

Cause 2: the app daemonizes itself

This one is sneaky because the process is a "server," but it forks a background copy and the foreground one exits. PID 1 returned, so the container dies even though the daemon technically started.

nginx is the classic. By default it backgrounds itself. You have to tell it not to:

dockerfile.dockerfile
CMD ["nginx", "-g", "daemon off;"]

Apache wants httpd -D FOREGROUND. Anything you'd normally run with a -d flag or a start subcommand is suspect. The rule: never let a process inside a container background itself. Docker is your process manager now; don't reach for systemd inside a container to work around this.

Cause 3: nonzero exit, meaning it crashed

Exited (1), Exited (127), Exited (137). Now it's failing, and the answer is in the logs:

bash.bash
docker logs sleepy_hopper
docker inspect --format '{{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}' sleepy_hopper

A few codes carry meaning on their own. Docker's run reference (checked October 2026) defines 125, 126, and 127; any other code is your process's own:

Exit codeMeaningFirst thing to check
0PID 1 finished successfullyOne-shot CMD or a daemonizing process
1, 2Generic application errordocker logs
125Error in the Docker daemon or docker run itselfBad flag, name clash, invalid option
126Command found but can't be invokedMissing execute bit on the entrypoint script
127Command not foundTypo in CMD, binary not in image, wrong PATH
137128 + 9, SIGKILLOOMKilled: true, or a docker stop timeout
139128 + 11, SIGSEGVNative crash, often an architecture or libc mismatch

We've watched people rebuild an image five times chasing a 127 that one docker logs would have named. Read the logs first.

Cause 4: wrong CMD or ENTRYPOINT, or missing a TTY

Sometimes the image is fine and the invocation is wrong. If you want an interactive shell, you have to actually attach one:

bash.bash
docker run -it ubuntu bash     # -i keeps stdin open, -t gives a tty

Without -it, bash sees no input and exits immediately. That Exited (0) from docker run ubuntu earlier was exactly this.

When you're not sure what the image even tries to run, override the entrypoint and poke around from the inside:

bash.bash
docker run -it --entrypoint sh my-image
# now you're in the container's filesystem, run the CMD by hand and watch it fail

This is the highest-value move on the list: you see the actual error instead of guessing at a container that's already gone.

Cause 5: shell form vs exec form, and signals

This one doesn't kill the container on startup, it bites you later, but it belongs here because it's the same PID 1 story. Compare:

dockerfile.dockerfile
CMD python app.py               # shell form: runs `/bin/sh -c "python app.py"`
CMD ["python", "app.py"]        # exec form: python is PID 1 directly

In shell form, PID 1 is sh, and your app is a child. Docker's Dockerfile reference is blunt: shell form runs as a subcommand of /bin/sh -c, "which does not pass signals." On docker stop, the SIGTERM never reaches your app. Your app never hears the shutdown, gets a hard SIGKILL ten seconds later, and you get ungraceful exits and Exited (137) on shutdown. Use exec form (the JSON array) so your process is PID 1 and receives signals directly. If your app genuinely needs to reap child processes, add a tiny init with docker run --init rather than reaching for a shell wrapper.

The debugging loop, start to finish

When a container won't stay up, this is the order:

bash.bash
docker ps -a                    # exit code: 0 = finished, nonzero = crashed
docker logs <container>         # what it printed before dying
docker run --rm my-image        # run in the foreground, no -d, watch it live
docker run -it --entrypoint sh my-image   # go inside, run CMD by hand

Ninety percent get solved at step two. For the wider map of Docker failures, our Docker troubleshooting guide covers the rest of the usual suspects.

Questions people ask

Why does a Docker container stop when its main process exits?

Because the container is that process. Docker starts your ENTRYPOINT or CMD as PID 1 in a new namespace, and when PID 1 returns, the namespace has nothing left to run, so the container stops with that process's exit code. Background children don't count. Keep the main process in the foreground and the container stays up.

Why does docker run ubuntu exit immediately?

The ubuntu image's default command is bash. Started without a terminal, bash reads empty stdin, hits end-of-file, and exits with code 0, so the container stops at once. Run docker run -it ubuntu bash for an interactive shell, or give it a long-running command such as sleep infinity if you only need the container alive to docker exec into.

How do I keep a Docker container running?

Run a process that never returns in the foreground: your server with its foreground flag (nginx -g 'daemon off;', httpd -D FOREGROUND), declared in exec form so it is PID 1. Avoid tail -f /dev/null hacks in production images; they keep the container alive while the real service is dead, which hides failures from restart policies and health checks.

The call we'd make

Before touching the Dockerfile, run docker ps -a and docker logs. Read the exit code as a sentence: 0 means your process finished, nonzero means it broke, 137 means something killed it. If it's a service that dies on 0, you have a backgrounding or one-shot-command problem, so pin the process to the foreground. Use exec-form CMD so signals land where they should. And keep docker run -it --entrypoint sh in your muscle memory, because a container you can walk around inside is worth ten you can only stare at in ps -a.

Sources

Explore topics:DockerDevOps
React
Share this post
KU

Kiril Urbonas

AI Engineer

553 articles
View all articles by Kiril Urbonas

You might have missed

Evergreen posts worth revisiting.