How to Set Up Django with PostgreSQL, Nginx, and Gunicorn on Ubuntu VPS Server

Last updated 2 weeks, 4 days ago · 10 min read

Welcome! Today, we will discuss how you can host your website on any VPS server. First of all, before thinking about hosting your website, it's important to know that the website we are hosting today is built using Django. We have already developed our Django website, and we are going to be hosting it on a VPS server. We will set it up to work with the PostgreSQL Database, Nginx server, and Gunicorn on Ubuntu 24.04 (LTS).

What you need before hosting your website

  1. You need a Django website ready to be shipped to production.
  2. Buy a VPS server
  3. Buy your domain name
If you have yet to get your domain name, you can use Dynadot Domains or NameCheap Domains. I will be using Dynadot and Namecheap for this tutorial as I am affiliated with them. And if you don't have your server yet, in this tutorial, we're going to be hosting our website on Linode. However, there are other options like DigitalOcean, Vultr , Namecheap VPS , and even Google Cloud. There are several other great cloud providers, but today, we will walk you through the process using Linode. If you're unsure which VPS server to choose, I recommend checking out our detailed guide on the top 5 VPS servers. Explore the best and most affordable options here - Top 5 VPS Servers. The same steps can be applied on DigitalOcean, Namecheap VPS, Vultr, or any VPS server that provides root access and an IP address. So, without wasting much time, let's dive right in! So, firstly, make sure you have your Django website in a file and keep it organized in a separate folder. Also, have your domain name written down somewhere for easy reference. Now, go to the Linode and create an account. Once you are on your dashboard, click on the Linode and create Linode. Check the pictures below. Select your server location, OS, and OS version, in our case Ubuntu 24.04. Select your Linode plan depending on your use case. Add a label and password for your Linode. Check and recheck everything and scroll down to create Linode. Wait until it's fully booted, you will get an IP address dedicated to your server. Next, grab your new IP address and remember your password. There's also an option to use an SSH key to access your server. However, in this tutorial, we're going to be using our password for simplicity. You can change to SSH keys anytime you want. Our servers are called "Linodes" and on DigitalOcean, the servers are called "Droplets," while on other platforms like Vultr, they are often referred to as "Virtual Machines" (VMs). If you are using Digital Ocean, go to the DigitalOcean create page for your Droplet. This is where you'll set up your server. The same thing applies to other platforms, follow their steps until you have your IP address and password.

Accessing Our Server With an SSH Client

Now, we need to get an SSH client. Some options include PuTTY, or you can even use your command line or PowerShell. There's also a powerful SSH client called MobaXterm. For this tutorial, we will be using MobaXterm. If you don't have MobileXterm installed on your system, head to their website, download it and install it. Use this link Okay, so once you are done with the installation of MobaXterm. Open your MobaXterm application. Click on the Session button, it will pop up a session setting box. Click on SSH and add your IP address in the Remote host field > Check the Specify Name and add root in the field. Trace the ok button below and click it. You will be prompted to enter the password you used while creating your server. Enter the password and hit Enter. Since this is your first time logging into the server, it will prompt you to... It will prompt you, to ask if you want to connect to this server. You can hit Enter. Now we have successfully logged in to our new server, we need to start installing the relevant tools to run our server. In our case, we are setting up the environment to power our Django website. This website will use Nginx as the web server, PostgreSQL as our database, and Python as our programming language. So, we need to install Python, PostgreSQL, and Nginx on the server. First, we have to update our server, let's copy the code below and run it. sudo apt update Then let's type in the following command: sudo apt install python3-dev python3.12-venv libpq-dev postgresql postgresql-contrib nginx curl Let's wait for a moment while all our software is installed. It's time to create our database, let's run the code below: sudo -u postgres psql Now we will be inside the PostgreSQL database. It's time to create our database. CREATE DATABASE mydb; Don't forget to end all the SQL statements with a semicolon, please. We are supposed to create a database user to connect with Django. But in the new Django and PostgreSQL setup, there's a permission error that can restrict you when trying to make migrations from your Django app to the database if you are using a newly created user. So, we are going to skip creating a new user. Instead, we will use the existing "postgres" user, which is the main user of the database. This error doesn't affect the PostgreSQL user but can impact new users created for a database. What we will do is create a password for our PostgreSQL user and use that user as our database user for the Django app. Okay, let's type "\password" and it will prompt us to add a password for the PostgreSQL user. We enter our desired password, confirm it by entering it again, and then hit Enter. Now, our PostgreSQL user has a password.
Now our database user is "postgres" and our password is the new password we created.
Okay, so now it's time to create our Django project. We already have our Django project locally. In MobaXterm, you can't directly upload a folder.
So, let's start the Django project again here.
We need to move to the root directory of our Ubuntu server. Then, create a home folder if it doesn't already exist. cd /.. Will move use to the root directory. mkdir home to create our home folder.

Note: the command cd (change directory) is used to navigate the command line interface. If you want to move one-inch backward use "cd ..", to move frontward use cd then the name of the available folder Ex: "cd home" or "cd home/mywebsite", but make sure the folder(s) exist there before trying to move to it. You can check the available folders with "ls" command. You can also move to the root directory one touch using the "cd /.." command.

