Set Up Django with PostgreSQL Nginx and Gunicorn on Ubuntu

Author: Daniel Marsh | Published: February 5, 2025 | Category: Infrastructure

Comprehensive guide for setting up Django with PostgreSQL, Nginx, and Gunicorn on Ubuntu 18.04 to ensure optimal performance and security

Step 1: Log in as root and create a user with sudo privileges 

First, log in to your server as the root user and create a new user with administrative privileges: 

adduser "username"   
usermod -aG sudo "username" 

This step ensures that you have a user with the necessary permissions to perform administrative tasks. 

 

Step 2: Set up a basic firewall 

To secure your server, enable the firewall and allow incoming SSH connections: 

ufw allow OpenSSH   
ufw enable 

This ensures your server is protected while enabling secure remote access. 

 

Step 3: Clone your Git repository and set up SSH keys 

Switch to the new user and create an SSH key for GitHub access: 

sudo su - "username"   
ssh-keygen -t rsa -b 4096 -C your_email@example.com 

Add the public key to your GitHub repository's deploy keys and clone your repository: 

git clone git@github.com:username/repository.git 

This step sets up SSH authentication for secure access to your code repository. 

 

Step 4: Install necessary packages 

Ensure your system is up-to-date and install the required packages: 

sudo apt update   
apt list --upgradable   
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl 

These packages are essential for setting up your Django environment, PostgreSQL database, and Nginx server. 

 

Step 5: Create the PostgreSQL database and user 

Create a database and user for your Django project: 

sudo -u postgres psql 
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; 
\q 

This step configures PostgreSQL to work with your Django application. 

 

Step 6: Set up a Python virtual environment and install dependencies 

Create a virtual environment and install the necessary Python packages: 

sudo -H pip3 install --upgrade pip   
sudo -H pip3 install virtualenv   
cd myproject   
virtualenv myprojectenv   
source myprojectenv/bin/activate   
pip install django gunicorn psycopg2-binary   
pip install -r requirements.txt 

This ensures that your Django project has the right dependencies isolated in a virtual environment. 

 

Step 7: Complete the initial Django project setup 

Run migrations, create a superuser, and collect static files: 

python manage.py makemigrations   
python manage.py migrate   
python manage.py createsuperuser   
python manage.py collectstatic   
Test the project by running the server temporarily: 
sudo ufw allow 8000   
python manage.py runserver 0.0.0.0:8000 

You can now access your project through your server's IP address or domain name on port 8000. 

 

Step 8: Test Gunicorn 

Verify that Gunicorn can serve your project: 

gunicorn --bind 0.0.0.0:8000 myproject.wsgi 
deactivate 

This ensures that Gunicorn is set up correctly and serves your project. 

 

Step 9: Create systemd socket and service files for Gunicorn 

Create the systemd socket and service files to manage Gunicorn: 

  1. Gunicorn Socket: 
sudo nano /etc/systemd/system/gunicorn.socket 

 

Add the following configuration for the Gunicorn socket: 

[Unit] 
Description=gunicorn socket 
  
[Socket] 
ListenStream=/run/gunicorn.sock 
  
[Install] 
WantedBy=sockets.target 

 

  1. Gunicorn Service: 

sudo nano /etc/systemd/system/gunicorn.service 

Add the following configuration for the Gunicorn service, replacing username with your actual username and directory paths: 

[Unit] 
Description=gunicorn daemon 
Requires=gunicorn.socket 
After=network.target 
  
[Service] 
User=username 
Group=www-data 
WorkingDirectory=/home/username/myprojectdir 
ExecStart=/home/username/myprojectdir/myprojectenv/bin/gunicorn \ 
          --access-logfile - \ 
          --workers 3 \ 
          --bind unix:/run/gunicorn.sock \ 
          myproject.wsgi:application 
  
[Install] 
WantedBy=multi-user.target 

Start and enable the Gunicorn socket: 

sudo systemctl start gunicorn.socket   
sudo systemctl enable gunicorn.socket 

This step ensures Gunicorn runs as a system service. 

 

Step 10: Test the Gunicorn socket 

Test the socket activation and restart the Gunicorn service if needed: 

sudo systemctl status gunicorn   
curl --unix-socket /run/gunicorn.sock localhost   
sudo systemctl daemon-reload   
sudo systemctl restart gunicorn 

This confirms that Gunicorn can serve your application. 

 

Step 11: Configure Nginx to proxy to Gunicorn 

Create an Nginx server block to proxy requests to Gunicorn: 

sudo nano /etc/nginx/sites-available/my_domain_name 

Add the following configuration for Nginx: 

server { listen 80; server_name server_domain_or_IP; 
location = /favicon.ico { access_log off; log_not_found off; } 
location /static/ { 
    root /home/username/myprojectdir; 
} 
location /media/ { 
    root /home/username/myprojectdir; 
} 
location / { 
    include proxy_params; 
    proxy_pass http://unix:/run/gunicorn.sock; 
} 
  
} 

Enable the site by linking it to the sites-enabled directory: 

sudo ln -s /etc/nginx/sites-available/my_domain_name /etc/nginx/sites-enabled 

Test the Nginx configuration for syntax errors: 

sudo nginx -t 

If no errors are reported, restart Nginx: 

sudo systemctl restart nginx 

Update your firewall settings to allow Nginx traffic: 

sudo ufw allow 'Nginx Full'   
sudo ufw delete allow 8000 

Your Django app should now be accessible via your domain or IP address. 

 

Step 12: Secure Nginx with SSL using Let's Encrypt 

Secure your site with HTTPS by installing Certbot and obtaining an SSL certificate: 

sudo snap install --classic certbot 
sudo ln -s /snap/bin/certbot /usr/bin/certbot 
sudo certbot --nginx -d your_domain -d www.your_domain 
sudo certbot renew --dry-run 

This step ensures your server is secure and accessible over HTTPS. 

 

Conclusion 

Congratulations! You have successfully set up Django with PostgreSQL, Gunicorn, and Nginx on an Ubuntu 18.04 server. This configuration ensures that your Django application runs efficiently, securely, and with optimal performance in a production environment. 

To keep your application running smoothly, regularly update your system, monitor server logs, and renew your SSL certificate when needed. You may also consider setting up automatic deployment with GitHub Actions or a CI/CD pipeline for smoother updates. 

If you encounter any issues, check the logs using: 

sudo journalctl -u gunicorn   
sudo tail -f /var/log/nginx/error.log   

 

By following these best practices, your Django application will remain fast, secure, and scalable. Happy coding! 🚀