Skip to main content

Deploy Flask on DigitalOcean — step by step

TL;DR

Step-by-step guide to deploying a Flask application on a DigitalOcean Droplet with Gunicorn, Supervisor, nginx, and SSL.

Key facts

Topology
Flask on DigitalOcean Droplet

TL;DR

Flask's built-in development server is not suitable for production. This guide deploys Flask behind Gunicorn as the WSGI server, managed by Supervisor for process persistence, with nginx handling SSL termination and reverse proxying on a DigitalOcean Droplet.

Prerequisites

  • A DigitalOcean account and a Droplet running Ubuntu 24.04 (minimum 1 GB RAM)
  • A domain name with DNS pointing to the Droplet's IP
  • Your Flask application in a Git repository

Step 1 — Droplet setup

SSH into your Droplet and prepare the system:

sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-venv python3-pip git build-essential

Create a deploy user:

sudo adduser deploy
sudo usermod -aG sudo deploy

Step 2 — Firewall configuration

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Step 3 — Deploy the application

sudo mkdir -p /var/www/flaskapp && sudo chown deploy:deploy /var/www/flaskapp
su - deploy
cd /var/www/flaskapp
git clone git@github.com:yourorg/flaskapp.git .
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install gunicorn

Create a .env file with production configuration:

FLASK_ENV=production
SECRET_KEY=your-secret-key-here
DATABASE_URL=postgresql://user:pass@localhost/flaskdb

Verify the app starts:

gunicorn --bind 0.0.0.0:8000 "app:create_app()"
curl http://localhost:8000/health

Step 4 — Gunicorn WSGI configuration

Create /var/www/flaskapp/gunicorn.conf.py:

import multiprocessing

bind = '127.0.0.1:8000'
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'gthread'
threads = 4
timeout = 120
graceful_timeout = 30
max_requests = 1000
max_requests_jitter = 50
accesslog = '/var/log/gunicorn/flask-access.log'
errorlog = '/var/log/gunicorn/flask-error.log'
loglevel = 'info'
sudo mkdir -p /var/log/gunicorn
sudo chown deploy:deploy /var/log/gunicorn

Step 5 — Supervisor process management

Install Supervisor and create a config:

sudo apt install -y supervisor

Create /etc/supervisor/conf.d/flaskapp.conf:

[program:flaskapp]
directory=/var/www/flaskapp
command=/var/www/flaskapp/venv/bin/gunicorn -c gunicorn.conf.py "app:create_app()"
user=deploy
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/flaskapp.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=5
environment=FLASK_ENV="production"
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status flaskapp

Step 6 — nginx reverse proxy

sudo apt install -y nginx

Create /etc/nginx/sites-available/flaskapp:

server {
    listen 80;
    server_name example.com;

    client_max_body_size 10M;

    location /static/ {
        alias /var/www/flaskapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
    }
}
sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Step 7 — SSL with Let's Encrypt

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

Verify auto-renewal:

sudo certbot renew --dry-run

Monitoring

Check Supervisor process status and tail logs:

sudo supervisorctl status flaskapp
tail -f /var/log/gunicorn/flask-access.log

With Reflex

Install reflexd to monitor your Flask stack continuously. Reflex tracks Gunicorn worker health, response latency, Supervisor process state, nginx error rates, and Droplet system resources. It can restart failed processes, run safe deployments with health verification, and alert your team before issues escalate. See How it works.