How to Deploy Django on VPS (Ubuntu + Nginx + Gunicorn 2026)

Deploying a Django application on a VPS transforms your project into a reliable production environment capable of handling real users. A proper deployment setup improves performance, security, scalability, and long term application stability for growing websites.

Many developers successfully build Django applications locally but face challenges while deploying them on a live Ubuntu server. Understanding each deployment step helps avoid configuration mistakes, downtime, unnecessary troubleshooting, and security issues later.

This guide explains how to deploy Django on an Ubuntu VPS using Gunicorn and Nginx, configure essential production settings, enable HTTPS, and verify everything works correctly before making your application publicly accessible.


What You’ll Need Before You Start

Before deploying your Django application, it’s worth making sure your server and project are ready. Having the required software and permissions in place will help you avoid common deployment errors later in the process. The requirements below are suitable for most personal projects, business websites, APIs, and web applications running on a Linux VPS.

VPS Requirements

Your server should meet these minimum requirements:

RequirementRecommended
Operating SystemUbuntu 22.04 LTS or Ubuntu 24.04 LTS
RAMMinimum 1 GB (2 GB or more recommended)
CPU1 vCPU minimum
StorageAt least 20 GB SSD or NVMe SSD
AccessRoot user or a user with sudo privileges
NetworkPublic IPv4 address
SSHEnabled for remote server access

If you plan to host a larger Django application with higher traffic, consider using additional CPU cores, more memory, and NVMe storage for better performance.

Software You’ll Use

This deployment relies on a few essential tools that work together to run your Django application efficiently.

  • Python 3 – The programming language required to run Django.
  • pip – Python’s package manager for installing Django and other dependencies.
  • Python Virtual Environment (venv) – Creates an isolated environment so your project’s packages don’t interfere with system wide Python packages.
  • Django – The web framework powering your application.
  • Gunicorn – A production ready WSGI server that runs your Django application.
  • Nginx – A high-performance web server that forwards client requests to Gunicorn and efficiently serves static files.
  • systemd – Manages the Gunicorn service, allowing it to start automatically whenever the VPS reboots.
  • UFW (Uncomplicated Firewall) – Helps protect your server by allowing only the necessary network ports.
  • Git (Optional) – Useful if your project is stored in a Git repository and you want to clone it directly to the VPS.
  • Certbot (Later in this guide) – Used to install a free SSL certificate so your website can run securely over HTTPS.

Prepare Your Django Project

Before you begin, ensure your Django project is in a working state on your local machine. If you’re using Git, push the latest version to your repository so it can be cloned easily on the VPS. If not, keep a copy of the project ready to upload via SFTP or another secure file transfer method.

It’s also a good idea to create a requirements.txt file that lists all your project’s Python dependencies. This makes it easy to install the same packages on the server with a single command and helps keep the deployment consistent.

While not required to complete the deployment, these items will make your production setup more complete:

  • A registered domain name that points to your VPS.
  • SSH key based authentication instead of password login for improved security.
  • A dedicated database server if your application expects heavy traffic.
  • Regular backup snapshots of your VPS before making major configuration changes.

Once these prerequisites are in place, you’re ready to connect to your Ubuntu VPS and begin the deployment process. In the next step, we’ll log in to the server using SSH, update the operating system, and prepare it for installing Django and its required components.


Step 1: Connect to Your Ubuntu VPS Using SSH

The first step is to connect to your Ubuntu VPS through SSH (Secure Shell). SSH provides an encrypted connection between your local computer and the remote server, allowing you to install software, manage files, and configure your Django application securely.

Most VPS providers send your server’s IP address, username, and password (or SSH key details) immediately after the VPS is created. Keep this information handy before proceeding.

Connect to the Server

Open your terminal (Linux/macOS) or use an SSH client such as PuTTY on Windows, then connect to your VPS using the following command:

ssh username@your_server_ip

For example:

ssh root@203.0.113.10

If you’re connecting to the server for the first time, you’ll see a message asking whether you trust the server’s fingerprint.

Are you sure you want to continue connecting (yes/no)?

Type:

yes

and press Enter.

Next, enter your password when prompted. If you’re using SSH keys, authentication will happen automatically without asking for the server password.

After a successful login, you’ll see a command prompt similar to this:

root@ubuntu:~#

or

username@ubuntu:~$

This indicates that you’re now connected to your Ubuntu VPS.

Update the Package Repository

Before installing Python, Django, or any other software, update Ubuntu’s package index to ensure you’re downloading the latest available packages.

Run:

sudo apt update

This command refreshes your server’s package list from the official Ubuntu repositories.

Upgrade Installed Packages

After updating the package list, upgrade any outdated packages already installed on the server.

sudo apt upgrade -y

Depending on how recently the VPS was provisioned, this process may take several minutes.

Keeping your server updated helps:

  • Install the latest security patches.
  • Fix known bugs.
  • Improve system stability.
  • Reduce compatibility issues during deployment.

If the upgrade installs a newer Linux kernel, Ubuntu may recommend restarting the VPS once the process finishes.

Verify Your Ubuntu Version

Before moving forward, verify that your server is running a supported Ubuntu release.

Use the following command:

lsb_release -a

or

cat /etc/os-release

You’ll see output similar to:

Distributor ID: Ubuntu
Description: Ubuntu 24.04 LTS
Release: 24.04
Codename: noble

Both Ubuntu 22.04 LTS and Ubuntu 24.04 LTS work well for Django deployments and receive long term security updates.

Check Your Python Installation (Optional)

Some Ubuntu VPS images already include Python 3. You can verify its availability by running:

python3 --version

If Python is installed, you’ll see output similar to:

Python 3.12.x

If the command returns an error or an older version than expected, don’t worry, we’ll install the required Python packages in the next step.


Step 2: Install Python and Required Packages

With your Ubuntu VPS ready, the next step is to install Python and the system packages required to run a Django application in a production environment. Although many Ubuntu VPS images include Python by default, installing the latest available packages ensures you have all the tools needed for development, dependency management, and deployment.

Update the Package List

If you haven’t updated the package repository recently, run the following command once more:

sudo apt update

This ensures Ubuntu installs the latest available package versions from its official repositories.

Install Python, pip, and Virtual Environment Tools

Now install Python 3, pip, the virtual environment package, and other commonly required development libraries.

sudo apt install python3 python3-pip python3-venv python3-dev build-essential libpq-dev -y

Here’s what each package does:

  • python3 – Installs the Python interpreter.
  • python3-pip – Installs pip, the Python package manager.
  • python3-venv – Lets you create isolated Python virtual environments.
  • python3-dev – Includes Python header files required when compiling certain Python packages.
  • build-essential – Installs essential compilation tools such as GCC and Make.
  • libpq-dev – Required if your Django application uses PostgreSQL.

