Labs ICT
โญ Pro Login

Deployment

Getting your app online.

Deployment

So you've built your Flask app and it works great on your machine. Now what? Getting it online so other people can use it is called deployment, and there are several layers to understand. Don't worry โ€” it's not as scary as it seems.

Why the Development Server Isn't Enough

When you run flask run, Flask starts a development server. It's convenient for testing but has serious limitations โ€” it's single-threaded, doesn't handle errors gracefully, and isn't secure for production. You need a proper WSGI server.

Gunicorn: The Production Server

Gunicorn (Green Unicorn) is a production WSGI server that handles multiple requests simultaneously. It's the standard for running Flask in production.

# Install gunicorn
pip install gunicorn

# Run your app with gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 app:app

# -w 4 means 4 worker processes
# -b binds to all interfaces on port 8000
# app:app means the 'app' variable in the 'app' module

Gunicorn spawns multiple worker processes to handle concurrent requests. For most apps, 2-4 workers per CPU core is a good starting point.

Nginx as Reverse Proxy

Nginx sits in front of Gunicorn and handles things like serving static files, SSL encryption, load balancing, and request buffering. It's the public face of your server.

# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name myapp.com;

    location /static {
        alias /var/www/myapp/static;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Nginx serves static files directly (much faster than Python) and forwards dynamic requests to Gunicorn. This is the standard production setup.

Environment Variables in Production

Never hardcode secrets in production. Use environment variables to keep your configuration separate from your code.

import os

app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL')
app.config['DEBUG'] = False  # Always False in production

Docker Basics

Docker packages your app with all its dependencies into a container. It runs the same everywhere โ€” your machine, a server, the cloud.

# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]

Build and run with docker build -t myapp . then docker run -p 8000:8000 -e SECRET_KEY=mysecret myapp.

Platform Deployment

Platforms like Heroku, Railway, and Render handle much of the deployment complexity. You push your code, and they handle the rest โ€” building, running, scaling, and SSL. Create a Procfile and a requirements.txt, push to their platform, and your app is live.

# Procfile (for Heroku/Railway)
web: gunicorn app:app

# runtime.txt
python-3.11.4

Database Migrations in Production

Running db.create_all() in production is risky. Use Flask-Migrate to apply changes safely. Run flask db upgrade as part of your deployment process so schema changes are applied cleanly.

Why Production Is Different

The development server prioritizes convenience over everything else. Production needs security, performance, reliability, and monitoring. A proper deployment stack โ€” Gunicorn behind Nginx, with environment variables and database migrations โ€” gives you all of that. It's not just about making your app accessible; it's about making it trustworthy.

Try it Yourself ->

๐Ÿงช Quick Quiz

What tool runs Flask in production?