Docker Container Won't Start? A Debugging Checklist
A Docker container not starting almost always comes down to one thing: the process inside died. Run docker ps -a to find its exit code, then docker logs <container> to see why. Nine times out of ten the answer is right there in the logs: a missing environment variable, a port already in use, a bad command, or a file the container can't read. The rest of this page walks through the checks in the order that finds the problem fastest.
First, figure out what "won't start" means
"Won't start" covers a few different failures, and they need different fixes. Before you change anything, run:
docker ps -a
The -a matters. docker ps alone only shows running containers, so a crashed one looks like it vanished. Look at the STATUS column:
Exited (0): the container ran and finished cleanly. If you expected a long-running service, your main process isn't staying alive (more on that below).Exited (1)or any non-zero code: the process inside crashed. Go read the logs.Restarting (1)looping: the container starts, dies, and the restart policy keeps retrying. Same root cause as a non-zero exit, just noisier.Createdbut neverUp: Docker couldn't even start the process. Usually a badcommand, a missing binary, or a volume mount that failed.
The exit code is your first clue. Write it down.
Read the logs (this is where most answers live)
docker logs <container_name_or_id>
If the container is restart-looping and the logs scroll past too fast, tail them and add timestamps:
docker logs --tail 50 --timestamps <container>
Most real failures announce themselves here. Some patterns you'll see over and over:
bind: address already in use: the host port is taken.no such file or directoryon startup: usually a wrongENTRYPOINT/CMDpath or a script without execute permission.permission denied: the container user can't read a mounted file or write to a volume.- An application stack trace: the app started, then threw. That's a config or dependency problem, not a Docker problem.
If docker logs is empty, the process died before it wrote anything, or it logs to a file inside the container instead of stdout. Try running it interactively (covered further down) to see the output directly.
Docker container not starting: the common causes, roughly by frequency
1. Port already in use
If the logs mention a port bind failure, something else on the host owns that port. Find it:
sudo lsof -i :8080
# or
sudo ss -ltnp | grep :8080
Either stop whatever is holding the port, or map your container to a different host port. In a compose file:
ports:
- "8081:8080" # host:container
2. A required environment variable is missing
Apps that expect a DATABASE_URL or an API key often crash immediately without one. Check what you actually passed in:
docker inspect <container> --format '{{json .Config.Env}}' | tr ',' '\n'
Compare that against what the image expects. A typo in an env var name is invisible until you print the list and read it.
3. The main process exits immediately (Exited 0)
Containers stay alive only as long as PID 1 keeps running. If your CMD starts a process that forks into the background, or runs a script that finishes, the container exits right away. This is the classic "why does my container start and immediately stop" question.
The fix is to run the process in the foreground. A web server should run without a daemon flag; nginx, for example, needs daemon off;. Don't wrap real services in tail -f /dev/null to keep them up. That hides the fact that the actual process died.
4. Volume and permission problems
A permission denied at startup usually means the user inside the container doesn't own the mounted path. Check who the container runs as:
docker inspect <container> --format '{{.Config.User}}'
If it runs as a non-root user (good practice) but the host directory is owned by root, the container can't write. Fix the ownership on the host to match the container's UID, or adjust the user: in your compose file. Bind mounts also silently shadow whatever was in the image at that path, so if a container suddenly can't find a config file it shipped with, check whether a mount is covering it.
5. The image or command is just wrong
An Created status with no logs often means Docker couldn't exec the command. Confirm the entrypoint and command:
docker inspect <container> --format 'ENTRYPOINT={{.Config.Entrypoint}} CMD={{.Config.Cmd}}'
A shell script referenced here needs chmod +x in the Dockerfile and the right line endings. A script saved with Windows CRLF endings fails with a confusing no such file or directory because the interpreter path gets a trailing \r.
Get a shell and reproduce it by hand
When the logs aren't enough, run the image interactively and override the entrypoint so you land in a shell instead of the failing command:
docker run --rm -it --entrypoint sh <image>
From there you can check whether files exist, whether the binary is on the PATH, and whether env vars resolve. Try running the real start command manually and watch it fail with full output. This is the fastest way to separate "the image is broken" from "the runtime config is broken."
If the container starts but dies too fast to exec into, add a temporary long-lived command so it stays up while you poke around:
docker run --rm -it --entrypoint sh <image> -c "sleep 3600"
# then in another terminal: docker exec -it <container> sh
Check host-level causes
Sometimes the container is fine and the host is the problem. A full disk stops containers from starting and produces some of the strangest error messages you'll see. Check it:
df -h
docker system df
If disk is tight, clear out dangling images and stopped containers:
docker system prune
Be careful with docker system prune -a --volumes, which also removes unused images and named volumes. Read what it's about to delete before you confirm. Out-of-memory kills are worth checking too; if the kernel OOM-killer reaped your process, docker inspect shows "OOMKilled": true in the state:
docker inspect <container> --format '{{.State.OOMKilled}}'
When you're managing servers you don't sit next to, catching a full disk or an OOM kill early is half the battle. This is where keeping an eye on host CPU, RAM, and disk pays off, and it's the reason Docker HQ lets you watch those metrics and read container logs from your phone over SSH instead of scrambling for a laptop. For the wider picture of what to watch and why, our complete guide to Docker container monitoring goes deeper.
When it happens on a remote server
Debugging over SSH is the same commands with more friction. SSH in and run the checklist:
ssh user@your-server
docker ps -a
docker logs --tail 100 <container>
If a whole stack refuses to come up after a deploy, check the compose logs together so you can see startup ordering and dependency failures:
docker compose logs --tail 100
docker compose ps
A container that depends on a database will crash-loop if the database isn't ready yet. depends_on controls start order but not readiness, so add a healthcheck or a retry in the app. If you're setting up remote deploys in the first place, how to deploy Docker Compose to a remote server covers the mechanics. And when a container going down is the start of a real outage, incident response when a Docker host goes down walks through the recovery steps.
The part that hurts is not knowing a container died until a user tells you. Push alerts the moment a container or host goes down turn a silent 3am failure into something you can act on before it spreads. That's the case Docker HQ is built for, and you can see the plans on the pricing page.
Frequently asked questions
Why does my Docker container start and immediately stop?
Because its main process exited. Containers live only as long as PID 1 runs. If your CMD starts a background daemon and returns, or runs a script that finishes, Docker sees the process end and stops the container. Run the service in the foreground instead, and check docker logs <container> for the exit reason.
How do I see why a container crashed if the logs are empty?
Run the image interactively with the entrypoint overridden: docker run --rm -it --entrypoint sh <image>, then run the start command by hand to see full output. Empty logs usually mean the process died before writing anything, or it logs to a file inside the container rather than stdout.
What does exit code 137 mean?
Exit code 137 means the process received SIGKILL (128 + 9). Most often the kernel out-of-memory killer stopped it because the container exceeded available memory. Check docker inspect <container> --format '{{.State.OOMKilled}}' and either raise the memory limit or reduce what the app uses.
Should I use restart policies to fix a crashing container?
No. A restart policy like restart: unless-stopped is for surviving reboots and transient failures, not for masking a container that crashes on startup. If it's crash-looping, the restart policy just hides a bug you still have to fix. Find the root cause first, then set the policy.
Next step
Start at the top: docker ps -a, read the exit code, then docker logs. If you're still stuck after the logs, drop into a shell with --entrypoint sh and run the command by hand. That sequence finds the cause of a stuck container faster than guessing at config changes and rebuilding the image each time.