Note: If your project uses MySQL instead of PostgreSQL, you can install the appropriate MySQL development package later when needed.

Verify the Python Installation

Once the installation completes, confirm that Python is available on your server.

python3 --version

Example output:

Python 3.12.3

The exact version may vary depending on your Ubuntu release and installed updates.

Verify pip Installation

Next, verify that pip was installed successfully.

pip3 --version

Example output:

pip 24.x.x from /usr/lib/python3/dist-packages/pip

This confirms that Python packages can now be installed using pip.

Check the Virtual Environment Tool

Ubuntu should now include the venv module. You can verify it by running:

python3 -m venv --help

If the help page appears without errors, your server is ready to create isolated Python environments for Django projects.

Why Use a Virtual Environment?

One of the most common mistakes beginners make is installing Python packages globally. While it may seem convenient, global installations can create dependency conflicts when multiple projects require different package versions.

A virtual environment solves this problem by giving each Django project its own isolated Python environment. 

This means:

  • Every project can use its own package versions.
  • System Python remains clean and untouched.
  • Updating one project won’t affect another.
  • Deployments become more reliable and easier to reproduce.

Using a virtual environment is considered a standard best practice for Django development and production deployments.

Verify Everything Is Ready

Before moving on, confirm that the essential tools are installed correctly.

Run the following commands:

python3 --version
pip3 --version

If both commands return version information without errors, your server is fully prepared for the next stage.

In the next step, you’ll create a dedicated project directory, set up a Python virtual environment, and activate it before installing Django and your project’s dependencies.


Step 3: Create a Python Virtual Environment

Now that Python and its required packages are installed, it’s time to create a virtual environment for your Django project. A virtual environment isolates your project’s dependencies from the system wide Python installation, making it easier to manage packages and avoid version conflicts.

Whether you’re deploying a personal project or a production application, using a virtual environment is considered a best practice for Django deployments.

Create a Project Directory

First, create a directory where your Django project will be stored. You can choose any location, but many developers keep application files inside their home directory.

For example:

mkdir ~/django-project

Move into the newly created directory:

cd ~/django-project

If you’ve already uploaded or cloned your Django project into another directory, navigate to that location instead.

Create the Virtual Environment

Inside your project directory, create a virtual environment using Python’s built in venv module.

python3 -m venv venv

This command creates a new folder named venv, which contains an isolated Python interpreter along with its own package manager and libraries.

Your project structure will now look similar to this:

django-project/
├── venv/

At this stage, no Python packages have been installed yet.

Activate the Virtual Environment

Before installing Django or any project dependencies, activate the virtual environment.

Run:

source venv/bin/activate

After activation, your terminal prompt will change slightly:

(venv) username@ubuntu:~/django-project$

The (venv) prefix indicates that all Python and pip commands now operate inside the virtual environment instead of the system-wide installation.

Upgrade pip

Before installing project packages, it’s a good idea to update pip to the latest available version.

pip install --upgrade pip

Keeping pip updated helps avoid compatibility issues with newer Python packages and ensures smoother dependency installation.

Verify the Virtual Environment

To confirm that the virtual environment is active, run:

which python

Example output:

/home/username/django-project/venv/bin/python

Similarly, verify pip:

which pip

Example output:

/home/username/django-project/venv/bin/pip

If both commands point to the venv directory, the virtual environment has been activated successfully.

Deactivate the Virtual Environment (Optional)

Whenever you finish working on the project, you can exit the virtual environment by running:

deactivate

Your terminal prompt will return to its normal state.

Don’t worry, you can reactivate the environment at any time using:

source venv/bin/activate

Why This Step Matters

Creating a virtual environment may seem like a small step, but it plays an important role in maintaining a stable production environment. It keeps your Django project self contained, prevents package conflicts, and makes future updates much easier.

This approach is especially useful if you plan to host multiple Python applications on the same VPS, as each project can maintain its own dependencies without affecting the others.

With the virtual environment ready, the server is now prepared to install Django, Gunicorn, and all the libraries your application requires. In the next step, we’ll install the project dependencies and verify that everything is configured correctly before deploying the application.


Step 4: Install Django and Project Dependencies

With your virtual environment active, the next step is to install Django and all the packages your application needs to run. Since every Django project may use different libraries, it’s important to install the exact dependencies required by your application instead of relying on the system wide Python installation.

If you’re deploying an existing project, you should always install packages from its requirements.txt file. This ensures your VPS uses the same package versions as your development environment.

Make Sure the Virtual Environment Is Active

Before installing anything, verify that your virtual environment is active.

If it isn’t, activate it using:\

source venv/bin/activate

Your terminal prompt should display something similar to:

(venv) username@ubuntu:~/django-project$

Install Django

If you’re creating a new Django project or simply want to install Django manually, run:

pip install django

Once the installation is complete, verify it by checking the installed version:

django-admin --version

Example output:

5.2.x

The version number may differ depending on the latest stable Django release available when you perform the installation.

Install Gunicorn

Gunicorn is a production grade WSGI server that runs your Django application. Unlike Django’s built in development server, Gunicorn is designed to handle production traffic efficiently.

Install it with:

pip install gunicorn

Verify the installation:

gunicorn --version

You should see the installed Gunicorn version displayed in the terminal.

Install Project Dependencies

If your Django project already contains a requirements.txt file, install all required packages using:

pip install -r requirements.txt

This command installs every dependency listed in the file, including Django (if specified), database drivers, authentication libraries, API packages, and any third party modules your application depends on.

Using requirements.txt keeps deployments consistent and reduces the risk of missing packages.

Create a Requirements File (Optional)

If you’re deploying a project that doesn’t already include a requirements.txt file, you can generate one after installing all required packages.

Run:

pip freeze > requirements.txt

This saves all installed Python packages and their versions into a file, making future deployments much easier.

Verify Installed Packages

To view the packages currently installed inside your virtual environment, run:

pip list

You’ll see output similar to:

Django
gunicorn
pip
setuptools
wheel
...

The list will vary depending on the dependencies used by your project.

Check for Dependency Issues

Before continuing, it’s a good idea to verify that all installed packages are compatible.

Run:

pip check

If everything is installed correctly, you’ll see a message similar to:

No broken requirements found.

If any dependency conflicts appear, resolve them before moving to the next step to avoid runtime errors later.

Why Installing Dependencies Correctly Matters

A Django application often relies on multiple third party packages for features such as database connectivity, authentication, REST APIs, image processing, caching, or background tasks. Installing these dependencies inside the virtual environment ensures your application runs in a predictable and isolated environment.

It also makes future updates, troubleshooting, and deployments much simpler, especially when working across multiple servers or collaborating with a development team.

At this point, your Python environment is fully prepared, and all required packages are installed. In the next step, you’ll upload or clone your Django project onto the VPS and prepare it for production configuration.


