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.