Skip to content

Deploying Python Applications with Nginx

This guide walks through setting up a Python web application with Nginx as a reverse proxy server.

1. Introduction

Nginx is a popular web server that can act as a reverse proxy for Python web applications. This setup is highly efficient and scalable for production environments.

Architecture Overview

Client Request → Nginx → WSGI Server (Gunicorn/uWSGI) → Python Application

2. Prerequisites

  • A server with Ubuntu/Debian (instructions can be adapted for other distributions)
  • Python 3.8+ installed
  • A Python web application (Flask/Django/FastAPI)
  • Root or sudo access

3. Installing Nginx

bash
# Update package lists
sudo apt update

# Install Nginx
sudo apt install nginx -y

# Start Nginx and enable it to start on boot
sudo systemctl start nginx
sudo systemctl enable nginx

# Check status
sudo systemctl status nginx

4. Setting Up Your Python Application

Create a Sample Flask Application

bash
# Install virtualenv if not installed
pip install virtualenv

# Create and activate virtual environment
mkdir -p /var/www/myapp
cd /var/www/myapp
virtualenv venv
source venv/bin/activate

# Install Flask and Gunicorn
pip install flask gunicorn

Create a sample application (app.py):

python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello from Python running behind Nginx!"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

Testing the Application Locally

bash
# Test with Flask's development server
python app.py

# Test with Gunicorn
gunicorn --bind 127.0.0.1:8000 app:app

5. Configuring Gunicorn as a Service

Create a systemd service file:

bash
sudo nano /etc/systemd/system/myapp.service

Add the following content:

ini
[Unit]
Description=Gunicorn instance to serve myapp
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/venv/bin"
ExecStart=/var/www/myapp/venv/bin/gunicorn --workers 3 --bind unix:myapp.sock -m 007 app:app

[Install]
WantedBy=multi-user.target

Start and enable the service:

bash
# Change ownership
sudo chown -R www-data:www-data /var/www/myapp

# Start and enable service
sudo systemctl start myapp
sudo systemctl enable myapp
sudo systemctl status myapp

6. Configuring Nginx

Create a new Nginx configuration file:

bash
sudo nano /etc/nginx/sites-available/myapp

Add the following content:

nginx
server {
    listen 80;
    server_name your_domain.com www.your_domain.com;

    location / {
        include proxy_params;
        proxy_pass http://unix:/var/www/myapp/myapp.sock;
    }

    location /static/ {
        alias /var/www/myapp/static/;
    }
}

Enable the site and test the configuration:

bash
# Create symbolic link
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled

# Test Nginx configuration
sudo nginx -t

# Restart Nginx
sudo systemctl restart nginx

7. Setting Up SSL with Let's Encrypt

bash
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y

# Obtain SSL certificate
sudo certbot --nginx -d your_domain.com -d www.your_domain.com

# Test auto-renewal
sudo certbot renew --dry-run

8. Optimizing Nginx Configuration

Edit your Nginx configuration for better performance:

nginx
server {
    listen 80;
    server_name your_domain.com www.your_domain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your_domain.com www.your_domain.com;

    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

    # Enable HSTS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";

    # Other security headers
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    add_header X-XSS-Protection "1; mode=block";

    # Enable gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # Application proxy
    location / {
        proxy_pass http://unix:/var/www/myapp/myapp.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;
    }

    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, max-age=2592000";
    }
}

9. Logging and Monitoring

Configure logging for your application:

bash
# View Nginx logs
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log

# View Gunicorn logs
sudo journalctl -u myapp

10. Load Balancing Multiple Application Instances

For high-traffic applications, configure multiple Gunicorn instances:

nginx
upstream myapp_servers {
    server unix:/var/www/myapp/myapp1.sock;
    server unix:/var/www/myapp/myapp2.sock;
    server unix:/var/www/myapp/myapp3.sock;
}

server {
    listen 443 ssl http2;
    server_name your_domain.com;

    # SSL configuration...

    location / {
        proxy_pass http://myapp_servers;
        # Other proxy settings...
    }
}

11. Django-Specific Configuration

For Django applications, include these additional settings:

nginx
location /static/ {
    alias /var/www/myapp/static/;
    expires 30d;
}

location /media/ {
    alias /var/www/myapp/media/;
    expires 30d;
}

And run the collectstatic command:

bash
python manage.py collectstatic

Conclusion

You've successfully deployed a Python application with Nginx as a reverse proxy. This setup provides excellent performance, scalability, and security for production environments.

For more advanced configurations, consider exploring:

  • Rate limiting
  • WebSocket support
  • Advanced caching strategies
  • Integration with CDNs