Step 5: Upload or Clone Your Django Project

Now that your Python environment is ready, it’s time to place your Django project on the VPS. There are two common ways to do this:

  • Clone the project from a Git repository (recommended)
  • Upload the project files manually using SFTP or SCP

If you’re actively developing your application, using Git makes future updates much easier. However, if your project isn’t stored in a Git repository, you can upload the files directly to the server.

If Git isn’t installed on your VPS yet, install it first:

sudo apt install git -y

Verify the installation:

git --version

Next, navigate to the directory where you want to store your project.

cd ~/django-project

Clone your repository:

git clone https://github.com/your-username/your-repository.git

After cloning, move into the project folder:

cd your-repository

Replace the repository URL and folder name with your own project details.

Option 2: Upload the Project Manually

If your project isn’t hosted on GitHub, GitLab, or another Git platform, upload it directly from your computer using an SFTP client such as FileZilla or WinSCP, or use the scp command.

For example:

scp -r my-django-project username@your_server_ip:~/django-project/

Once the upload finishes, connect to your VPS and navigate to the project directory:

cd ~/django-project/my-django-project

Verify the Project Structure

Before moving forward, make sure all project files were copied correctly.

Run:

ls

You should see files similar to:

manage.py
requirements.txt
app/
project/
static/
templates/

The exact folders will vary depending on your Django project’s structure.

Activate the Virtual Environment

If you aren’t already inside the virtual environment, activate it again.

source ../venv/bin/activate

If your virtual environment is located elsewhere, adjust the path accordingly.

Your terminal should now display:

(venv) username@ubuntu:~/django-project/your-repository$

Install Project Dependencies

If you haven’t already installed the dependencies from your project’s requirements.txt file, do so now.

pip install -r requirements.txt

This ensures every library required by your application is available before deployment.

Verify Django Can Detect Your Project

Run the following command from the directory containing manage.py:

python manage.py check

If everything is configured correctly, Django will display:

System check identified no issues (0 silenced).

If errors appear, resolve them before continuing. Common issues at this stage include missing dependencies, incorrect project paths, or missing environment variables.

Confirm the Project Directory

Before configuring Django for production, verify you’re working from the correct location.

Run:

pwd

Example output:

/home/username/django-project/your-repository

This directory will be referenced later when configuring Gunicorn and the systemd service, so it’s helpful to note its exact path.

Why This Step Is Important

Successfully copying your project to the VPS is more than just transferring files. This step confirms that your application, dependencies, and project structure are all in place before you begin production configuration.

Taking a few minutes to verify the directory structure and run Django’s built in system checks can save significant troubleshooting time later, especially when configuring Gunicorn, Nginx, and system services.

With your project now available on the server, the next step is to configure Django for a production environment. You’ll disable development settings, configure allowed hosts, prepare static files, and run database migrations to make the application ready for public access.


Step 6: Configure Django for Production

At this stage, your Django project is available on the VPS, but it’s still configured for development. Before making the application publicly accessible, you need to update a few settings to improve security, stability, and performance.

A production configuration ensures your application runs safely behind Gunicorn and Nginx while preventing sensitive information from being exposed.

Open the Django Settings File

Navigate to your project’s settings file. Depending on your project structure, it’s usually located here:

your-project/
├── manage.py
├── your_project/
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py

Open the file using Nano:

nano your_project/settings.py

Replace your_project with your actual Django project name.

Disable Debug Mode

During development, Django displays detailed error pages that are useful for debugging. However, exposing these details on a live server can reveal sensitive information about your application.

Locate:

DEBUG = True
Change it to:
DEBUG = False

Never leave DEBUG enabled on a production server.

Configure ALLOWED_HOSTS

Django only accepts requests from domains or IP addresses listed in the ALLOWED_HOSTS setting.

Update it with your server’s IP address or domain name.

Example:

ALLOWED_HOSTS = [
   "yourdomain.com",
   "www.yourdomain.com",
   "203.0.113.10",
]

If you’re testing before connecting a domain, using the VPS IP address is perfectly acceptable.

Configure Static Files

Production deployments use Nginx to serve static files such as CSS, JavaScript, and images.

Inside settings.py, verify or add the following:

STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"

If your project already contains a STATICFILES_DIRS setting, leave it unchanged unless you need to modify the directory structure.

Configure Media Files (If Your Project Uses Uploads)

If users can upload images, documents, or other files, configure the media settings as well.

MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"

Later, you’ll configure Nginx to serve this directory.

Protect Your Secret Key

Every Django project contains a unique SECRET_KEY used for cryptographic signing. Avoid hardcoding it into your project, especially if the code is stored in a public repository.

Instead of:

SECRET_KEY = "your-secret-key"

Store it as an environment variable.

Example:

import os
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")

Then export it on your server:

export DJANGO_SECRET_KEY="your-secret-key"

For long term deployments, it’s better to load environment variables using tools such as python-dotenv or configure them directly in the Gunicorn systemd service.

Configure the Database

If you’re using SQLite for a small project or testing, no additional changes may be required.

For production applications using PostgreSQL or MySQL, verify that your database settings contain the correct:

  • Database name
  • Username
  • Password
  • Host
  • Port

Always confirm that the database server is running before proceeding.

Apply Database Migrations

After updating your settings, apply all pending migrations.

Run:

python manage.py migrate

If successful, Django will create or update the required database tables.

Collect Static Files

Next, gather all static assets into the STATIC_ROOT directory.

Run:

python manage.py collectstatic

When prompted, type:

yes

Django will copy all static files into the production directory that Nginx will serve later.

Verify the Project Configuration

Before continuing, use Django’s built in system check.

python manage.py check --deploy

If everything is configured correctly, Django will report any security recommendations or confirm that your production settings are ready.

Pay close attention to any warnings. Resolving them now helps prevent deployment issues later.

Test the Application Locally on the VPS

Before introducing Gunicorn and Nginx, verify that Django still starts correctly.

Run:

python manage.py runserver 0.0.0.0:8000

Open your browser and visit:

http://your_server_ip:8000

If your homepage loads successfully, your Django project is functioning correctly.

Press Ctrl + C to stop the development server after confirming everything works.

Important: The Django development server is only for testing. It should never be used to host a production website. In the next step, you’ll replace it with Gunicorn, which is designed to serve Django applications reliably in production.


Step 7: Test Django with Gunicorn

Before configuring Gunicorn as a permanent system service, it’s a good idea to run it manually and verify that your Django application starts correctly. This helps identify configuration issues early, making it easier to troubleshoot before introducing Nginx and systemd.

If Gunicorn can successfully serve your application at this stage, the remaining deployment process becomes much smoother.

Make Sure You’re in the Project Directory

Navigate to the folder that contains your manage.py file.

For example:

cd ~/django-project/your-repository

