How to Deploy a Flask App on DigitalOcean: The Complete 2026 Walkthrough
If you have built a Python Flask application and you are ready to share it with the world, DigitalOcean remains one of the most practical and affordable hosting solutions available. Whether you are launching a side project, a REST API, or a full web application, deploying your Flask app on a DigitalOcean Droplet gives you full control over your server environment without breaking the bank.
In this guide, we will walk through every step required to deploy a Flask app on DigitalOcean, from creating your Droplet to configuring Gunicorn as your WSGI server and setting up Nginx as a reverse proxy. By the end, your Flask app will be live, secure, and production-ready.
What You Will Need Before You Start
Before diving in, make sure you have the following ready:
- A DigitalOcean account (sign up at digitalocean.com if you do not have one)
- A Flask application ready for deployment (either locally or in a GitHub repository)
- A domain name (optional but recommended for production)
- Basic familiarity with the Linux command line
- An SSH key pair configured on your local machine
Step 1: Create a DigitalOcean Droplet
A Droplet is a virtual private server (VPS) on DigitalOcean. Here is how to create one suited for a Flask application:
- Log in to your DigitalOcean dashboard.
- Click the Create button in the top right corner and select Droplets.
- Choose your configuration:
| Setting | Recommended Choice |
|---|---|
| Image (OS) | Ubuntu 24.04 LTS |
| Plan | Basic – $6/month (1 GB RAM, 1 vCPU) |
| Datacenter Region | Choose the one closest to your target audience |
| Authentication | SSH Key (strongly recommended over password) |
Click Create Droplet and wait a few seconds for it to spin up. Once ready, note the public IP address assigned to your Droplet.
Step 2: Connect to Your Droplet via SSH
Open a terminal on your local machine and connect:
ssh root@your_server_ip
Replace your_server_ip with the actual IP address of your Droplet.
Create a Non-Root User (Recommended)
Running everything as root is a security risk. Create a dedicated user:
adduser flaskuser
usermod -aG sudo flaskuser
Switch to the new user:
su - flaskuser
Step 3: Update the Server and Install Dependencies
Start by updating the system packages:
sudo apt update && sudo apt upgrade -y
Install Python, pip, and the essential components you will need:
sudo apt install python3 python3-pip python3-venv nginx -y
This installs:
- Python 3 and pip for managing Python packages
- python3-venv for creating virtual environments
- Nginx which we will use as a reverse proxy later
Step 4: Upload or Clone Your Flask Application
You can get your Flask app onto the server in several ways. The most common approach is cloning from a Git repository:
cd /home/flaskuser
git clone https://github.com/yourusername/your-flask-app.git
cd your-flask-app
Alternatively, you can use scp to upload files from your local machine:
scp -r /path/to/your/flask-app flaskuser@your_server_ip:/home/flaskuser/
Step 5: Set Up a Python Virtual Environment
Creating a virtual environment keeps your project dependencies isolated from the system Python:
python3 -m venv venv
source venv/bin/activate
Now install your Flask app dependencies:
pip install -r requirements.txt
If you do not have a requirements.txt file yet, at minimum you will need:
pip install flask gunicorn
And then generate the file for future use:
pip freeze > requirements.txt
Step 6: Test Your Flask App Locally on the Server
Before configuring the production stack, make sure your app actually runs. Assuming your main Flask file is app.py and your Flask instance is named app:
python app.py
If it starts without errors, you are good to proceed. Press Ctrl+C to stop it.
Step 7: Configure Gunicorn as the WSGI Server
Flask’s built-in development server is not designed for production traffic. Gunicorn (Green Unicorn) is a production-grade WSGI HTTP server that handles concurrent requests efficiently.
Test Gunicorn Manually
First, make sure Gunicorn can serve your Flask app correctly:
gunicorn --bind 0.0.0.0:8000 app:app
Here, app:app means: look in the file app.py for the Flask instance named app. Adjust this based on your project structure. For example, if your file is main.py and the Flask object is application, use main:application.
Visit http://your_server_ip:8000 in your browser. If you see your app, Gunicorn is working. Stop it with Ctrl+C.
Create a Systemd Service for Gunicorn
To keep Gunicorn running in the background and auto-start on reboot, create a systemd service file:
sudo nano /etc/systemd/system/flaskapp.service
Paste the following content:
[Unit]
Description=Gunicorn instance to serve Flask app
After=network.target
[Service]
User=flaskuser
Group=www-data
WorkingDirectory=/home/flaskuser/your-flask-app
Environment="PATH=/home/flaskuser/your-flask-app/venv/bin"
ExecStart=/home/flaskuser/your-flask-app/venv/bin/gunicorn --workers 3 --bind unix:flaskapp.sock -m 007 app:app
[Install]
WantedBy=multi-user.target
Key parameters explained:
--workers 3sets the number of worker processes. A common formula is(2 x number_of_cores) + 1.--bind unix:flaskapp.sockcreates a Unix socket file instead of binding to a TCP port. This is more secure and efficient when paired with Nginx.-m 007sets the file permissions on the socket so Nginx can access it.
Enable and start the service:
sudo systemctl start flaskapp
sudo systemctl enable flaskapp
Check the status:
sudo systemctl status flaskapp
You should see active (running). If there are errors, check the logs with:
sudo journalctl -u flaskapp
Step 8: Configure Nginx as a Reverse Proxy
Nginx will sit in front of Gunicorn, handling incoming HTTP requests, serving static files, and providing an extra layer of performance and security.
Create an Nginx Server Block
sudo nano /etc/nginx/sites-available/flaskapp
Add the following configuration:
server {
listen 80;
server_name your_domain_or_ip;
location / {
include proxy_params;
proxy_pass http://unix:/home/flaskuser/your-flask-app/flaskapp.sock;
}
location /static/ {
alias /home/flaskuser/your-flask-app/static/;
}
}
Replace your_domain_or_ip with your actual domain name or the Droplet IP address.
Enable the Configuration
sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled
Test the Nginx configuration for syntax errors:
sudo nginx -t
If the test passes, restart Nginx:
sudo systemctl restart nginx
Adjust the Firewall
If you are using UFW (Uncomplicated Firewall), allow Nginx traffic:
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable
Now visit http://your_domain_or_ip in your browser. Your Flask app should be live.
Step 9: Secure Your App with a Free SSL Certificate
Running your app over HTTPS is essential. Let’s Encrypt provides free SSL certificates, and Certbot makes the process simple.
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the prompts. Certbot will automatically modify your Nginx configuration to redirect HTTP traffic to HTTPS.
Verify that auto-renewal is set up:
sudo certbot renew --dry-run
Step 10: Set Up Environment Variables (Best Practice)
Hardcoding secrets like database passwords or API keys in your source code is dangerous. Use environment variables instead.
Create a .env file in your project directory:
SECRET_KEY=your_secret_key_here
DATABASE_URL=postgresql://user:password@localhost/dbname
FLASK_ENV=production
In your Flask app, load them using python-dotenv:
pip install python-dotenv
And in your app.py:
from dotenv import load_dotenv
import os
load_dotenv()
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
You can also add environment variables directly into your systemd service file under the [Service] section using Environment directives.
Complete Architecture Overview
Here is what the full deployment stack looks like:
| Layer | Component | Role |
|---|---|---|
| Client | Browser / API consumer | Sends HTTP/HTTPS requests |
| Web Server | Nginx | Reverse proxy, SSL termination, static file serving |
| WSGI Server | Gunicorn | Runs your Python Flask code with multiple workers |
| Application | Flask | Your Python web application |
| Infrastructure | DigitalOcean Droplet | Ubuntu VPS hosting everything |
Troubleshooting Common Issues
Here are the most frequent problems developers run into when they deploy a Flask app on DigitalOcean, along with their solutions:
502 Bad Gateway Error
This usually means Nginx cannot communicate with Gunicorn. Check that:
- The Gunicorn service is running:
sudo systemctl status flaskapp - The socket file exists:
ls /home/flaskuser/your-flask-app/flaskapp.sock - File permissions are correct on the socket and project directory
Permission Denied on the Socket
Make sure the www-data group has access. You can fix this with:
sudo chown flaskuser:www-data /home/flaskuser/your-flask-app
chmod 710 /home/flaskuser
App Works on Port 8000 But Not Through Nginx
Double-check your Nginx config file for typos in the proxy_pass path. The Unix socket path must exactly match the one in your systemd service file.
Changes to Code Are Not Reflected
After updating your Flask app code, you need to restart Gunicorn:
sudo systemctl restart flaskapp
Optional: Deploy Using Docker on DigitalOcean
If you prefer a containerized approach, you can also deploy your Flask app using Docker. This is useful for ensuring consistency between your local development environment and production.
Create a Dockerfile in your project root:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Build and run:
docker build -t flaskapp .
docker run -d -p 8000:8000 flaskapp
Then configure Nginx to proxy to http://127.0.0.1:8000 instead of using a Unix socket.
DigitalOcean Droplet vs. App Platform: Which Should You Choose?
DigitalOcean also offers an App Platform, a managed platform-as-a-service option. Here is a quick comparison:
| Feature | Droplet (VPS) | App Platform |
|---|---|---|
| Server control | Full root access | Managed by DigitalOcean |
| Setup complexity | Manual configuration required | Push-to-deploy from GitHub |
| Starting price | $6/month | Free tier available, then $5/month |
| SSL | Manual (Certbot) | Automatic |
| Best for | Developers who want full control | Quick deployments with minimal DevOps |
For most developers who want to learn server management or need custom configurations, the Droplet approach covered in this guide is the better choice.
Performance Tips for Production Flask Apps
- Increase Gunicorn workers based on your Droplet’s CPU cores. The formula
(2 x cores) + 1is a solid starting point. - Enable Gzip compression in Nginx to reduce response sizes.
- Use a CDN like Cloudflare for static assets and global caching.
- Monitor your server with tools like
htop, DigitalOcean’s built-in monitoring, or third-party services. - Set up automated backups through DigitalOcean’s Droplet backup feature (small additional cost).
- Keep your system updated regularly with
sudo apt update && sudo apt upgrade.
Frequently Asked Questions
How much does it cost to deploy a Flask app on DigitalOcean?
The most affordable DigitalOcean Droplet starts at $6 per month, which includes 1 GB of RAM and 1 vCPU. This is enough to run a small to medium Flask application. You only pay for what you use, and there are no hidden fees.
Do I need Gunicorn to run Flask in production?
Yes. Flask’s built-in development server is single-threaded and not designed to handle real-world traffic. Gunicorn is a production-grade WSGI server that manages multiple worker processes, making your app significantly more reliable and performant.
Can I deploy a Flask app on DigitalOcean without a domain name?
Absolutely. You can access your app directly via the Droplet’s public IP address. However, for production use, a domain name with SSL is strongly recommended for credibility and security.
How do I update my Flask app after deployment?
SSH into your server, pull the latest code from your repository (e.g., git pull origin main), install any new dependencies, and restart the Gunicorn service with sudo systemctl restart flaskapp.
Is DigitalOcean good for hosting Python web apps?
DigitalOcean is one of the most popular choices among Python developers for hosting web applications. Its straightforward pricing, excellent documentation, and developer-friendly tools make it ideal for Flask, Django, and FastAPI projects alike.
Can I run multiple Flask apps on one Droplet?
Yes. You can create separate Gunicorn systemd services and Nginx server blocks for each application. Just make sure each app uses a unique socket file or port, and that your Droplet has enough resources to handle all of them.
How do I host a Flask app on a VPS?
The process described in this guide applies to virtually any VPS provider, not just DigitalOcean. The core steps are the same: set up the server, install Python and dependencies, configure Gunicorn as the WSGI server, and use Nginx as a reverse proxy.
Wrapping Up
Deploying a Flask app on DigitalOcean is straightforward once you understand the stack. To recap the key steps:
- Create a DigitalOcean Droplet with Ubuntu
- Set up a non-root user and install dependencies
- Upload your Flask app and create a virtual environment
- Configure Gunicorn as a systemd service
- Set up Nginx as a reverse proxy
- Secure everything with an SSL certificate
This stack (Flask + Gunicorn + Nginx on a DigitalOcean Droplet) is battle-tested, affordable, and gives you complete control over your deployment. It is the same approach used by thousands of developers and startups in production today.
If you found this guide helpful or have questions about deploying your specific Flask project, feel free to reach out. At Box Software, we help teams build and deploy reliable web applications. Visit boxsoftware.net to learn more about our services.
