This tutorial walks you through deploying a Django project on Ubuntu using:
Python Virtual Environment
PostgreSQL as the database
Gunicorn as the WSGI application server
Nginx as a reverse proxy
Static and Media file configuration
Whether you're starting fresh or deploying an existing Django project from a Git repository, this guide covers it all.
Prerequisites
Ubuntu 22.04+
A non-root user with sudo privileges
Git installed
Domain name configured (optional but recommended)
Clone Your Django Project Repository
If you're working with an existing Django project hosted on GitHub or another Git provider:
cd ~
git clone https://github.com/yourusername/yourproject.git
cd yourproject
Set Up a Python Virtual Environment
Why Use a Virtual Environment?
Keeps your project dependencies isolated
Avoids conflicts with system-level packages
Essential for reproducibility and deployment
Commands:
sudo apt update
sudo apt install python3-pip python3-venv
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt # if using a requirements file
pip install django gunicorn psycopg2-binary
Configure Your Django Settings
ALLOWED_HOSTS
In settings.py, update this:
ALLOWED_HOSTS = ['yourdomain.com', 'your.server.ip.address']
Configure PostgreSQL
Install PostgreSQL:
sudo apt install postgresql postgresql-contrib libpq-dev
sudo -u postgres psql
CREATE DATABASE yourdbname;
CREATE USER yourdbuser WITH PASSWORD 'yourdbpassword';
ALTER ROLE yourdbuser SET client_encoding TO 'utf8';
ALTER ROLE yourdbuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE yourdbuser SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE yourdbname TO yourdbuser;
\q
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'yourdbname',
'USER': 'yourdbuser',
'PASSWORD': 'yourdbpassword',
'HOST': 'localhost',
'PORT': '5432',
}
}
python manage.py migrate
Set Up Static and Media Files
In settings.py:
import os
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
python manage.py collectstatic
sudo chown -R yourusername:www-data static media
sudo chmod -R 775 static media
Run and Test Gunicorn
pip install gunicorn
gunicorn --bind 127.0.0.1:8000 yourproject.wsgi
http://your.server.ip.address:8000
Create a Gunicorn Systemd Service
sudo nano /etc/systemd/system/yourproject.service
[Unit]
Description=gunicorn daemon for Django project
After=network.target
[Service]
User=yourusername
Group=www-data
WorkingDirectory=/home/yourusername/yourproject
ExecStart=/home/yourusername/yourproject/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/yourusername/yourproject/yourproject.sock yourproject.wsgi:application
[Install]
WantedBy=multi-user.target
sudo chown -R yourusername:www-data /home/yourusername/yourproject
sudo chmod -R 775 /home/yourusername/yourproject
sudo systemctl daemon-reexec
sudo systemctl start yourproject
sudo systemctl enable yourproject
Set Up Nginx
sudo apt install nginx
sudo nano /etc/nginx/sites-available/yourproject
server {
listen 80;
server_name yourdomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/yourusername/yourproject;
}
location /media/ {
root /home/yourusername/yourproject;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/yourusername/yourproject/yourproject.sock;
}
}
sudo ln -s /etc/nginx/sites-available/yourproject /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
sudo ufw allow 'Nginx Full'
Secure with HTTPS (Optional)
Install Certbot:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com
Final Checklist
✅ Django served with Gunicorn
✅ PostgreSQL configured
✅ Static and media files served
✅ Nginx reverse proxy setup
✅ HTTPS enabled (optional)
✅ Permissions correctly set
✅
ALLOWED_HOSTS
configured✅ Gunicorn tested via browser
✅ Ready for production
FAQs
Do I need a virtual environment for Django?
Yes. It ensures isolated, reproducible environments for dependencies.
How does a virtual environment work?
It creates a self-contained directory with a specific Python interpreter and installed packages.
Are virtual environments portable?
Not directly. Use requirements.txt
to replicate environments elsewhere.
Where are Python virtual environments stored?
Where you create them — typically inside your project (venv/
).
Why Gunicorn?
It’s a production-grade WSGI HTTP server that integrates cleanly with Nginx.
Why Nginx?
To handle static files and reverse proxy HTTP requests to Gunicorn efficiently.
Which Django version?
Use the latest LTS or stable release (as of 2025, Django 5.0+ is recommended).