Looking for a development team? Let's build something amazing together! Hire Us
Codend Logo end

Browse Categories

ESC

Start typing to search through our articles...

How to Deploy a Flask App on VPS: Complete Production Guide

How to Deploy a Flask App on VPS: Complete Production Guide

A step-by-step guide to deploying your Flask application on a Virtual Private Server (VPS) with Nginx, Gunicorn, and SSL certificates. --- ## Table of Contents 1. [Prerequisites](#prerequisites) 2. [Initial VPS Setup](#initial-vps-setup) 3. [Installing Required Software](#installing-required-software) 4. [Setting Up Your Flask Application](#setting-up-your-flask-application) 5. [Configuring Gunicorn](#configuring-gunicorn) 6. [Setting Up Nginx](#setting-up-nginx) 7. [SSL Certificate with Let's Encrypt](#ssl-certificate-with-lets-encrypt) 8. [Systemd Service Configuration](#systemd-service-configuration) 9. [Firewall Configuration](#firewall-configuration) 10. [Troubleshooting](#troubleshooting) --- ## Prerequisites Before starting, ensure you have: - A VPS running **Ubuntu 20.04/22.04** (DigitalOcean, Linode, Vultr, etc.) - A domain name pointing to your VPS IP address - SSH access to your server - A Flask application ready to deploy - Basic Linux command line knowledge --- ## Initial VPS Setup ### Step 1: Connect to Your VPS ```bash ssh root@your_server_ip ``` ### Step 2: Create a Non-Root User ```bash # Create new user adduser deploy # Grant sudo privileges usermod -aG sudo deploy # Switch to new user su - deploy ``` ### Step 3: Set Up SSH Key Authentication (Recommended) On your **local machine**: ```bash # Generate SSH key (if you don't have one) ssh-keygen -t ed25519 -C "[email protected]" # Copy public key to server ssh-copy-id deploy@your_server_ip ``` ### Step 4: Update System Packages ```bash sudo apt update && sudo apt upgrade -y ``` --- ## Installing Required Software ### Install Python and pip ```bash # Install Python 3 and pip sudo apt install python3 python3-pip python3-venv -y # Verify installation python3 --version pip3 --version ``` ### Install Nginx ```bash sudo apt install nginx -y # Start and enable Nginx sudo systemctl start nginx sudo systemctl enable nginx # Verify Nginx is running sudo systemctl status nginx ``` ### Install Additional Dependencies ```bash # Install essential build tools sudo apt install build-essential libssl-dev libffi-dev python3-dev -y # Install Git (for cloning your repository) sudo apt install git -y ``` --- ## Setting Up Your Flask Application ### Step 1: Create Application Directory ```bash # Create directory structure sudo mkdir -p /var/www/myflaskapp sudo chown -R deploy:deploy /var/www/myflaskapp cd /var/www/myflaskapp ``` ### Step 2: Clone Your Application ```bash # Clone from Git repository git clone https://github.com/yourusername/your-flask-app.git . # Or create a simple test app nano app.py ``` **Simple Flask Application (app.py):** ```python from flask import Flask app = Flask(__name__) @app.route('/') def home(): return '<h1>Hello from Flask on VPS!</h1>' @app.route('/health') def health(): return {'status': 'healthy'}, 200 if __name__ == '__main__': app.run() ``` ### Step 3: Create Virtual Environment ```bash # Create virtual environment python3 -m venv venv # Activate virtual environment source venv/bin/activate # Upgrade pip pip install --upgrade pip ``` ### Step 4: Install Dependencies ```bash # Install Flask and Gunicorn pip install flask gunicorn # Or install from requirements.txt pip install -r requirements.txt # Add gunicorn to requirements pip freeze > requirements.txt ``` ### Step 5: Test Your Application ```bash # Run Flask development server python app.py ``` Visit `http://your_server_ip:5000` to verify it works (you may need to temporarily allow port 5000). --- ## Configuring Gunicorn Gunicorn (Green Unicorn) is a production-ready WSGI HTTP server for Python. ### Step 1: Create WSGI Entry Point ```bash nano /var/www/myflaskapp/wsgi.py ``` **wsgi.py:** ```python from app import app if __name__ == '__main__': app.run() ``` ### Step 2: Test Gunicorn ```bash cd /var/www/myflaskapp source venv/bin/activate # Run Gunicorn gunicorn --bind 0.0.0.0:8000 wsgi:app ``` Test by visiting `http://your_server_ip:8000` ### Step 3: Create Gunicorn Configuration File (Optional) ```bash nano /var/www/myflaskapp/gunicorn.conf.py ``` **gunicorn.conf.py:** ```python # Gunicorn configuration file import multiprocessing # Server socket bind = 'unix:/var/www/myflaskapp/myflaskapp.sock' backlog = 2048 # Worker processes workers = multiprocessing.cpu_count() * 2 + 1 worker_class = 'sync' worker_connections = 1000 timeout = 120 keepalive = 5 # Process naming proc_name = 'myflaskapp' # Logging accesslog = '/var/log/gunicorn/access.log' errorlog = '/var/log/gunicorn/error.log' loglevel = 'info' # Daemon mode daemon = False ``` Create log directory: ```bash sudo mkdir -p /var/log/gunicorn sudo chown -R deploy:deploy /var/log/gunicorn ``` --- ## Setting Up Nginx Nginx acts as a reverse proxy, forwarding requests to Gunicorn. ### Step 1: Create Nginx Server Block ```bash sudo nano /etc/nginx/sites-available/myflaskapp ``` **Nginx Configuration:** ```nginx server { listen 80; server_name yourdomain.com www.yourdomain.com; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Logging access_log /var/log/nginx/myflaskapp_access.log; error_log /var/log/nginx/myflaskapp_error.log; # Max upload size client_max_body_size 10M; location / { proxy_pass http://unix:/var/www/myflaskapp/myflaskapp.sock; 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_connect_timeout 300s; proxy_read_timeout 300s; } # Static files (if any) location /static { alias /var/www/myflaskapp/static; expires 30d; add_header Cache-Control "public, immutable"; } # Favicon location /favicon.ico { alias /var/www/myflaskapp/static/favicon.ico; access_log off; log_not_found off; } } ``` ### Step 2: Enable the Site ```bash # Create symbolic link sudo ln -s /etc/nginx/sites-available/myflaskapp /etc/nginx/sites-enabled/ # Remove default site (optional) sudo rm /etc/nginx/sites-enabled/default # Test Nginx configuration sudo nginx -t # Reload Nginx sudo systemctl reload nginx ``` --- ## SSL Certificate with Let's Encrypt ### Step 1: Install Certbot ```bash sudo apt install certbot python3-certbot-nginx -y ``` ### Step 2: Obtain SSL Certificate ```bash sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com ``` Follow the prompts: - Enter your email address - Agree to the Terms of Service - Choose whether to redirect HTTP to HTTPS (recommended: Yes) ### Step 3: Verify Auto-Renewal ```bash # Test renewal process sudo certbot renew --dry-run # Check certbot timer sudo systemctl status certbot.timer ``` Your Nginx configuration will be automatically updated for HTTPS. --- ## Systemd Service Configuration Create a systemd service to manage Gunicorn. ### Step 1: Create Service File ```bash sudo nano /etc/systemd/system/myflaskapp.service ``` **myflaskapp.service:** ```ini [Unit] Description=Gunicorn instance to serve myflaskapp After=network.target [Service] User=deploy Group=www-data WorkingDirectory=/var/www/myflaskapp Environment="PATH=/var/www/myflaskapp/venv/bin" ExecStart=/var/www/myflaskapp/venv/bin/gunicorn --workers 3 --bind unix:myflaskapp.sock -m 007 wsgi:app Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` ### Step 2: Start and Enable Service ```bash # Reload systemd sudo systemctl daemon-reload # Start the service sudo systemctl start myflaskapp # Enable on boot sudo systemctl enable myflaskapp # Check status sudo systemctl status myflaskapp ``` ### Step 3: Useful Service Commands ```bash # Restart application sudo systemctl restart myflaskapp # Stop application sudo systemctl stop myflaskapp # View logs sudo journalctl -u myflaskapp -f # View last 50 lines of logs sudo journalctl -u myflaskapp -n 50 ``` --- ## Firewall Configuration ### Using UFW (Uncomplicated Firewall) ```bash # Enable UFW sudo ufw enable # Allow SSH (important - do this first!) sudo ufw allow OpenSSH # Allow HTTP sudo ufw allow 'Nginx HTTP' # Allow HTTPS sudo ufw allow 'Nginx HTTPS' # Or allow both at once sudo ufw allow 'Nginx Full' # Check status sudo ufw status ``` **Expected output:** ``` Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6) ``` --- ## Environment Variables ### Managing Secrets Securely **Option 1: Using .env file** ```bash nano /var/www/myflaskapp/.env ``` **.env:** ``` FLASK_ENV=production SECRET_KEY=your-super-secret-key-here DATABASE_URL=postgresql://user:pass@localhost/dbname ``` Install python-dotenv: ```bash pip install python-dotenv ``` Load in your app: ```python from dotenv import load_dotenv load_dotenv() import os SECRET_KEY = os.getenv('SECRET_KEY') ``` **Option 2: Using systemd environment file** Update your service file: ```ini [Service] EnvironmentFile=/var/www/myflaskapp/.env ``` --- ## Database Setup (Optional) ### PostgreSQL ```bash # Install PostgreSQL sudo apt install postgresql postgresql-contrib -y # Create database and user sudo -u postgres psql # In PostgreSQL shell: CREATE DATABASE myflaskapp; CREATE USER flaskuser WITH PASSWORD 'securepassword'; GRANT ALL PRIVILEGES ON DATABASE myflaskapp TO flaskuser; \q ``` ### MySQL/MariaDB ```bash # Install MariaDB sudo apt install mariadb-server -y # Secure installation sudo mysql_secure_installation # Create database sudo mysql -u root -p # In MySQL shell: CREATE DATABASE myflaskapp; CREATE USER 'flaskuser'@'localhost' IDENTIFIED BY 'securepassword'; GRANT ALL PRIVILEGES ON myflaskapp.* TO 'flaskuser'@'localhost'; FLUSH PRIVILEGES; EXIT; ``` --- ## Troubleshooting ### Common Issues and Solutions #### 502 Bad Gateway ```bash # Check if Gunicorn is running sudo systemctl status myflaskapp # Check socket file exists ls -la /var/www/myflaskapp/myflaskapp.sock # Check Gunicorn logs sudo journalctl -u myflaskapp -n 50 # Check Nginx error logs sudo tail -f /var/log/nginx/error.log ``` #### Permission Denied on Socket ```bash # Fix socket permissions sudo chown deploy:www-data /var/www/myflaskapp chmod 755 /var/www/myflaskapp # Restart services sudo systemctl restart myflaskapp sudo systemctl restart nginx ``` #### Application Not Starting ```bash # Test manually cd /var/www/myflaskapp source venv/bin/activate gunicorn --bind 0.0.0.0:8000 wsgi:app # Check for Python errors python wsgi.py ``` #### Static Files Not Loading ```bash # Verify static directory exists ls -la /var/www/myflaskapp/static # Check Nginx configuration sudo nginx -t # Ensure correct permissions sudo chown -R deploy:www-data /var/www/myflaskapp/static ``` ### Useful Debugging Commands ```bash # View real-time logs sudo journalctl -u myflaskapp -f # Check Nginx configuration sudo nginx -t # Check listening ports sudo ss -tulpn | grep -E '(80|443|8000)' # Check disk space df -h # Check memory usage free -m # Check running processes htop ``` --- ## Deployment Workflow For future updates, use this workflow: ```bash # SSH into server ssh deploy@your_server_ip # Navigate to app directory cd /var/www/myflaskapp # Activate virtual environment source venv/bin/activate # Pull latest changes git pull origin main # Install new dependencies (if any) pip install -r requirements.txt # Run database migrations (if using Flask-Migrate) flask db upgrade # Restart application sudo systemctl restart myflaskapp # Check status sudo systemctl status myflaskapp ``` --- ## Quick Reference | Action | Command | |--------|---------| | Start app | `sudo systemctl start myflaskapp` | | Stop app | `sudo systemctl stop myflaskapp` | | Restart app | `sudo systemctl restart myflaskapp` | | View logs | `sudo journalctl -u myflaskapp -f` | | Restart Nginx | `sudo systemctl restart nginx` | | Test Nginx config | `sudo nginx -t` | | Renew SSL | `sudo certbot renew` | --- ## Conclusion You now have a production-ready Flask application running on your VPS with: - **Gunicorn** as the WSGI server - **Nginx** as the reverse proxy - **SSL/HTTPS** via Let's Encrypt - **Systemd** for process management - **UFW** firewall for security Your application is now secure, performant, and ready to handle production traffic. --- *Last Updated: January 2026* *Tags: #Flask #Python #VPS #Deployment #Nginx #Gunicorn #DevOps #Ubuntu*

Comments (0)

Leave a Comment