Now we have created our home and project folder, let's create our virtual environment. python3 -m venv myvitname
Let's wait for a moment. Once the virtual environment is created, we need to activate it. source myvitname/bin/activate
Once we've activated our virtual environment, it's time to install some packages. We need Django, Gunicorn, Psycopg, pillow, etc. pip install django gunicorn psycopg[binary] pillow Now is the time to create our Django project. django-admin startproject mynewproject Once you have created your Django project, move straight to the settings.py and open it.
MobaXterm has a file editor, you can use that to edit your files or right-click on the file and select "open with" It will show you multiple options, and you can select VS code.
Now, remember your domain name and your IP address. In the settings.py file, you'll find the "ALLOWED_HOSTS" section. You may have omitted this in your local development environment, but now it's time to fill that in for your Django project.
In the "ALLOWED_HOSTS," add the domain name you bought from Dynadot or Namecheap. Include both the www version and the non-www version. Our domain will not work yet, but let's have them there, for now, only the IP address will work at this point.
Then, copy the IP address from your server and add it to the list. If you fail to add all of them to the list Django will not allow them to serve your website. So we also need to add localhost to our list since our PostgreSQL database is available on our local server.
This is how our ALLOWED_HOST will look like: ALLOWED_HOSTS = ['18.28.00.15', 'withubb.com', 'www.withubb.com', 'localhost'] Let's move down to the place where we have the database settings, it has sqlite3 database by default change it to our PostgreSQL database. DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "NAME": "mydatabase", "USER": "mydatabaseuser", "PASSWORD": "mypassword", "HOST": "localhost", "PORT": "", } } Scroll down to where we have the media and static root and add the configuration below so Django can serve your static and media root. STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'static/' MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR / 'mediafiles/' Run the following commands to create the initial migrations and apply them to your PostgreSQL database: python manage.py makemigrations python manage.py migrate To create an admin user, run: python manage.py createsuperuser You will be prompted to enter a username, email, and password. Gather all static content by running: python manage.py collectstatic Confirm the operation when prompted, and the static files will be placed in the `static` directory. Enable your fire wall and allow traffic on port 8000 to test the development server: sudo ufw allow 8000 sudo ufw enable Test your project by starting the development server: python manage.py runserver 0.0.0.0:8000 Visit your server's IP or domain followed by `:8000. For the admin interface, append `/admin` to the URL and log in using your admin credentials. Test Gunicorn's ability to serve your project, move to the project and run: gunicorn --bind 0.0.0.0:8000 mywebsite.wsgi The admin interface will not have styling at this point, as Gunicorn doesn't serve static files. Press `CTRL+C` to stop the server. Exit your virtual environment by typing: deactivate To automate Gunicorn startup, create a systemd socket and service: Create the socket file: sudo nano /etc/systemd/system/gunicorn.socket Add the following: [Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target Next, create the service file: sudo nano /etc/systemd/system/gunicorn.service Add this content: [Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=root Group=www-data WorkingDirectory=/home/mywebsite/ ExecStart=/home/mywebsite/myvitname/bin/gunicorn \ --access-logfile - \ --workers 3 \ --bind unix:/run/gunicorn.sock \ mywebsite.wsgi:application [Install] WantedBy=multi-user.target Enable and start the Gunicorn socket: sudo systemctl start gunicorn.socket sudo systemctl enable gunicorn.socket Verify the gunicorn socket is active: sudo systemctl status gunicorn.socket To use Nginx as a reverse proxy, create a server block: sudo nano /etc/nginx/sites-available/mywebsite Add the following: server { server_name mywebsite.com, www.mywebsite.com, my_server_IP; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/mywebsite/mywebsite ; } location / { include proxy_params; proxy_pass http://unix:/run/gunicorn.sock; } } Enable the configuration: sudo ln -s /etc/nginx/sites-available/mywebsite /etc/nginx/sites-enabled sudo nginx -t sudo systemctl restart nginx ufw is our firewall, you need to check the status first: sudo ufw status If inactive, you need to enable it and add rules so you don't lock yourself out. sudo ufw enable It will prompt you if you want to override existing rules, input Y, and enter. Open port 80 for Nginx and remove the development server rule: sudo ufw delete allow 8000 sudo ufw allow openSSH sudo ufw allow 'Nginx Full'

At this stage, your application should be live and accessible via your server's domain or IP address. You've done an amazing job following along! In the next chapter, we'll cover advanced Nginx configurations, securing your website with Certbot's free SSL certificate, and setting up DNS records for your domain name.

More Articles

The Importance of Domain Extensions: .com Vs .net Vs .org Vs .ng

.org, .com and .net Choosing the right domain extensions

2 days, 5 hours ago · 6 min read
How to Become a Full Stack Developer: Essential Skills You Need

Skills to Become a Full Stack Developer in 2025

5 days, 6 hours ago · 11 min read
Choosing the Right Database for Your Business Website

How to Choose the right Database for Your Business Website

5 days, 6 hours ago · 6 min read
Common Programming Mistakes and How to Avoid Them

Avoiding common programming mistakes: best practices for quality code

1 week, 6 days ago · 16 min read
A Comprehensive Guide to Domain Parking and Leveraging It for Passive Income

What is Domain parking and how to earn money from it ?

1 week, 6 days ago · 8 min read
Essential Elements for Building an SEO-Friendly Website

Steps to Building an SEO-Friendly Website

3 weeks, 2 days ago · 7 min read
The Ultimate guide to building a stunning website: a step by step guide

How to build a stunning website (A step by step guide)

3 weeks, 2 days ago · 12 min read
A Comprehensive Guide to Database Normalization

What is Database Normalization ?

1 month, 1 week ago · 6 min read
How to debug a code: A comprehensive guide for beginners

What is debugging? How to debug a code for beginners

1 month, 1 week ago · 8 min read
How to Choose the Right Web Development Framework for Your Project

Tips for Choosing the Right Web Development Framework for Your Project

1 month, 2 weeks ago · 6 min read