Table of Contents

Introduction: What are Nginx and Gunicorn?

When you decide to deploy your Django app in production, you want it to be fast, secure, and scalable. Two of the most powerful tools for this are Nginx and Gunicorn.

Gunicorn is a WSGI server that runs your Django application. It listens for incoming requests and passes them to Django, which processes and responds. On the other hand, Nginx is a high-performance web server that acts as a reverse proxy, handling HTTP requests and serving static files, while forwarding dynamic requests to Gunicorn.

This tutorial will take you through the entire process of setting up your Django app with Nginx, Gunicorn, and Systemd—starting from creating a simple app to configuring a production-ready environment. Let’s dive in!

Step 1: Create a Simple Django App

Before we get into the deployment, we need a simple Django app. If you already have one, you can skip this step. But for new users, here's how you can create a simple Django project and app.

# Install Django in your environment
pip install django

# Create a new Django project
django-admin startproject myproject

# Create an app inside the project
cd myproject
python manage.py startapp myapp

# Create a simple view in your app
# myapp/views.py
from django.http import HttpResponse

def home(request):
    return HttpResponse("Hello, World!")

In your urls.py, make sure to wire up this view:

# myproject/urls.py
from django.contrib import admin
from django.urls import path
from myapp import views

urlpatterns = [
    path('', views.home),
    path('admin/', admin.site.urls),
]

Test it by running the Django development server:

python manage.py runserver

Now, visit http://localhost:8000, and you should see "Hello, World!"

Step 2: Setting Up the Production Environment

Now that we have a working Django app, let’s configure the production environment. This step ensures that everything runs securely and efficiently in production.

First, create a virtual environment to isolate your project dependencies:

# Install virtualenv if you haven’t already
pip install virtualenv

# Create a virtual environment
virtualenv venv

# Activate the virtual environment
source venv/bin/activate  # On Windows, use venv\Scripts\activate

# Install Django and Gunicorn
pip install django gunicorn

Update your settings.py to configure Django for production:

# myproject/settings.py
DEBUG = False
ALLOWED_HOSTS = ['your_domain_or_ip']  # Add your domain or server IP here

# Configure your database (e.g., PostgreSQL)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'your_db_name',
        'USER': 'your_db_user',
        'PASSWORD': 'your_db_password',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

Make sure to apply database migrations:

python manage.py migrate

Your Django app is now ready for production. But before you can serve it, we need Gunicorn to run the app and Nginx to reverse proxy requests.

Step 3: Install and Configure Gunicorn

Gunicorn is the WSGI server that will serve your Django app. Let’s install Gunicorn and test it.

pip install gunicorn

To run Gunicorn on your app, use this command:

gunicorn --workers 3 --bind 0.0.0.0:8000 myproject.wsgi:application

This binds Gunicorn to all available network interfaces on port 8000. Now your app should be accessible at http://your_server_ip:8000. You can check this by opening a browser and visiting the server’s IP address on port 8000.

For production, however, you should use Nginx as a reverse proxy (discussed in the next section).

Step 4: Use Systemd for Process Management

Gunicorn should be managed by systemd, which will ensure it runs as a background process and starts on boot.

First, create a systemd service file:

# /etc/systemd/system/myproject_gunicorn.service
[Unit]
Description=gunicorn daemon for Django project
After=network.target

[Service]
User=your_user
Group=your_group
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/your/venv/bin/gunicorn --workers 3 --bind unix:/path/to/your/project/myproject.sock myproject.wsgi:application

[Install]
WantedBy=multi-user.target

Enable and start Gunicorn with these commands:

# Enable Gunicorn to start on boot
sudo systemctl enable myproject_gunicorn

# Start Gunicorn
sudo systemctl start myproject_gunicorn

# Check the status of the service
sudo systemctl status myproject_gunicorn

Gunicorn will now run as a service and automatically restart if it crashes.

Step 5: Configure Nginx as a Reverse Proxy

Now, let’s configure Nginx as a reverse proxy. Nginx will accept incoming HTTP requests on port 80 and forward them to Gunicorn running on port 8000 (or using a Unix socket for better performance).

Create an Nginx configuration file for your app:

# /etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name your_domain_or_ip;  # Replace with your domain or public IP

    location / {
        proxy_pass http://unix:/path/to/your/project/myproject.sock;  # Unix socket for performance
        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;
    }
}

Enable this site and restart Nginx:

# Enable the Nginx site
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

# Test the Nginx configuration
sudo nginx -t

# Restart Nginx to apply the changes
sudo systemctl restart nginx

Now, users can access your app at http://your_domain_or_ip, and Nginx will forward requests to Gunicorn.

Step 6: Secure the App with SSL (Optional)

It’s a good idea to secure your app with SSL. We recommend using Let’s Encrypt for free SSL certificates.

Here’s how to set up SSL in Nginx:

# /etc/nginx/sites-available/myproject
server {
    listen 443 ssl;
    server_name your_domain_or_ip;

    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;

    location / {
        proxy_pass http://unix:/path/to/your/project/myproject.sock;
    }
}

Don’t forget to add a redirect from HTTP to HTTPS:

server {
    listen 80;
    server_name your_domain_or_ip;
    return 301 https://$host$request_uri;
}

Step 7: Troubleshooting Common Issues

As you deploy your Django app, you may run into some common errors. Here’s how to handle them:

  • Gunicorn Not Starting: If Gunicorn fails to start, check the logs with sudo journalctl -u myproject_gunicorn for error details.
  • 403 Forbidden Error: If you’re seeing a 403 error, ensure that Nginx has permission to access the Gunicorn socket file. Use ls -l /path/to/your/project/myproject.sock to check its ownership and permissions.
  • 500 Internal Server Error: This is usually a Django configuration issue. Check the logs in /var/log/nginx/error.log or use sudo journalctl -u myproject_gunicorn.

With these fixes, your app should be running smoothly in production!