If your virtual environment isn’t active, activate it again:

source ../venv/bin/activate

Adjust the path if your virtual environment is located elsewhere.

Find Your WSGI Module

Gunicorn needs Django’s WSGI application to start the project.

Your project structure will usually look similar to this:

your-project/
├── manage.py
└── your_project/
   ├── settings.py
   ├── urls.py
   ├── wsgi.py
   └── asgi.py

The important file here is:

your_project/wsgi.py

The module name before .wsgi will be used when starting Gunicorn.

For example:

your_project.wsgi:application

Replace your_project with your actual Django project name throughout this guide.

Start Gunicorn Manually

Run the following command:

gunicorn --bind 0.0.0.0:8000 your_project.wsgi:application

If everything is configured correctly, you’ll see output similar to:

[INFO] Starting gunicorn
[INFO] Listening at: http://0.0.0.0:8000
[INFO] Booting worker with pid: 12345

This means Gunicorn has started successfully and is serving your Django application.

Verify the Application

Open your web browser and visit:

http://your_server_ip:8000

If your website loads correctly, Gunicorn is communicating with Django as expected.

Try navigating through a few pages to confirm that:

  • The homepage loads successfully.
  • CSS and JavaScript files are accessible (if previously collected).
  • Forms work correctly.
  • The Django admin panel opens without errors.
  • Database queries execute normally.

Testing these basic functions now can help detect configuration problems before moving on.

Check for Errors

If the application doesn’t start, Gunicorn usually displays an error message in the terminal.

Some common issues include:

  • Incorrect WSGI module name.
  • Missing Python packages.
  • Invalid ALLOWED_HOSTS configuration.
  • Database connection failures.
  • Missing environment variables.
  • Syntax errors in settings.py.

Read the first error carefully, it often points directly to the root cause.

You can also run:

python manage.py check

to verify that Django detects no configuration issues.

Stop Gunicorn

After confirming that your application works, stop Gunicorn by pressing:

Ctrl + C

This is expected because Gunicorn is currently running in the foreground for testing purposes.

In the next step, you’ll configure Gunicorn to run as a background service using systemd, allowing it to:

  • Start automatically whenever the VPS boots.
  • Restart automatically if it crashes.
  • Run continuously without keeping your terminal session open.

Why Test Gunicorn Before Configuring systemd?

Running Gunicorn manually helps separate application issues from server configuration problems. If something goes wrong later when setting up the systemd service or configuring Nginx, you’ll already know that the Django application itself is working correctly.

This small verification step can save considerable troubleshooting time and provides a solid foundation before completing the production deployment.


Step 8: Create a Gunicorn systemd Service

After confirming that your Django application runs correctly with Gunicorn, the next step is to configure it as a systemd service. This allows Gunicorn to run in the background, start automatically whenever the VPS reboots, and restart itself if it unexpectedly stops.

Using systemd is the standard approach for running Django applications in production because it provides reliable service management and makes monitoring much easier.

Find Your Project Information

Before creating the service file, note the following details from your server:

  • Your Linux username
  • Your project directory
  • Your virtual environment path
  • Your Django project name (the folder containing settings.py and wsgi.py)

For example:

SettingExample
Usernameubuntu
Project Directory/home/ubuntu/django-project/myproject
Virtual Environment/home/ubuntu/django-project/venv
Django Project Namemyproject

You’ll use these values in the service configuration below.

Create the Gunicorn Service File

Create a new systemd service file:

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

Paste the following configuration:

[Unit]
Description=Gunicorn daemon for Django
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/django-project/myproject
Environment="PATH=/home/ubuntu/django-project/venv/bin"
ExecStart=/home/ubuntu/django-project/venv/bin/gunicorn \
   --workers 3 \
   --bind unix:/run/gunicorn.sock \
   myproject.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.target

Before saving the file, replace:

  • ubuntu with your Linux username.
  • /home/ubuntu/django-project/myproject with your actual project path.
  • /home/ubuntu/django-project/venv with your virtual environment path.
  • myproject.wsgi:application with your Django project’s WSGI module.

Using a Unix socket (/run/gunicorn.sock) instead of a TCP port allows Nginx to communicate with Gunicorn more efficiently.

Save the file and exit Nano.

Reload systemd

Whenever a new service file is created or modified, reload the systemd configuration:

sudo systemctl daemon-reload

This command allows Ubuntu to recognize the newly created Gunicorn service.

Start the Gunicorn Service

Start Gunicorn:

sudo systemctl start gunicorn

If no errors appear, the service has started successfully.

Enable Gunicorn at Boot

To make sure Gunicorn starts automatically after every VPS reboot, enable the service:

sudo systemctl enable gunicorn

Ubuntu will create the necessary symbolic links so the service launches during system startup.

Check the Service Status

Verify that Gunicorn is running:

sudo systemctl status gunicorn

A healthy service typically displays output similar to:

● gunicorn.service - Gunicorn daemon for Django
  Loaded: loaded
  Active: active (running)

The important part is:

Active: active (running)

If you see this status, Gunicorn is running correctly in the background.

Press Q to exit the status screen.

Test the Gunicorn Socket

Confirm that the Unix socket has been created:

ls -l /run/gunicorn.sock

If the service is working properly, you’ll see the socket file listed.

This socket will be used by Nginx in the next step to forward incoming HTTP requests to your Django application.

View Gunicorn Logs

If the service doesn’t start, review its logs to identify the cause.

View recent log entries:

sudo journalctl -u gunicorn

To monitor logs in real time while troubleshooting:

sudo journalctl -u gunicorn -f

These logs often reveal issues such as:

  • Incorrect project paths.
  • Missing Python packages.
  • Invalid environment variables.
  • Database connection errors.
  • Incorrect WSGI module names.
  • Permission problems.

Resolving these issues before configuring Nginx will make the remaining deployment process much smoother.

Useful Gunicorn Commands

As you maintain your application, you’ll frequently use these commands:

Restart the service:

sudo systemctl restart gunicorn

Stop the service:

sudo systemctl stop gunicorn

Start it again:

sudo systemctl start gunicorn

Check its current status:

sudo systemctl status gunicorn

These commands are especially useful after deploying new code or updating project dependencies.

Why Use systemd?

Running Gunicorn manually works for testing, but it’s not practical for a production server. A systemd service keeps your application running continuously, restarts it automatically if it crashes, and ensures it comes back online after a system reboot.

With Gunicorn now running as a managed background service, your Django application is ready to receive requests. In the next step, you’ll configure Nginx as a reverse proxy to handle incoming traffic, serve static files efficiently, and forward application requests to Gunicorn through the Unix socket.


Step 9: Configure Nginx as a Reverse Proxy

