How to Deploy a Flask App to Production
Flask's built-in server is for development only. How to deploy a Flask app properly: the app factory and config from environment variables, Gunicorn, a reverse proxy with HTTPS, running it as a systemd service, a Docker option, and the mistakes that cause 502s.
When you run flask run (or app.run()), Flask prints:
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
Take it at its word. Here's how to deploy properly. (Flask vs Django vs FastAPI)
The production setup
Browser → Caddy/Nginx (HTTPS) → Gunicorn (several workers) → your Flask app
Gunicorn is a production WSGI server: it runs multiple copies of your app to handle requests in parallel and restarts workers that crash.
Step 1: configuration from the environment
Don't hardcode secrets or debug mode:
# app.py
import os
from flask import Flask
def create_app():
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"]
# register blueprints, extensions...
return app
app = create_app()
- Never run with
debug=Truein production — the debugger lets anyone who sees an error page run Python code on your server. SECRET_KEYsigns session cookies; it must be long, random and secret. (Environment variables explained)
Step 2: dependencies
pip install gunicorn
pip freeze > requirements.txt
Step 3: try Gunicorn locally
gunicorn --bind 127.0.0.1:8000 --workers 3 app:app
app:app means "the app object in app.py". A common rule of thumb is 2–4 workers per CPU core.
Step 4: on the server
git clone https://github.com/you/myflask.git /srv/myflask
cd /srv/myflask
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
Create /srv/myflask/.env with your secrets, readable only by the app user (chmod 600). (Python virtual environments)
Step 5: run as a systemd service
# /etc/systemd/system/myflask.service
[Unit]
Description=My Flask app
After=network.target
[Service]
User=app
WorkingDirectory=/srv/myflask
EnvironmentFile=/srv/myflask/.env
ExecStart=/srv/myflask/.venv/bin/gunicorn --bind 127.0.0.1:8000 --workers 3 app:app
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now myflask
journalctl -u myflask -f
Step 6: HTTPS
With Caddy:
example.com {
reverse_proxy 127.0.0.1:8000
}
Caddy gets the certificate automatically. (What is Caddy?) With Nginx, use proxy_pass http://127.0.0.1:8000; and Certbot. (Nginx reverse proxy config)
Tell Flask it's behind a proxy so it sees the real scheme and client IP:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
Alternative: Docker
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nobody
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "app:app"]
Note 0.0.0.0 inside a container. (Dockerfile explained)
Troubleshooting
- 502 Bad Gateway — Gunicorn isn't running or isn't on the port the proxy expects. Check
journalctl -u myflask. (502 Bad Gateway) - Worker timeout — a request took longer than Gunicorn's default 30 seconds. Make it faster or move the work to a background job. (504 Gateway Timeout)
- ModuleNotFoundError — the service uses a different Python than where you installed packages; point
ExecStartat the venv's gunicorn. (ModuleNotFoundError) - Static files missing — serve
static/from the proxy, or use WhiteNoise.
EasySpawn runs your Flask app behind HTTPS with Gunicorn, Postgres and daily backups set up — push your code and it's live. See how it works or join the waitlist.
Related: Flask vs Django vs FastAPI · How to Deploy a Django App · Deploy a FastAPI App to Production · How to Run a Python Script 24/7
Keep reading
What Is Vercel? What It Does, What It Costs You, and When to Use Something Else
Vercel is a hosting platform built around frontend frameworks, especially Next.js: push to GitHub and your site is live. What it actually does, what serverless functions mean for your app, where the limits are, and when a regular server is a better fit.
What Is Nginx? The Web Server in Front of Half the Internet
Nginx ("engine-x") is a web server that serves files, forwards requests to your app, handles HTTPS and balances load. What it does, what a basic config looks like, where the files live, the commands you'll need, and whether you need it at all.