Deploying a Django project to a live server can feel overwhelming at first — but once you break it into steps, it becomes straightforward. In this guide, you'll learn how to deploy your Django app using PostgreSQL and Nginx on a DigitalOcean Ubuntu server.

Step 1: Set Up Your DigitalOcean Droplet

1. Create a DigitalOcean Droplet

  • Go to DigitalOcean and log in.
  • Click “Create Droplet”.
  • Choose Ubuntu 22.04 LTS as the operating system.
  • Select a plan (e.g., Basic with 1GB RAM for small projects).
  • Add your SSH key (or choose a password if you're not using SSH).
  • Finalize and launch your droplet.

2. Access Your Droplet via SSH

ssh root@your_server_ip

3. Create a New User (Recommended for Security)

adduser dydevops
usermod -aG sudo dydevops

4. Enable the UFW Firewall

ufw allow OpenSSH
ufw enable 

5. Install Essential Packages:

sudo apt update && sudo apt upgrade -y
sudo apt install python3-pip python3-dev ufw nginx -y

Step 2: Set Up Your Project Directory

1.  Switch to the New User:

su - dydevops

2. Create Project Directory:

cd /home/dydevops/
mkdir myproject
cd myproject

3. Upload Your Project Files:
Use an FTP client like FileZilla to upload your local Django project files to the /home/dydevops/myproject/ directory on the server.

4. Now ssh in to the server as dydevops user

ssh dydevops@SERVER_IP_ADDRES
sudo ufw allow ssh
sudo ufw enable
sudo apt update
sudo pip3 install virtualenv

Step 3 : Security & Access

Creating SSH keys (Optional)

You can choose to create SSH keys to login if you want. If not, you will get the password sent to your email to login via SSH

To generate a key on your local machine

$ ssh-keygen

Hint enter all the way through and it will create a public and private key at

~/.ssh/id_rsa
~/.ssh/id_rsa.pub

Add SSH key for new user

Navigate to the new users home folder and create a file at ‘.ssh/authorized_keys’ and paste in the key

cd /home/dydevops
mkdir .ssh
cd .ssh

Open the authorized_keys file (or create it if it doesn’t exist):

nano authorized_keys

Paste your public key into the file (usually starts with ssh-rsa or ssh-ed25519).

Save and exit:

  • Press Ctrl + X to exit
  • Press Y to confirm saving
  • Press Enter to finalize the file name

Set Proper Permissions:

chmod 600 authorized_keys
chmod 700 ~/.ssh

 Now you can SSH into the server using your key, without typing the password every time.

Possible Deployment Issues & How to Prevent Them

Before pushing your Django project to production, it's important to handle a few key items that are often the root cause of errors. Follow these best practices to avoid common deployment pitfalls:

 Set ALLOWED_HOSTS in settings.py

Make sure you include your server's IP address or domain name:

ALLOWED_HOSTS = ['your_domain.com', 'your_server_ip']

❗ Not setting this correctly can lead to a DisallowedHost error when trying to access your site.

Release the media Folder

Ensure your media folder (for user-uploaded content) is tracked and accessible on the production server. Update your Nginx config to serve media files correctly.

In your settings.py:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Collect Static Files

Run this command to gather all static files into your STATIC_ROOT directory:

python manage.py collectstatic

This is necessary for serving CSS, JS, and image files through Nginx in production.

Create requirements.txt

To ensure your production server installs the exact same Python packages as your local machine:

pip freeze > requirements.txt

Then, upload this file to your server and run:

pip install -r requirements.txt
  • Replace psycopg2 package with psycopg2-binary
  • Install backports.zoneinfo only if the server python version is less than 3.9
  • backports.zoneinfo==0.2.1;python_version<"3.9"
  • Add gunicorn to requirements.txt

 

Django File Upload Using FTP (FileZilla Server Setup & Example)

In some cases, especially for legacy systems or restricted hosting environments, you may want to handle Django file uploads via FTP instead of directly through HTTP POST.

This section will walk you through:

  • Setting up FileZilla Server on Windows
  • Using Django with an FTP backend
  • Backing up and restoring your local Django database to the production server

Install FileZilla Server (Windows 64-bit)

To allow FTP uploads from your local development environment or external clients:

  1. Download FileZilla Server from the official site:
     Download FileZilla Server 64-bit
  2. Install and configure it:
    • Set your FTP port (default: 21)
    • Create a new user and set a password
    • Assign a home directory (this is where files will be uploaded)
  3. Ensure the Windows firewall allows FTP traffic (port 21)

FileZilla Server acts as the FTP backend which your Django app or manual workflows can interact with.


Use Minimal Django File Upload Example (Educational Demo)

To keep things clean and educational, use a minimal Django project designed specifically to show how file uploading works.

Example source: minimal-django-file-upload-example

Why use this?

  • It's stripped of extra features, so you can focus on the file upload logic.
  • Helps you clearly understand what Django needs: form, view, MEDIA_ROOT, and upload handler.

Basic components include:

  • forms.py: with FileField
  • views.py: using request.FILES to handle uploads
  • settings.py: with MEDIA_URL and MEDIA_ROOT configured
  • urls.py: to serve uploaded files in development

Backup & Restore Django Data Between Local & Production Servers

When moving data from your local development environment to the live server, you’ll want to back up your database and restore it properly.

On Your Local Machine

Export your database to JSON format:

python manage.py dumpdata > backup.json

While you are logged in to the server via SSH, create a project directory as myproject inside /home/dydevops/ folder

cd /home/dydeops/
mkdir myproject
cd myproject

Now check the remote directory, our project is pushed to the server. That’s all, we have set up Filezilla to upload the code from local machine to ftp server.

Install & Configure PostgreSQL

While you are logged into the server, run following commands to install, start, enable and see the status of postgresql database:

sudo apt-get install postgresql postgresql-contrib
sudo systemctl start postgresql.service
sudo systemctl enable postgresql.service
sudo systemctl status postgresql.service

Install PostgreSQL and Extensions

Run the following command to install PostgreSQL and its standard additional tools:

sudo apt-get install postgresql postgresql-contrib
  • postgresql installs the core database system
  • postgresql-contrib provides additional features and extensions

Start the PostgreSQL Service

After installation, start the PostgreSQL service:

sudo systemctl start postgresql.service

Enable PostgreSQL on Boot

Ensure PostgreSQL automatically starts when your server boots:

sudo systemctl enable postgresql.service

Check PostgreSQL Service Status

Verify that PostgreSQL is running correctly:

sudo systemctl status postgresql.service

PostgreSQL Database & User Setup for Django

Once PostgreSQL is installed and running, you'll need to create:

  • A database
  • A user with access to that database
  • And grant privileges so Django can connect properly

Access PostgreSQL Shell

Switch to the postgres system user to access the PostgreSQL command-line interface:

sudo -u postgres psql

You'll now be in the psql prompt:

postgres=#

Create a New Database

CREATE DATABASE myprojectdb;

Replace myprojectdb with your actual database name.

Create a New User

CREATE USER myprojectuser WITH PASSWORD 'your_secure_password';

Make sure to replace myprojectuser and 'your_secure_password' with your desired username and a strong password.

Set default encoding, tansaction isolation scheme (Recommended from Django)

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 Access to the User

GRANT ALL PRIVILEGES ON DATABASE myprojectdb TO myprojectuser;

Exit PostgreSQL Shell

\q

You're now back to the Ubuntu shell.

Set Up a Virtual Environment & Run the Server

Using a virtual environment keeps your Django project's dependencies isolated from the system Python and avoids package conflicts.

Follow these steps inside your project directory (e.g., /home/dydevops/myproject/):

1. Install virtualenv (if not already installed)

sudo apt install python3-virtualenv

2. Create a Virtual Environment

Navigate to your project directory:

cd /home/dydevops/myproject/

Then create a virtual environment named env:

virtualenv env

This will create a new folder named env/ containing an isolated Python environment.

Activate the Virtual Environment

source env/bin/activate

You should see your terminal prompt prefixed with (env) — indicating that the virtual environment is active.

Install Project Requirements

If you already created requirements.txt, install all necessary packages:

pip install -r requirements.txt

Run makemigrations and migrate commands

python manage.py migrate

If not, install Django and any other dependencies manually, then generate the file:

pip install django psycopg2-binary
pip freeze > requirements.txt

Allow port 8000

sudo ufw allow 8000

Check status of ufw

sudo ufw status

Run the Django Development Server (for Testing)

To verify that everything works:

python manage.py runserver 0.0.0.0:8000

You should now be able to visit your server’s IP in the browser via port 8000 to see the default Django page.

Note: For production use, you'll run Django with Gunicorn + Nginx, not the development server.

Remote server

python manage.py shell

from django.contrib.contenttypes.models import ContentType
ContentType.objects.all().delete()
quit()
python manage.py loaddata backup.json

Configuring Gunicorn

Install Gunicorn on our server

sudo apt install gunicorn

Tell gunicorn to bind to our Django application and start running

gunicorn --bind 0.0.0.0:8000 mwcshop.wsgi

Test the link and make sure the site is working

exit

Go to this location and paste below code:

sudo nano /etc/systemd/system/gunicorn.socket
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target

Location:

sudo nano /etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=dydevops
Group=www-data
WorkingDirectory=/home/dydevops/myproject
ExecStart=/home/dydevops/myproject/env/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          mwcshop.wsgi:application

[Install]
WantedBy=multi-user.target

Restart and enable Gunicorn socket


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

Configuring Nginx as a reverse proxy

sudo nano /etc/nginx/sites-available/dydevops
server {
    listen 80;
    server_name dydevops.com www.dydevops.com;

    location ~ ^/.well-known {
        root /home/dydevops/myproject;
        allow all;
    }
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/dydevops/myproject;
    }
    location /media/ {
        root /home/dydevops/myproject;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

 

sudo ln -s /etc/nginx/sites-available/dydevops /etc/nginx/sites-enabled/
sudo systemctl restart nginx

Open port 80 and close 8000

sudo ufw allow 80
sudo ufw allow 'Nginx Full'
sudo ufw allow 586
sudo ufw deny 8000

Go to sites-enabled directory and delete the default site

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

Fix Static Files on Server

cd /etc/nginx/
ls
sudo nano nginx.conf

 

sudo systemctl restart nginx
cd myproject
sudo nano mwcshop/settings.py
ALLOWED_HOSTS = ['SERVER_IP_ADDRESS', 'www.dydevops.com', 'dydevops.com']
sudo service nginx restart
sudo service gunicorn restart