With Gunicorn running as a background service, the next step is to configure Nginx. Instead of exposing Gunicorn directly to the internet, Nginx acts as a reverse proxy that receives incoming HTTP and HTTPS requests, serves static files efficiently, and forwards dynamic requests to your Django application through the Gunicorn socket.

This architecture is widely used for Django production deployments because it improves performance, enhances security, and provides greater flexibility for future scaling.

Install Nginx

If Nginx isn’t already installed on your VPS, install it using the following command:

sudo apt install nginx -y

After the installation completes, verify that Nginx is running:

sudo systemctl status nginx

If the service is active, you’ll see output similar to:

Active: active (running)

If Nginx isn’t running, start it manually:

sudo systemctl start nginx

You can also enable it to start automatically whenever the server reboots:

sudo systemctl enable nginx

Create an Nginx Server Block

Instead of modifying the default configuration, create a separate server block for your Django application.

Create a new configuration file:

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

Replace myproject with a meaningful name for your website.

Add the Nginx Configuration

Paste the following configuration into the file:

server {
   listen 80;
   server_name yourdomain.com www.yourdomain.com your_server_ip;
   location = /favicon.ico {
       access_log off;
       log_not_found off;
   }
   location /static/ {
       alias /home/ubuntu/django-project/myproject/staticfiles/;
   }
   location /media/ {
       alias /home/ubuntu/django-project/myproject/media/;
   }
   location / {
       include proxy_params;
       proxy_pass http://unix:/run/gunicorn.sock;
   }
}

Before saving the file, replace:

  • yourdomain.com with your actual domain name.
  • your_server_ip with your VPS IP address.
  • /home/ubuntu/django-project/myproject/ with your project’s actual location.

If your project doesn’t use uploaded media files, you can remove the /media/ block.

Enable the Site

Create a symbolic link so Nginx loads the new configuration.

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

If the default Nginx site is still enabled, you can disable it to avoid configuration conflicts:

sudo rm /etc/nginx/sites-enabled/default

Test the Nginx Configuration

Before restarting the service, always test the configuration for syntax errors.

Run:

sudo nginx -t

If everything is correct, you’ll see:

nginx: the configuration file syntax is ok
nginx: configuration file test is successful

If any errors appear, fix them before proceeding.

Restart Nginx

Apply the new configuration by restarting Nginx.

sudo systemctl restart nginx

Alternatively, you can reload the configuration without interrupting existing connections:

sudo systemctl reload nginx

Verify the Website

Open your browser and visit:

http://your_server_ip

or, if you’ve already configured DNS: http://yourdomain.com

If everything is configured correctly, your Django application should now load through Nginx instead of the Django development server or the manually started Gunicorn process.

Verify Static Files

Navigate through your website and confirm that static assets load correctly.

Check that:

  • CSS styles are applied.
  • JavaScript files load without errors.
  • Logos and images appear correctly.
  • The Django admin interface displays proper styling.

If the website loads but appears unstyled, it’s usually because:

  • collectstatic wasn’t executed.
  • STATIC_ROOT is incorrect.
  • The Nginx alias path doesn’t match your Django configuration.

Correcting these issues should restore the missing assets.

Useful Nginx Commands

While managing your server, these commands are commonly used:

Check service status:

sudo systemctl status nginx

Restart Nginx:

sudo systemctl restart nginx

Reload the configuration:

sudo systemctl reload nginx

Stop Nginx:

sudo systemctl stop nginx

View recent error logs:

sudo tail -f /var/log/nginx/error.log

These commands are particularly useful when troubleshooting configuration issues or after making changes to your server block.

Why Nginx Is Used with Django

Although Gunicorn runs your Django application, it isn’t designed to serve static assets efficiently or manage client connections on its own. Nginx complements Gunicorn by handling these responsibilities.

Using Nginx provides several important advantages:

  • Efficiently serves static and media files.
  • Acts as a reverse proxy between users and Gunicorn.
  • Supports HTTPS with SSL certificates.
  • Handles multiple client connections with low resource usage.
  • Improves application security by keeping Gunicorn isolated from direct public access.

With Nginx now forwarding requests to Gunicorn, your Django application is running through a production ready web server. In the next step, you’ll configure the UFW firewall to allow HTTP and HTTPS traffic while keeping your VPS secure.


Step 10: Allow HTTP and HTTPS Through the Firewall

A firewall is one of the simplest ways to improve your server’s security. By default, it blocks unwanted incoming connections and allows only the services you explicitly permit. On Ubuntu, the recommended firewall is UFW (Uncomplicated Firewall), which provides an easy way to manage firewall rules from the command line.

Before making your Django application publicly accessible, configure UFW to allow web traffic while keeping unnecessary ports closed.

Important: If you’re connected to your VPS through SSH, always allow SSH access before enabling the firewall. Otherwise, you could lock yourself out of the server.

Check Whether UFW Is Installed

Most Ubuntu installations include UFW by default. You can verify this by running:

sudo ufw status

If UFW isn’t installed, install it with:

sudo apt install ufw -y

Allow SSH Connections

Before enabling the firewall, make sure SSH access is allowed.

sudo ufw allow OpenSSH

Verify the rule:

sudo ufw status

You should see an entry similar to:

OpenSSH                    ALLOW       Anywhere

Allow HTTP and HTTPS Traffic

Since your Django application is being served through Nginx, allow both HTTP (port 80) and HTTPS (port 443).

The easiest way is to use the predefined Nginx profile:

sudo ufw allow 'Nginx Full'

This opens:

  • Port 80 (HTTP)
  • Port 443 (HTTPS)

If you only want to allow HTTP temporarily, you can use:

sudo ufw allow 'Nginx HTTP'

Later, after installing an SSL certificate, you can switch to the Nginx Full profile.

Enable the Firewall

Once the required rules are in place, enable UFW.

sudo ufw enable

When prompted, type:

y
and press Enter.

The firewall is now active and protecting your server.

Verify Firewall Rules

Check the current firewall configuration:

sudo ufw status

A typical configuration looks similar to:

Status: active
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

This confirms that SSH, HTTP, and HTTPS traffic are permitted while other unsolicited connections remain blocked.

Test Website Accessibility

Open your browser and visit:

http://your_server_ip

or

http://yourdomain.com

If your website loads normally, the firewall is configured correctly.

If the site is unreachable, double check that:

  • Nginx is running.
  • Gunicorn is active.
  • DNS records (if using a domain) point to the correct VPS.
  • The required UFW rules are enabled.

Useful UFW Commands

As you continue managing your VPS, these commands are particularly useful.

View all firewall rules:

sudo ufw status numbered

Allow a specific port:

sudo ufw allow 8000

Delete a firewall rule:

sudo ufw delete allow 8000

Disable the firewall temporarily:

sudo ufw disable

Reload firewall rules:

sudo ufw reload

In most production environments, you won’t need to open additional ports unless you’re running other services such as a database, mail server, or monitoring tools.

