You run docker run myimage and… nothing. The container starts, exits immediately, and you’re left staring at a silent terminal. Sound familiar?
This is one of the most common Docker frustrations, especially for beginners. Let’s fix it.
Understanding Why Containers Exit
A Docker container runs as long as its main process (PID 1) is running. When that process exits, the container exits. This is by design — containers aren’t VMs that sit around waiting for something to happen.
The exit code tells you what happened:
- Exit code 0: Process completed successfully (this is often the surprise)
- Exit code 1: General error
- Exit code 137: Container was killed (OOM or
docker kill) - Exit code 139: Segmentation fault
- Exit code 143: Graceful termination (SIGTERM)
The Most Common Causes
1. Your Command Completes Immediately
This is the #1 cause. Your Dockerfile or run command executes something that finishes instantly.
The problem:
| |
Nginx by default runs in the background (daemonizes) and exits. The container sees the process end and shuts down.
The fix:
| |
The -g "daemon off;" flag keeps nginx in the foreground.
2. Shell Form vs Exec Form Confusion
These look similar but behave differently:
| |
Shell form wraps your command in a shell, which can cause signal handling issues and unexpected exits. Always prefer exec form unless you specifically need shell features.
3. Your Script Has No Loop
If your entrypoint is a script that runs and completes, the container exits.
The problem:
| |
The fix:
| |
Or if you need the container to stay alive:
| |
4. Application Crash on Startup
Your app might be crashing before it even gets going. Check the logs:
| |
Common culprits:
- Missing environment variables
- Config file not found
- Port already in use
- Dependency not installed
5. The Entrypoint/CMD Interaction
When both ENTRYPOINT and CMD exist, CMD becomes arguments to ENTRYPOINT:
| |
If your ENTRYPOINT doesn’t handle arguments properly, it might just exit.
Debugging Checklist
Step 1: Check the exit code
| |
Step 2: Check the logs
| |
Step 3: Run interactively
| |
Step 4: Override the entrypoint
| |
Step 5: Keep it alive temporarily
| |
Quick Reference: Common Services
| Service | Foreground Flag |
|---|---|
| nginx | nginx -g "daemon off;" |
| Apache | apache2ctl -D FOREGROUND |
| PHP-FPM | php-fpm -F |
| Redis | redis-server (foreground by default) |
| MySQL | mysqld (foreground by default) |
The Pattern That Always Works
| |
The key insight: your main process must stay in the foreground and not exit. If it backgrounds itself, pipes to another process, or completes its work, the container stops.
Still Stuck?
If your container still exits immediately after trying these fixes, the issue is almost certainly in your application code — it’s crashing before producing any useful output. Add some logging at the very start of your entrypoint to confirm it’s even being reached:
| |
Then check if that file exists after the container exits.
Containers aren’t magic — they’re just processes with fancy isolation. Once you internalize “container = foreground process,” these issues become much easier to debug.