Flask Docker Container Not Starting (Fix Guide)
If your Flask Docker container is not starting, restarting repeatedly, or exiting right after launch, this guide shows you how to identify the failure point and fix it step-by-step. The goal is to get the container running, verify the Flask app is reachable, and prevent the same startup issue in production.
Quick Fix / Quick Setup
Start with the container state, logs, and startup command.
docker ps -a
docker logs --tail=200 <container_name>
docker inspect <container_name> --format '{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}'
docker run --rm -it <image_name> sh
# inside the container, test the startup command manually
python -m flask --app app routes || true
python -m flask --app app run --host=0.0.0.0 --port=5000 || true
# or, if using gunicorn
gunicorn -b 0.0.0.0:5000 wsgi:app
# validate compose or dockerfile inputs
docker compose config
docker exec -it <running_container> env | sort
Most startup failures come from one of these:
- incorrect
CMDorENTRYPOINT - missing Python dependencies
- wrong Flask or gunicorn import path
- missing environment variables
- app binding to
127.0.0.1instead of0.0.0.0
What’s Happening
A Docker container stays running only while its main process stays alive. If your Flask app crashes during import, startup, or dependency initialization, the main process exits and the container stops or restarts. In other cases, the container may be running but the app is unreachable because it is bound to the wrong interface or port.
Step-by-Step Guide
- Check the container state and exit code
Run:bashdocker ps -a docker inspect <container_name> --format '{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}'
What to look for:Exitedwith non-zero exit code: startup failureRestarting: process is failing and restart policy is retryingOOMKilled=true: memory pressure killed the process
- Read the container logs first
Run:bashdocker logs --tail=200 <container_name>
Common failures:ModuleNotFoundErrorImportErrorKeyError- syntax errors
- database connection failures
- gunicorn errors such as:
textFailed to find attribute 'app' in 'wsgi' - Verify the startup command
Check your DockerfileCMDorENTRYPOINT. For production, use gunicorn instead of the Flask development server.
Example Dockerfile:dockerfileFROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["gunicorn", "-b", "0.0.0.0:5000", "wsgi:app"]
If you use Compose, also inspect the servicecommand:because it can override the image default. - Open a shell in the image and test startup manually
Run:bashdocker run --rm -it <image_name> sh
Then test:bashpython -c "from wsgi import app; print(app)" gunicorn -b 0.0.0.0:5000 wsgi:app
This isolates image-level problems from Compose or orchestration issues. - Confirm the Flask app import path
Gunicorn must point to the correct module and app object.
Common patterns:bashgunicorn -b 0.0.0.0:5000 wsgi:app gunicorn -b 0.0.0.0:5000 app:app gunicorn -b 0.0.0.0:5000 'app:create_app()'
Test imports directly:bashpython -c "from wsgi import app; print(app)" python -c "from app import app; print(app)"
If your app uses a factory, verify the callable exists and returns a valid Flask app. - Verify dependencies are installed
Inside the container:bashpip show flask gunicorn pip freeze
If required packages are missing:- update
requirements.txtorpyproject.toml - rebuild the image without cache
bashdocker build --no-cache -t <image_name> . - update
- Check the working directory and copied files
Inside the container:bashpwd ls -la find . -maxdepth 2 -type f | sort
Confirm these exist where expected:- application source files
wsgi.py- templates
- static assets
- config files
If files are missing, review:WORKDIRCOPYinstructions.dockerignore
- Verify environment variables
Missing runtime variables often crash the app during import or configuration.
Run:bashenv | sort
Confirm required values such as:SECRET_KEYDATABASE_URLREDIS_URL- app-specific settings
Compose example:yamlservices: web: image: myflaskapp:latest environment: SECRET_KEY: change-me DATABASE_URL: postgresql://user:pass@db:5432/app
If variables are not loading correctly, see Flask Environment Variables Not Loading in Production. - Confirm the app binds to all interfaces
If the app listens on127.0.0.1, Docker port publishing will not expose it correctly.
Correct:bashgunicorn -b 0.0.0.0:5000 wsgi:app
For temporary testing only:bashpython -m flask --app app run --host=0.0.0.0 --port=5000 - Check exposed and published ports
If using Docker directly:bashdocker run -p 5000:5000 <image_name>
If using Compose:yamlservices: web: ports: - "5000:5000"
Validate that:- the app listens on the same container port you publish
- upstream reverse proxy config points to the same port
- Validate Docker Compose configuration
Run:bashdocker compose config
Review the merged output for:- incorrect
command - wrong
env_file - invalid volume mounts
- missing networks
- broken health checks
Also inspect service state:bashdocker compose ps docker compose logs -f <service_name> - incorrect
- Test for broken volume mounts
A bind mount can hide files copied into the image.
Problem example:yamlservices: web: volumes: - .:/app
If your local directory does not contain the same files as the image, startup can fail. Temporarily remove the volume and start again. - Check permissions and runtime user
If the container uses a non-root user, verify it can read application files and write required paths.
Example:dockerfileRUN useradd -m appuser USER appuser
Validate ownership and permissions:bashls -la
If needed:dockerfileRUN chown -R appuser:appuser /app - Check database and dependency readiness
The app may exit if PostgreSQL, MySQL, Redis, or another service is unavailable at startup.
Test connectivity from inside the container where possible, or verify hostnames and ports in environment variables. If the app fails only after the container starts, you may need:- retry logic
- startup backoff
- proper service readiness checks
If startup succeeds but requests fail later with server errors, see Flask 500 Internal Server Error in Production. - Inspect health checks
A bad health check can mark a healthy container as unhealthy or trigger restarts.
Inspect health output:bashdocker inspect <container_name> --format '{{json .State.Health}}'
Compose example:yamlservices: web: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000/health"] interval: 30s timeout: 5s retries: 3
Confirm the endpoint exists and returns a successful HTTP response. - Rebuild cleanly after fixes
After changing dependencies, Dockerfile instructions, or app files, rebuild without cache:bashdocker compose build --no-cache docker compose up -d
Or with raw Docker:bashdocker build --no-cache -t <image_name> . docker run -d -p 5000:5000 <image_name>
Then verify the container remains inUpstate.
Common Causes
- Incorrect
CMDorENTRYPOINT→ Docker starts the wrong process or no long-running process → set a valid gunicorn or app startup command. - Wrong gunicorn app path → gunicorn cannot import the Flask app object → fix
wsgi:appor factory syntax. - Missing Python dependencies → imports fail at startup → update dependency files and rebuild the image.
- Application code not copied into the image → required files are missing at runtime → fix
COPYinstructions and.dockerignore. - Bind mount hides application files → local volume overlays built image contents → remove or correct the mount path.
- Required environment variables missing → app crashes during configuration or import → define variables in Compose, env files, or runtime flags.
- App binds to
127.0.0.1→ service is not reachable through Docker networking → bind to0.0.0.0. - Wrong port mapping → host traffic goes to the wrong container port → align published ports with the actual app bind port.
- Database or Redis unavailable during startup → app exits when dependency checks fail → test connectivity and add retry handling.
- Permissions or non-root user issues → app cannot read files or write needed paths → correct ownership and runtime user settings.
- Health check command is wrong → Docker or an orchestrator marks the container unhealthy → fix the health check endpoint and command.
- Out-of-memory kill → container stops under memory pressure → reduce memory usage or increase limits.
Debugging Section
Use these commands in order.
docker ps -a
docker logs --tail=200 <container_name>
docker inspect <container_name> --format '{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}'
docker inspect <container_name>
docker image inspect <image_name>
docker run --rm -it --entrypoint sh <image_name>
docker compose ps
docker compose logs -f <service_name>
docker compose config
docker exec -it <container_name> env | sort
docker exec -it <container_name> sh -lc 'pwd && ls -la'
docker exec -it <container_name> sh -lc 'python -c "from wsgi import app; print(app)"'
docker exec -it <container_name> sh -lc 'pip freeze'
docker exec -it <container_name> sh -lc 'ss -lntp || netstat -lntp'
What to look for:
ExitCodeis non-zeroOOMKilledistrue- startup command does not match your actual app module
- environment variables are missing
- bind mounts hide source files
- process is not listening on the expected port
- health check output shows repeated failures
Checklist
- Container state is
Up, notExitedorRestarting -
docker logsshows the Flask app or gunicorn started without import errors - Startup command points to the correct module and app object
- Required environment variables are present inside the container
- Application files exist in the expected working directory
- The app listens on
0.0.0.0and the correct container port - Port mapping or reverse proxy configuration matches the container port
- Database or dependent services are reachable at startup
- Health check passes if one is configured
Related Guides
- Flask Environment Variables Not Loading in Production
- Flask 500 Internal Server Error in Production
- Flask Production Checklist (Everything You Must Do)
FAQ
Why does the container exit with code 0?
The main process completed successfully and Docker had nothing left to run. This often happens when a shell script starts a background process and then exits.
Why does the container restart repeatedly?
A restart policy is active and the main process keeps failing. Check container logs and the original exit code.
Can a successful image build still fail at runtime?
Yes. Build success only means the image was created. Runtime failures still happen from missing environment variables, incorrect commands, unavailable services, or bind mounts hiding files.
Why is the container running but the app is unreachable?
The app may be listening on 127.0.0.1, using the wrong port, or the reverse proxy may be targeting the wrong upstream.
How do I test whether gunicorn can import my app?
Run this inside the container:
python -c "from wsgi import app; print(app)"
Or start gunicorn directly with the same command used in your Dockerfile or Compose file.
Can Docker Compose volumes break a working image?
Yes. A bind mount can overwrite the application directory and hide files copied during image build.
Should I use flask run in production?
No. Use gunicorn or another production WSGI server.
Final Takeaway
When a Flask Docker container does not start, treat it as a runtime process failure. Check logs, exit code, startup command, imports, environment variables, ports, mounts, and dependency readiness in that order. In most cases, the fix is a corrected gunicorn command, valid app import path, complete environment configuration, or a clean rebuild followed by validation against the production checklist at Flask Production Checklist (Everything You Must Do).