This guide walks you through deploying a Django application on a LumaDock VPS running Ubuntu 22.04 LTS. You will configure Python, a virtual environment, Gunicorn, Nginx, and optional PostgreSQL and HTTPS.
Firewall note: if you enable the cloud firewall later, allow inbound ports 22/tcp, 80/tcp, and 443/tcp.
Requirements
A working Django setup requires:
A LumaDock VPS running Ubuntu 22.04 LTS
SSH access as root or a sudo-enabled user
A domain pointed to your VPS (recommended for HTTPS)
1) Connect and update
Log in:
ssh root@YOUR_SERVER_IP
Update packages:
apt update && apt -y upgrade
To avoid using root directly, create a sudo user:
adduser admin usermod -aG
sudo admin ssh admin@YOUR_SERVER_IP
2) Install Python and build tools
Install required packages:
apt install -y python3 python3-venv python3-pip python3-dev build-essential nginx git
3) Create your Django project and virtual environment
Create a directory and activate a virtual environment:
mkdir -p /opt/djangoapp &&
cd /opt/djangoapp
python3 -m venv venv source
venv/bin/activate
Install Django and Gunicorn:
pip install --upgrade pip pip install django gunicorn
Create a Django project:
django-admin startproject myproject .
Allow your domain or IP in Django settings:
nano myproject/settings.py
# ALLOWED_HOSTS = ["YOUR_DOMAIN_OR_IP"]
4) Test with Gunicorn
Run migrations:
python manage.py migrate
Collect static files:
python manage.py collectstatic --noinput
Start Gunicorn:
gunicorn --bind 127.0.0.1:8000 myproject.wsgi
In another terminal:
curl -I http://127.0.0.1:8000
You should see 200 OK.
5) Set up Nginx as a reverse proxy
Create a new Nginx configuration:
nano /etc/nginx/sites-available/djangoapp
Paste the following block:
server {
listen 80;
server_name YOUR_DOMAIN_OR_IP;
client_max_body_size 20M;
location /static/ {
alias /opt/djangoapp/static/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Enable and test the configuration:
ln -s /etc/nginx/sites-available/djangoapp /etc/nginx/sites-enabled/ nginx -t && systemctl restart nginx
Visit:
http://YOUR_DOMAIN_OR_IP
6) Create a systemd service for Gunicorn
Create a service file:
nano /etc/systemd/system/gunicorn-djangoapp.service
Insert:
[Unit]
Description=Gunicorn for Django (djangoapp)
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/djangoapp
Environment="PATH=/opt/djangoapp/venv/bin"
ExecStart=/opt/djangoapp/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 myproject.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.target
Enable the service:
systemctl daemon-reload systemctl enable --now gunicorn-djangoapp
systemctl status gunicorn-djangoapp
7) Optional — enable HTTPS with Let’s Encrypt
Install Certbot:
apt install -y certbot python3-certbot-nginx
Request a certificate:
certbot --nginx -d YOUR_DOMAIN -m you@example.com --agree-tos --redirect
Check automatic renewal:
systemctl list-timers | grep certbot
8) Optional — configure PostgreSQL
Install PostgreSQL:
apt install -y postgresql postgresql-contrib libpq-dev
Create a database and user:
sudo -u postgres psql
CREATE DATABASE mydb;
CREATE USER myuser WITH PASSWORD 'StrongPassword123!';
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;
\q
Install the driver:
source /opt/djangoapp/venv/bin/activate pip install psycopg2-binary
Update settings:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "mydb",
"USER": "myuser",
"PASSWORD": "StrongPassword123!",
"HOST": "127.0.0.1",
"PORT": "5432",
}
}
Apply migrations:
python manage.py migrate
systemctl restart gunicorn-djangoapp
9) Configure and collect static files
Add to settings:
STATIC_URL = "static/"
STATIC_ROOT = "/opt/djangoapp/static"
Collect files and restart services:
python manage.py collectstatic --noinput
systemctl restart gunicorn-djangoapp
systemctl restart nginx
Troubleshooting
Common issues you may encounter:
400 Bad Request: your domain/IP is missing from
ALLOWED_HOSTS403/404 static files:
STATIC_ROOTmissing or static not collected502 Bad Gateway: Gunicorn is not running or Nginx proxy_pass uses wrong address
Port 80/443 errors: Nginx down or firewall blocking traffic
Appendix: useful commands
Logs and service checks:
journalctl -u gunicorn-djangoapp -e
journalctl -u nginx -e
systemctl restart gunicorn-djangoapp
systemctl restart nginx
Check open ports:
ss -tulpen | egrep ':80|:443|:8000' curl -I http://127.0.0.1:8000 curl -I http://YOUR_DOMAIN_OR_IP
Your Django application is now running behind Nginx and Gunicorn on your LumaDock VPS.
You can deploy your code, configure environment variables, and continue building out your project.
