# How To Set Up Secure Django with Postgres, Nginx, and Gunicorn on Ubuntu

## Introduction

Django is a robust web framework designed to help you rapidly build Python applications or websites. While Django provides a simplified local development server, you’ll need a more secure and scalable server setup for production environments.

This guide will walk you through setting up Django on Ubuntu 22.04 (or a supported version) with a PostgreSQL database. We’ll configure the Gunicorn application server to interface with your Django app and set up Nginx to reverse proxy to Gunicorn, leveraging its security and performance benefits. Additionally, we’ll deploy the application from GitHub using DigitalOcean’s App Platform, allowing automatic scaling and management.

By isolating Django within a virtual environment, you’ll be able to handle project dependencies independently. Once your database and application are live, Gunicorn will translate client requests into Python calls. Nginx will manage connections and serve static files efficiently.

Let’s dive into setting everything up!

---

## Prerequisites

Ensure you’re using Ubuntu 22.04 or newer, as older versions like 16.04 are no longer supported. Follow our server setup guide to create a non-root user with `sudo` privileges and an active firewall.

---

## Steps to Set Up Django with PostgreSQL, Gunicorn, and Nginx

1. **Install Packages from Ubuntu Repositories**
    
2. **Create PostgreSQL Database and User**
    
3. **Set Up a Python Virtual Environment**
    
4. **Create and Configure Your Django Project**
    
5. **Complete the Django Setup**
    
6. **Test Gunicorn’s Ability to Serve Django**
    
7. **Create Gunicorn** `systemd` Socket and Service Files
    
8. **Check Gunicorn Socket File**
    
9. **Configure Nginx to Proxy Gunicorn**
    
10. **Troubleshoot and Complete Setup**
    

---

### Step 1 — Install Packages from Ubuntu Repositories

Start by updating your package lists and installing the required packages:

```bash
sudo apt update
sudo apt install python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl
```

This will install Python, PostgreSQL, and Nginx, alongside development libraries and tools required for your project.

---

### Step 2 — Create PostgreSQL Database and User

Set up your PostgreSQL database and user:

1. Log in as the `postgres` user and access PostgreSQL:
    

```bash
sudo -u postgres psql
```

2. Create the database and user for your Django project:
    

```sql
CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD 'password';
```

3. Configure the user’s access and settings:
    

```sql
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;
```

4. Exit PostgreSQL:
    

```sql
\q
```

---

### Step 3 — Set Up a Python Virtual Environment

Create a virtual environment and install Django:

1. Create and navigate to your project directory:
    

```bash
mkdir ~/myprojectdir
cd ~/myprojectdir
```

2. Create and activate a virtual environment:
    

```bash
python3 -m venv myprojectenv
source myprojectenv/bin/activate
```

3. Install Django, Gunicorn, and PostgreSQL adapter:
    

```bash
pip install django gunicorn psycopg2-binary
```

---

### Step 4 — Create and Configure a New Django Project

1. Create a new Django project:
    

```bash
django-admin startproject myproject .
```

2. Update Django settings:
    

* Modify `ALLOWED_HOSTS` in `myproject/`[`settings.py`](http://settings.py):
    

```yaml
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'localhost']
```

* Configure PostgreSQL database settings:
    

```yaml
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}
```

* Configure static files:
    

```yaml
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
```

---

### Step 5 — Complete the 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
```

4. Open firewall for testing:
    

```bash
sudo ufw allow 8000
```

5. Test the development server:
    

```bash
python manage.py runserver 0.0.0.0:8000
```

Visit [`http://your_server_domain_or_IP:8000`](http://your_server_domain_or_IP:8000) in your browser to verify that Django is running.

---

### Step 6 — Test Gunicorn’s Ability to Serve the Project

Stop the Django development server and test Gunicorn:

1. Run Gunicorn:
    

```bash
gunicorn --bind 0.0.0.0:8000 myproject.wsgi
```

2. Visit your server again to ensure the app is served.
    

---

### Step 7 — Create Gunicorn `systemd` Socket and Service Files

Create socket and service files for Gunicorn:

1. Create a Gunicorn socket file:
    

```yaml
sudo nano /etc/systemd/system/gunicorn.socket
```

Add the following content:

```yaml
[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 this content:

```yaml
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=your_user
Group=www-data
WorkingDirectory=/home/your_user/myprojectdir
ExecStart=/home/your_user/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 — Check the Gunicorn Socket File

Verify that Gunicorn started properly:

```bash
sudo systemctl status gunicorn.socket
```

You should see a message indicating that the socket is active.

Check for the socket file:

```bash
file /run/gunicorn.sock
```

If there’s an issue, check the logs:

```bash
sudo journalctl -u gunicorn.socket
```

---

### Step 9 — Configure Nginx to Proxy Gunicorn

1. Create a new Nginx server block:
    

```bash
sudo nano /etc/nginx/sites-available/myproject
```

Add this content:

```yaml
server {
    listen 80;
    server_name your_server_domain_or_IP;

    location / {
        proxy_pass http://unix:/run/gunicorn.sock;
    }

    location /static/ {
        alias /home/your_user/myprojectdir/static/;
    }
}
```

2. Enable the configuration:
    

```bash
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
sudo nginx -t
```

3. Restart Nginx:
    

```bash
sudo systemctl restart nginx
```

---

### Step 10 — Troubleshoot Nginx and Gunicorn

If you encounter any issues, check Nginx’s error log:

```bash
sudo journalctl -u nginx
```

And Gunicorn’s logs:

```bash
sudo journalctl -u gunicorn
```

If everything is working, your Django application should now be live, served via Nginx and Gunicorn with PostgreSQL as the database backend!