Why a Firewall Matters

Even if your Django application is configured correctly, leaving unnecessary ports open can expose your server to unwanted traffic and automated attacks. A properly configured firewall reduces this risk by limiting access to only the services your application actually needs.

With UFW configured, your VPS is now better protected while remaining fully accessible to website visitors. In the next step, you’ll point your domain name to the VPS, allowing users to access your Django application through a custom domain instead of the server’s IP address.


Step 12: Secure Your Django Website with a Free SSL Certificate

At this point, your Django application is accessible through your domain over HTTP. The final step before going live is to enable HTTPS by installing an SSL certificate.

HTTPS encrypts the communication between your visitors and your server, protecting sensitive information such as login credentials, contact forms, and session cookies. It also improves user trust, and modern browsers mark websites without HTTPS as “Not Secure.”

One of the easiest ways to enable HTTPS on Ubuntu is by using Let’s Encrypt together with Certbot.

Prerequisite: Before continuing, make sure your domain already points to your VPS and your website is accessible over HTTP.

Install Certbot

First, update the package list:

sudo apt update

Now install Certbot and its Nginx plugin:

sudo apt install certbot python3-certbot-nginx -y

The Nginx plugin automatically detects your website configuration and updates it to use HTTPS.

Verify Your Nginx Configuration

Before requesting an SSL certificate, test your Nginx configuration.

sudo nginx -t

If everything is correct, you’ll see:

nginx: configuration file syntax is ok
nginx: configuration file test is successful

If errors appear, resolve them before continuing.

Request an SSL Certificate

Run the following command:

sudo certbot --nginx

Certbot will guide you through a few prompts.

You may be asked to:

  • Enter an email address for renewal notifications.
  • Accept the Let’s Encrypt Terms of Service.
  • Choose whether to share your email address.
  • Select the domain names that should receive the certificate.

Choose your domain from the list and continue.

Enable Automatic HTTP to HTTPS Redirection

During the installation, Certbot usually asks:

Redirect HTTP traffic to HTTPS?

Choose the option that redirects all HTTP requests to HTTPS.

This ensures that visitors who enter: http://yourdomain.com

are automatically redirected to: https://yourdomain.com

without requiring any manual action.

Verify HTTPS

After the installation completes successfully, open your browser and visit: https://yourdomain.com

Verify that:

  • The website loads normally.
  • A padlock icon appears in the browser’s address bar.
  • There are no browser security warnings.
  • Pages load correctly over HTTPS.

Your Django application is now protected with an SSL certificate.

Check Certificate Information

You can inspect the installed certificate using:

sudo certbot certificates

The output displays:

  • Installed domains
  • Expiration date
  • Certificate path
  • Private key location

This is useful when managing multiple websites on the same VPS.

Test Automatic Renewal

Let’s Encrypt certificates are valid for 90 days, but Certbot can renew them automatically.

To test the renewal process without making any changes, run:

sudo certbot renew --dry-run

If the simulation completes successfully, automatic renewal is configured correctly.

Verify the Renewal Timer

Ubuntu usually installs a system timer that checks for certificate renewals automatically.

Verify it using:

systemctl list-timers

You should see a Certbot timer in the list.

This means your SSL certificate will renew automatically before it expires, provided the domain remains reachable.

Confirm Everything Is Working

Visit your website and verify the following:

  • The site opens using HTTPS.
  • HTTP automatically redirects to HTTPS.
  • Static CSS and JavaScript files load correctly.
  • Images display without mixed content warnings.
  • The Django admin panel works normally.
  • Browser developer tools show no certificate related errors.

If any assets still load over HTTP, update their URLs to use HTTPS or relative paths to eliminate mixed content warnings.

Why HTTPS Is Essential

Running your Django application over HTTPS is no longer optional—it’s an expected standard for modern websites. Beyond encrypting traffic, HTTPS helps protect user data, builds visitor confidence, and ensures compatibility with many modern web features and browser security requirements.

With Gunicorn, Nginx, UFW, and SSL now configured, your Django application is fully deployed and ready for production use. In the next section, you’ll perform a final deployment checklist to verify that every component is working correctly before launching your website to the public.


Step 13: Verify Everything Is Working Correctly

Congratulations! Your Django application is now deployed on your Ubuntu VPS with Gunicorn, Nginx, and HTTPS configured. Before considering the deployment complete, take a few minutes to verify that every component is working as expected.

Performing these checks can help you catch small issues before they affect your users.

Check That Your Website Loads Successfully

Open your browser and visit your domain:

https://yourdomain.com

Verify that:

  • The homepage loads without errors.
  • Navigation works correctly.
  • Internal pages open as expected.
  • Forms and interactive features function properly.

If your application includes user authentication, sign in and test the login process.

Confirm HTTPS Is Active

Look for the padlock icon in your browser’s address bar.

You should also verify that:

  • The website opens directly over HTTPS.
  • HTTP automatically redirects to HTTPS.
  • There are no SSL certificate warnings.
  • Browser developer tools show no mixed content errors.

A secure HTTPS connection confirms that your SSL certificate has been installed correctly.

Verify Static Files

Navigate through multiple pages and ensure that all static assets load correctly.

Check for:

  • CSS styles
  • JavaScript files
  • Logos
  • Images
  • Fonts
  • Icons

If the website appears unstyled, rerun:

python manage.py collectstatic

Then reload Nginx:

sudo systemctl reload nginx

Verify Uploaded Media Files

If your Django project allows users to upload files, test that functionality as well.

For example:

  • Upload a profile picture.
  • Upload a document.
  • Open previously uploaded files.

If media files don’t load, review your MEDIA_ROOT, MEDIA_URL, and the corresponding Nginx location /media/ configuration.

Check Gunicorn Status

Confirm that Gunicorn is running normally.

sudo systemctl status gunicorn

A healthy service should display:

Active: active (running)

If the service isn’t running, review the logs:

sudo journalctl -u gunicorn -f

Check Nginx Status

Verify that Nginx is also active.

sudo systemctl status nginx

Expected output:

Active: active (running)

If necessary, restart it:

sudo systemctl restart nginx

Verify Firewall Rules

Check your firewall configuration.

sudo ufw status

You should see rules allowing:

  • OpenSSH
  • Nginx Full

No additional ports should be open unless they’re required by another service running on your VPS.

Check Database Connectivity

Perform a few actions inside your application that interact with the database.

Examples include:

  • Logging in.
  • Creating a new record.
  • Updating existing data.
  • Deleting a test record.

If these operations work without errors, your database configuration is functioning correctly.

Test the Django Admin Panel

Visit:

https://yourdomain.com/admin

Log in using your administrator account and verify that:

  • The dashboard opens.
  • Models load correctly.
  • Records can be added, edited, and deleted.
  • Static assets load properly.

Review Server Logs

