Skip to content

How to Deploy Django to a Hetzner VPS with Nginx and Gunicorn

Hetzner CX22 gives you 2 vCPUs, 4 GB RAM, and 40 GB SSD for around £4/month. Here is exactly how I deploy Django — from a fresh Ubuntu server to a live SSL-secured site.

MI

mubashar

· 2 min read
Share

Hetzner's CX22 VPS gives you 2 vCPUs, 4 GB RAM, and 40 GB SSD for around £4/month — genuinely great value for hosting Django applications. Here is exactly how I deploy, from a fresh Ubuntu server to a live, SSL-secured site.

Prerequisites

  • A Hetzner CX22 running Ubuntu 22.04 LTS
  • A domain name with DNS pointed at the server's IP
  • Your Django project in a Git repository
  • SSH access to the server

1. Initial server setup

Log in as root and create a deployment user:

adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

Log out and back in as deploy for the rest of this guide.

2. Install system dependencies

sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-pip python3-venv nginx certbot python3-certbot-nginx git

3. Clone your project and set up the virtualenv

cd /var/www
git clone https://github.com/you/your-project.git mysite
cd mysite
python3 -m venv env
source env/bin/activate
pip install -r requirements/production.txt

4. Configure environment variables

Create /var/www/mysite/.env with your production secrets:

SECRET_KEY=your-very-long-random-secret-key-here
DJANGO_SETTINGS_MODULE=mysite.settings.production

Run initial setup:

python manage.py migrate
python manage.py collectstatic --no-input
python manage.py createsuperuser

5. Set up Gunicorn as a systemd service

Create /etc/systemd/system/gunicorn.service:

[Unit]
Description=Gunicorn daemon for Django
After=network.target

[Service]
User=deploy
Group=www-data
WorkingDirectory=/var/www/mysite
EnvironmentFile=/var/www/mysite/.env
ExecStart=/var/www/mysite/env/bin/gunicorn     --workers 3     --bind unix:/run/gunicorn.sock     mysite.wsgi:application

[Install]
WantedBy=multi-user.target
sudo systemctl start gunicorn
sudo systemctl enable gunicorn

6. Configure Nginx

Create /etc/nginx/sites-available/mysite:

server {
    server_name yourdomain.com www.yourdomain.com;

    location = /favicon.ico { access_log off; log_not_found off; }

    location /static/ {
        root /var/www/mysite;
    }

    location /media/ {
        root /var/www/mysite;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl restart nginx

7. SSL with Let's Encrypt

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot handles Nginx configuration automatically and sets up auto-renewal. Your site is now live, secure, and will renew its certificate without any manual intervention.

Deployment workflow going forward

cd /var/www/mysite
git pull
source env/bin/activate
pip install -r requirements/production.txt
python manage.py migrate
python manage.py collectstatic --no-input
sudo systemctl restart gunicorn

I keep a simple deploy.sh script in the repo root that runs all of the above in one command.

MI

Written by

Mubashar Iqbal

Web developer, SEO expert, and independent maker. I build products, write about what I've learned, and create free tools for developers and marketers.