A proper Flask deployment is more than just running python app.py. In this article, we will review a production setup with Docker Compose, Traefik as a reverse proxy, and automatic Let's Encrypt HTTPS certificates.

Why Traefik?

Traefik is a modern reverse proxy that can automatically discover Docker containers and issue SSL certificates for them via Let's Encrypt. This removes the need for manual Nginx and certbot configuration.

Project structure

A typical structure looks like this:

project/
├── app.py
├── Dockerfile
├── compose.yaml
└── .env

Dockerfile

Use the official Python image and gunicorn as the WSGI server:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]

compose.yaml

In compose.yaml, define app and traefik services. Traefik needs access to the Docker socket to discover containers.

Important labels for the app container:

- traefik.enable=true
- traefik.http.routers.app.rule=Host(`your.domain.com`)
- traefik.http.routers.app.tls.certresolver=le

CI/CD with GitHub Actions

Automate deployment with GitHub Actions: on push to the main branch, the workflow connects to the server over SSH and runs docker compose pull && docker compose up -d.

Do not forget to add repository secrets: SSH key, server address, and domain.

Summary

The Flask + Gunicorn + Docker + Traefik stack provides a reliable production setup with minimal maintenance effort.