# Setting Up a Secure Django Environment with PostgreSQL, Nginx, and Gunicorn on Ubuntu

## Introduction

Django is a powerful web framework that allows you to quickly build robust applications in Python. While its local development server is great for development, production environments require a more secure and scalable setup.

In this guide, we'll walk you through the process of deploying a Django project on an Ubuntu server with a PostgreSQL database, using Gunicorn to serve the application and Nginx as a reverse proxy. This setup enhances security and performance by leveraging the strengths of each component.

We'll also discuss how to configure systemd to manage Gunicorn and set up a virtual environment for isolating dependencies.

## Prerequisites

* An Ubuntu 22.04 server or newer with a non-root user and sudo privileges
    
* An active firewall
    
* A registered domain name (optional but recommended)
    

---

## Step 1: Install Required Packages

1. First, update your package lists:
    
    ```bash
    sudo apt update
    sudo apt upgrade -y
    ```
    
2. Next, install Python, PostgreSQL, and Nginx, along with other dependencies:
    
    ```bash
    sudo apt install python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl -y
    ```
    

---

## Step 2: Configure PostgreSQL Database

1. Switch to the `postgres` user:
    
    ```bash
    sudo -u postgres psql
    ```
    
2. Create a new PostgreSQL database and user, replacing `myproject` and `myprojectuser` with your project’s name:
    
    ```sql
    CREATE DATABASE myproject;
    CREATE USER myprojectuser WITH PASSWORD 'password';
    ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
    ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
    ALTER ROLE myprojectuser SET timezone TO 'UTC';
    GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
    ```
    
3. Exit the PostgreSQL prompt:
    
    ```sql
    \q
    ```
    

---

## Step 3: Set Up the Python Virtual Environment

1. Create and navigate to your project directory:
    
    ```bash
    mkdir ~/myprojectdir
    cd ~/myprojectdir
    ```
    
2. Set up a virtual environment and activate it:
    
    ```bash
    python3 -m venv myprojectenv
    source myprojectenv/bin/activate
    ```
    
3. Install Django, Gunicorn, and the PostgreSQL adapter:
    
    ```bash
    pip install django gunicorn psycopg2-binary
    ```
    

---

## Step 4: Create and Configure the Django Project

1. Start a new Django project:
    
    ```bash
    django-admin startproject myproject .
    ```
    
2. Configure `ALLOWED_HOSTS` in `myproject/`[`settings.py`](http://settings.py):
    
    ```python
    ALLOWED_HOSTS = ['your_domain.com', 'your_server_ip', 'localhost']
    ```
    
3. Set up the PostgreSQL database connection in `myproject/`[`settings.py`](http://settings.py):
    
    ```python
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': 'myproject',
            'USER': 'myprojectuser',
            'PASSWORD': 'password',
            'HOST': 'localhost',
            'PORT': '',
        }
    }
    ```
    
4. Set up static files:
    
    ```python
    STATIC_URL = '/static/'
    STATIC_ROOT = BASE_DIR / 'static'
    ```
    

---

## Step 5: Complete Django Setup

1. Migrate the database schema:
    
    ```bash
    python manage.py migrate
    ```
    
2. Create a Django superuser:
    
    ```bash
    python manage.py createsuperuser
    ```
    
3. Collect static files:
    
    ```bash
    python manage.py collectstatic
    ```
    

---

## Step 6: Test Gunicorn's Ability to Serve the Project

1. Run Gunicorn to test serving your application:
    
    ```bash
    gunicorn --bind 0.0.0.0:8000 myproject.wsgi
    ```
    
2. Visit [`http://your_server_ip:8000`](http://your_server_ip:8000) to verify that Django is running.
    

---

## Step 7: Create Gunicorn systemd Socket and Service Files

1. Create a Gunicorn socket file:
    
    ```bash
    sudo nano /etc/systemd/system/gunicorn.socket
    ```
    
    Add the following content:
    
    ```ini
    [Unit]
    Description=gunicorn socket
    
    [Socket]
    ListenStream=/run/gunicorn.sock
    
    [Install]
    WantedBy=sockets.target
    ```
    
2. Create a Gunicorn service file:
    
    ```bash
    sudo nano /etc/systemd/system/gunicorn.service
    ```
    
    Add the following content, replacing paths and user details as needed:
    
    ```ini
    [Unit]
    Description=gunicorn daemon
    Requires=gunicorn.socket
    After=network.target
    
    [Service]
    User=user_name
    Group=www-data
    WorkingDirectory=/home/user_name/myprojectdir
    ExecStart=/home/user_name/myprojectdir/myprojectenv/bin/gunicorn \
              --access-logfile - \
              --workers 3 \
              --bind unix:/run/gunicorn.sock \
              myproject.wsgi:application
    
    [Install]
    WantedBy=multi-user.target
    ```
    
3. Start and enable the Gunicorn socket:
    
    ```bash
    sudo systemctl start gunicorn.socket
    sudo systemctl enable gunicorn.socket
    ```
    

---

## Step 8: Configure Nginx as a Reverse Proxy

1. Create an Nginx configuration file:
    
    ```bash
    sudo nano /etc/nginx/sites-available/myproject
    ```
    
    Add the following content:
    
    ```nginx
    server {
        listen 80;
        server_name your_domain.com your_server_ip;
    
        location / {
            proxy_pass http://unix:/run/gunicorn.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 /home/awm/myprojectdir/static/;
        }
    }
    ```
    
2. Enable the configuration and restart Nginx:
    
    ```bash
    sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
    sudo nginx -t
    sudo systemctl restart nginx
    ```
    

---

## Step 9: Troubleshoot and Complete Setup

1. If Nginx or Gunicorn is not running, check their logs:
    
    ```bash
    sudo journalctl -u nginx
    sudo journalctl -u gunicorn
    ```
    

---

Following this setup, your Django application will be served through Nginx and Gunicorn, backed by PostgreSQL for database management, and secured on Ubuntu.
