/blog/deploying-django-to-production-nginx-and-gunicorn/ - zsh
user@portfolio ~ $

cat deploying-django-to-production-nginx-and-gunicorn.md

Deploying Django to Production: Nginx and Gunicorn

Author: Aslany Rahim Published: November 29, 2025
The runserver command is not for production! Learn how to set up a robust production server using Gunicorn as the WSGI application server and Nginx as the reverse proxy.

AYou have built your Django app, pushed it to a Virtual Private Server (like AWS EC2 or DigitalOcean Droplet), and now you want the world to see it.

Warning: Do not run python manage.py runserver in production. It is single-threaded and insecure.

To serve Django professionally, we need two components:
1. Gunicorn (Green Unicorn): A WSGI HTTP Server that translates web requests into Python function calls.
2. Nginx: A high-performance Reverse Proxy that handles incoming traffic, static files, and SSL, then passes the request to Gunicorn.

Step 1: Gunicorn

First, install Gunicorn in your virtual environment:

pip install gunicorn

You can test it simply by running:

gunicorn --bind 0.0.0.0:8000 myproject.wsgi

However, if you close your SSH terminal, the site goes down. We need to keep it running in the background using Systemd.

Create a service file: /etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/myproject
ExecStart=/home/ubuntu/myproject/venv/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/home/ubuntu/myproject/myproject.sock \
          myproject.wsgi:application

[Install]
WantedBy=multi-user.target

Start and enable the service:

sudo systemctl start gunicorn
sudo systemctl enable gunicorn

This creates a Unix Socket file. This is faster than using a network port (8000) because Nginx and Gunicorn communicate via a file on the disk.

Step 2: Nginx

Install Nginx:

sudo apt update
sudo apt install nginx

Create a configuration file for your site: /etc/nginx/sites-available/myproject

server {
    listen 80;
    server_name example.com www.example.com 203.0.113.1;

    # Ignore favicon errors
    location = /favicon.ico { access_log off; log_not_found off; }

    # Serve Static Files Directly (Nginx is super fast at this)
    location /static/ {
        root /home/ubuntu/myproject;
    }

    # Serve Media Files
    location /media/ {
        root /home/ubuntu/myproject;
    }

    # Pass everything else to Gunicorn
    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/myproject/myproject.sock;
    }
}

Enable the site by creating a symbolic link:

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx

Step 3: Static Files

Django doesn't serve static files (CSS/Images) in production. You must run:

python manage.py collectstatic

This gathers all files into the folder Nginx is looking at.

Conclusion

This architecture is the gold standard for Python deployment. Nginx acts as the bouncer/security guard, handling SSL and buffering slow clients, while Gunicorn focuses purely on executing your Python code.

14 views
0 comments

Comments (0)

Leave a Comment

No comments yet. Be the first to comment!

Related Posts

Keeping Your Stack Safe: Managing Dependencies in Python and Node

The Equifax breach was caused by a single unpatched library. Learn how to audit and update your dependencies using pip-audit …

November 30, 2025

Automating Django Tests with GitHub Actions (CI/CD)

Stop manually running tests. Set up a Continuous Integration pipeline that automatically tests your code every time you push to …

November 24, 2025

Dockerizing Django: From Development to Production

Stop the "it works on my machine" excuses. Learn how to containerize your Django and PostgreSQL application using Docker and …

November 19, 2025

user@portfolio ~ $ _