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.
mubashar
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.
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.