Even if everything appears to work correctly, it’s worth checking the logs for hidden warnings or errors.

View Gunicorn logs:

sudo journalctl -u gunicorn --since "30 minutes ago"

View Nginx error logs:

sudo tail -f /var/log/nginx/error.log

Reviewing these logs after deployment can help identify issues before they become noticeable to users.

Deployment Checklist

Before launching your Django application publicly, confirm that the following items are complete:

  • Ubuntu is fully updated.
  • Python and project dependencies are installed.
  • Virtual environment is configured.
  • Django migrations have been applied.
  • Static files have been collected.
  • DEBUG is set to False.
  • ALLOWED_HOSTS includes your domain.
  • Gunicorn is running as a systemd service.
  • Nginx is configured as a reverse proxy.
  • UFW firewall is enabled.
  • Your domain points to the VPS.
  • HTTPS is enabled with a valid SSL certificate.
  • Automatic SSL renewal is configured.
  • The website loads successfully without errors.

If every item on this checklist is complete, your Django application is running in a stable production environment and is ready to serve real users.


Common Django Deployment Errors and Fixes

Even when you carefully follow each deployment step, it’s normal to encounter a few issues the first time you deploy a Django application. Most problems are caused by small configuration mistakes, such as an incorrect file path, missing dependency, or server setting.

The good news is that these errors are usually easy to diagnose once you know where to look. Below are some of the most common Django deployment issues along with their likely causes and practical solutions.

502 Bad Gateway

A 502 Bad Gateway error usually means that Nginx cannot communicate with Gunicorn.

Possible Causes

  • Gunicorn service isn’t running.
  • Incorrect Unix socket path.
  • Wrong project directory in the Gunicorn service file.
  • Invalid WSGI module name.
  • Gunicorn crashed during startup.

How to Fix It

First, check the Gunicorn service status:

sudo systemctl status gunicorn

If the service isn’t running, restart it:

sudo systemctl restart gunicorn

Next, verify that the socket file exists:

ls -l /run/gunicorn.sock

If the socket isn’t present, review the Gunicorn logs:

sudo journalctl -u gunicorn -f

Most 502 errors can be resolved by correcting the Gunicorn configuration or fixing startup errors reported in the logs.

Static Files Are Not Loading

If your website loads but appears unstyled, Django’s static files aren’t being served correctly.

Possible Causes

  • collectstatic wasn’t executed.
  • Incorrect STATIC_ROOT.
  • Incorrect Nginx alias path.
  • File permission issues.

How to Fix It

Collect all static files again:

python manage.py collectstatic

Then reload Nginx:

sudo systemctl reload nginx

Also verify that:

  • STATIC_ROOT matches the Nginx configuration.
  • The static directory exists.
  • Nginx has permission to read the files.

Gunicorn Service Failed

Sometimes Gunicorn refuses to start after creating the systemd service.

Possible Causes

  • Incorrect virtual environment path.
  • Missing Python packages.
  • Wrong project directory.
  • Incorrect WSGI module.
  • Syntax errors in Django settings.

How to Fix It

Review the service logs:

sudo journalctl -u gunicorn -f

Double-check:

  • WorkingDirectory
  • ExecStart
  • Virtual environment location
  • Django project name

After making changes, reload systemd:

sudo systemctl daemon-reload

Restart the service:

sudo systemctl restart gunicorn

DisallowedHost Error

If Django displays a DisallowedHost exception, it means the incoming request isn’t included in the ALLOWED_HOSTS setting.

How to Fix It

Open your settings file:

nano your_project/settings.py

Update the configuration:

ALLOWED_HOSTS = [
   "yourdomain.com",
   "www.yourdomain.com",
   "203.0.113.10",
]

Restart Gunicorn after saving the file:

sudo systemctl restart gunicorn

ModuleNotFoundError

This error appears when Django cannot locate one of your Python packages.

Possible Causes

  • Missing dependency.
  • Virtual environment not activated.
  • Incorrect Python interpreter.

How to Fix It

Activate the virtual environment:

source venv/bin/activate

Install the missing package:

pip install package-name

If you’re deploying an existing project, reinstall all dependencies:

pip install -r requirements.txt

Permission Denied Errors

Permission-related errors usually occur when Gunicorn or Nginx cannot access project files.

How to Fix It

Verify file ownership:

ls -l

Update ownership if necessary:

sudo chown -R $USER:www-data /home/username/django-project

Then grant appropriate read and execute permissions:

sudo chmod -R 755 /home/username/django-project

Avoid using overly permissive settings such as 777, as they can introduce unnecessary security risks.

Database Migration Errors

Sometimes the application starts, but database tables are missing.

How to Fix It

Apply all pending migrations:

python manage.py migrate

If you’re unsure which migrations have been applied:

python manage.py showmigrations

This command displays the migration status for every installed Django app.

SSL Certificate Problems

If HTTPS doesn’t work correctly, first verify that your domain points to the correct VPS.

Check your certificate:

sudo certbot certificates

Then test automatic renewal:

sudo certbot renew --dry-run

If renewal succeeds, your SSL configuration is working properly.

Nginx Configuration Errors

If Nginx fails to restart after editing its configuration, test the syntax before making further changes.

sudo nginx -t

If errors are reported, correct the line mentioned in the output before restarting Nginx.

Once the configuration passes validation, reload the service:

sudo systemctl reload nginx

How to Troubleshoot Deployment Problems Efficiently

When something doesn’t work, avoid changing multiple settings at once. Instead, check each layer of the deployment individually:

  1. Confirm the Django project works locally using manage.py runserver.
  2. Verify that Gunicorn starts successfully.
  3. Ensure the Gunicorn service is active.
  4. Check that Nginx can communicate with the Gunicorn socket.
  5. Verify DNS records point to the correct VPS.
  6. Confirm the SSL certificate is installed correctly.
  7. Review Gunicorn and Nginx logs for detailed error messages.

Following this sequence makes it much easier to identify the source of the problem and resolve it without unnecessary trial and error.

With these troubleshooting tips, you’ll be able to diagnose and fix the vast majority of deployment issues encountered when hosting a Django application on an Ubuntu VPS. In the next section, we’ll cover Django deployment best practices to help you improve your server’s security, maintainability, and long-term performance.


Django Deployment Best Practices

Deploying your Django application successfully is only the beginning. To keep your website secure, stable, and easy to maintain over time, it’s important to follow a few production best practices. These recommendations can help reduce downtime, improve performance, and make future updates much smoother.

Keep Ubuntu and Installed Packages Updated

Regular software updates include security patches, bug fixes, and performance improvements. Make it a habit to update your server periodically.

sudo apt update
sudo apt upgrade -y

Likewise, keep your Python dependencies up to date after testing them in a development environment.

pip list --outdated

Avoid upgrading packages directly on a production server without verifying compatibility first.

Always Use a Virtual Environment

Installing Python packages globally can lead to dependency conflicts, especially if you’re hosting multiple Python applications on the same VPS.

Using a virtual environment keeps each project isolated, making it easier to manage dependencies and reproduce your deployment on another server.

Never Enable DEBUG in Production

The Django debug page contains detailed information about your application, including file paths and configuration details. Exposing this information on a public server creates unnecessary security risks.

Always ensure your production configuration contains:

DEBUG = False

Before launching your website, confirm that the setting hasn’t accidentally been changed during development.

Store Sensitive Data in Environment Variables

Avoid hardcoding sensitive information directly into your source code.

Examples include:

  • Django SECRET_KEY
  • Database passwords
  • API keys
  • Email credentials
  • Third-party service tokens

Keeping sensitive values in environment variables makes your application more secure and simplifies deployment across different environments.

Use HTTPS for Every Website

Even if your Django application doesn’t process payments or collect sensitive personal information, HTTPS should always be enabled.

A valid SSL certificate:

  • Encrypts communication.
  • Protects user sessions.
  • Builds visitor trust.
  • Prevents browsers from displaying “Not Secure” warnings.

If you’re using Let’s Encrypt, periodically verify that automatic certificate renewal continues to work correctly.

Keep Regular Backups

Unexpected problems such as accidental file deletion, server failures, or software issues can occur at any time.

Create regular backups of:

  • Your Django project files.
  • Database.
  • Uploaded media files.
  • Environment configuration.
  • Nginx configuration.
  • Gunicorn service file.

Many VPS providers also offer automated snapshots, which provide an additional layer of protection.

Monitor Server Logs

Logs provide valuable information about your application’s health and can help identify problems before they affect users.

Useful log locations include:

Gunicorn:

sudo journalctl -u gunicorn -f

Nginx errors:

sudo tail -f /var/log/nginx/error.log

Reviewing logs regularly makes it easier to detect configuration issues, failed requests, and unexpected application errors.

Protect SSH Access

Since SSH provides administrative access to your VPS, securing it should be a priority.

Some recommended practices include:

  • Use SSH key authentication instead of passwords.
  • Disable root login if possible.
  • Choose strong passwords for all user accounts.
  • Keep SSH open only on trusted networks whenever practical.
  • Remove unused user accounts from the server.

These simple measures significantly reduce the risk of unauthorized access.

Keep Your Dependencies Organized

As your project grows, managing dependencies becomes increasingly important.

Whenever you install or update a package, regenerate your dependency list:

pip freeze > requirements.txt

This ensures future deployments install the exact package versions your application expects.

Test Before Deploying Updates

Avoid uploading untested code directly to your production server.

A safer workflow is:

  1. Test changes locally.
  2. Verify functionality in a staging environment (if available).
  3. Commit the changes to your repository.
  4. Deploy to the VPS.
  5. Restart Gunicorn if required.

This approach minimizes downtime and reduces the chance of introducing unexpected issues.

Monitor Server Resources

As traffic increases, monitor your VPS to ensure it has sufficient resources.

Useful commands include:

View CPU and memory usage:

top

Check disk usage:

df -h

View memory usage:

free -h

Monitoring these metrics helps you determine when it’s time to upgrade your VPS or optimize your application.

Restart Services After Major Changes

Whenever you modify Django settings, update dependencies, or change server configurations, restart the affected services so the changes take effect.

For example:

Restart Gunicorn:

sudo systemctl restart gunicorn

Reload Nginx:

sudo systemctl reload nginx

Verifying that both services restart successfully should always be part of your deployment routine.

Final Thoughts

A reliable Django deployment is built on more than just installing Gunicorn and Nginx. Keeping your server updated, securing sensitive information, monitoring system health, and following established deployment practices will help your application remain stable as it grows.

By following the steps and best practices covered in this guide, you’ll have a production-ready Django deployment that’s easier to maintain, more secure, and better prepared to handle real world traffic.


Conclusion

Deploying a Django application on a VPS may seem challenging at first, but once you understand the deployment workflow, the process becomes much more manageable. By preparing your Ubuntu server, creating a virtual environment, installing your project dependencies, configuring Gunicorn and Nginx, enabling the firewall, connecting your domain, and securing the application with HTTPS, you’ve built a production-ready environment that follows widely accepted deployment practices.

Remember that deployment isn’t a one-time task. Regular updates, monitoring, backups, and security checks are essential for keeping your application reliable over the long term. As your project grows, you can further enhance your setup with tools such as caching, database optimization, background task queues, and automated CI/CD pipelines.

With your Django application now live, you can confidently focus on developing new features and improving the user experience while knowing your deployment is built on a solid foundation.


FAQs

Can I deploy Django without Gunicorn?

Yes, but it’s not recommended for production. Django’s built-in development server is intended only for local development and testing. For a production environment, use a WSGI server such as Gunicorn behind Nginx to ensure better performance, stability, and security.

Why is Nginx used with Django?

Nginx acts as a reverse proxy. It handles incoming client requests, serves static and media files efficiently, manages HTTPS connections, and forwards application requests to Gunicorn, allowing Django to focus solely on processing application logic.

Can I deploy Django on Ubuntu 24.04?

Yes. Ubuntu 24.04 LTS is an excellent choice for deploying Django applications and is fully compatible with Python, Gunicorn, Nginx, and other commonly used deployment tools.

How much RAM does a Django VPS need?

For small personal projects or development environments, 1 GB RAM is usually sufficient. For production websites, 2 GB RAM or more is recommended, especially if your application serves multiple users or uses PostgreSQL, Redis, or background workers.

Should I enable HTTPS before launching my Django application?

Yes. Enabling HTTPS protects data exchanged between users and your server, improves trust, and is considered a standard security practice for modern websites.

How do I restart Gunicorn after updating my Django project?

After deploying new code or changing your application settings, restart the Gunicorn service using:
sudo systemctl restart gunicorn
This ensures Gunicorn loads the latest version of your application.

Why are my Django static files not loading?

This usually happens when collectstatic hasn’t been run, STATIC_ROOT is configured incorrectly, or the Nginx alias path doesn’t match your Django settings. Verify these configurations and reload Nginx after making any changes.

Can I deploy multiple Django projects on one VPS?

Yes. You can host multiple Django applications on a single VPS by creating separate virtual environments, Gunicorn services, and Nginx server blocks for each project. This keeps each application isolated while allowing them to share the same server resources.

Sanjeet Chauhan
Sanjeet Chauhan

Passionate about helping websites thrive, Sanjeet Chauhan is a blogger and SEO expert who turns ideas into actionable strategies, sharing tips and insights that boost traffic, improve rankings, & create a strong online presence.

Articles: 36

Leave a Reply

Your email address will not be published. Required fields are marked *