Most Django deployment guides send you to a platform that runs your app on their infrastructure. This one is different. Here you will deploy Django to a plain Linux server that you own and control, on any cloud (Hetzner, DigitalOcean, AWS, or a box under your desk).

We will do it two ways. First the full manual setup, so you understand every moving part: Gunicorn, Nginx, systemd, Postgres, and SSL. Then the managed way, where Appliku does all of that for you and you just push code. By the end you will know exactly what production Django needs, and you can decide how much of it you want to run by hand.

What "deploying Django" actually involves

A Django app in development runs on manage.py runserver. That server is not built for production. A real deployment needs several pieces working together:

  • An application server (Gunicorn or uWSGI) to run your Python code across multiple workers
  • A web server / reverse proxy (Nginx) to terminate HTTPS, serve static files, and forward requests to Gunicorn
  • A process manager (systemd) to keep Gunicorn running and restart it on boot or crash
  • A database (Postgres) with its own user, password, and backups
  • TLS certificates (Let's Encrypt via Certbot) so the site is served over HTTPS
  • A deploy process to pull new code, install dependencies, run migrations, collect static files, and restart the app

None of this is exotic, but it is a lot of small steps that all have to be correct. Miss the systemd restart and your app dies on the next reboot. Miss the static-files step and your CSS disappears in production. This is the work a platform hides from you, and the work you are choosing to own when you deploy to your own VPS.

Prerequisites

  • A Django project in a Git repository
  • A fresh Ubuntu 24.04 LTS server (any provider; 2 vCPU / 4GB RAM is plenty to start)
  • A domain name pointed at the server's IP (an A record)
  • SSH access to the server as a sudo user

Option A: Deploy Django manually

1. Prepare the server

SSH in and install the system packages Django and Postgres need:

sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx postgresql postgresql-contrib git curl
# Install uv, the fast Python package and project manager
curl -LsSf https://astral.sh/uv/install.sh | sh

2. Create the database

sudo -u postgres psql
CREATE DATABASE myapp;
CREATE USER myapp_user WITH PASSWORD 'a-strong-password';
ALTER ROLE myapp_user SET client_encoding TO 'utf8';
ALTER ROLE myapp_user SET default_transaction_isolation TO 'read committed';
GRANT ALL PRIVILEGES ON DATABASE myapp TO myapp_user;
\q

3. Pull the code and install dependencies

cd /srv
sudo git clone https://github.com/you/myapp.git
sudo chown -R $USER:$USER /srv/myapp
cd /srv/myapp
uv venv --python 3.14          # uv fetches Python 3.14 if it is not already installed
uv pip install -r requirements.txt gunicorn

Set your production environment variables (database URL, SECRET_KEY, DJANGO_ALLOWED_HOSTS, DEBUG=False) in a .env file the app reads, or export them in the systemd unit below. Then run the one-time release steps:

uv run python manage.py migrate
uv run python manage.py collectstatic --noinput

4. Run Django under Gunicorn with systemd

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

[Unit]
Description=myapp Gunicorn daemon
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/myapp
EnvironmentFile=/srv/myapp/.env
ExecStart=/srv/myapp/.venv/bin/gunicorn \
    --workers 3 \
    --bind unix:/run/myapp.sock \
    myapp.wsgi:application

[Install]
WantedBy=multi-user.target

Enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp

5. Put Nginx in front

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

server {
    listen 80;
    server_name example.com www.example.com;

    location /static/ {
        alias /srv/myapp/staticfiles/;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/myapp.sock;
    }
}

Enable the site and reload:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

6. Add HTTPS with Let's Encrypt

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

Certbot edits your Nginx config to serve HTTPS and sets up automatic renewal.

7. Deploying again, and again

Every future deploy means repeating a version of this by hand:

cd /srv/myapp && git pull
uv pip install -r requirements.txt
uv run python manage.py migrate
uv run python manage.py collectstatic --noinput
sudo systemctl restart myapp

You will also want to add, on your own: database backups (a cron job running pg_dump), log rotation, a firewall (ufw), unattended security upgrades, and monitoring so you know when the app is down. This is the ongoing part. It works, and plenty of teams run exactly this. The question is whether you want deploys and server upkeep to be a recurring task.

Option B: Deploy Django the managed way

The manual setup above is the same on every deploy, for every app. That is exactly the kind of repetitive, error-prone work worth automating. Appliku does the whole of Option A for you, on a server you own:

  1. Connect a cloud account (or point Appliku at a fresh Ubuntu server).
  2. Create your application from your Git repo.
  3. Push code. Appliku provisions the server, installs and configures Gunicorn, Nginx, and Postgres, issues SSL, runs your migrations and collectstatic, and restarts the app. From then on, every git push deploys.

You still own the server and pay the provider directly, so you keep the cost control and the root SSH access. The difference is that patching, SSL renewal, backups, and zero-downtime restarts are handled for you. We manage the servers. You just push code.

For the exact managed walkthrough, see the Deploy Django docs. For provider-specific guides, see Deploy Django to Hetzner, to AWS EC2, to a DigitalOcean Droplet, or to Linode.

Manual vs managed: which should you choose?

Manual (DIY) Managed (Appliku)
Server ownership Yes Yes
Initial setup Hours, many steps Minutes
Every deploy Manual commands or your own scripts git push
SSL renewal You (or Certbot cron) Automatic
Backups, monitoring, patching You configure and maintain Built in
Cost Server only Server + Appliku (Free plan to start)
When it breaks at 2am You debug it Direct support, often from the founder

If you enjoy running your own infrastructure and have the time, Option A is completely valid. If you would rather your server just stay healthy while you ship features, Option B gives you the same server ownership without the upkeep.

FAQ

Do I need Nginx and Gunicorn, or just one?

Both, and they do different jobs. Gunicorn runs your Python code; Nginx handles HTTPS, serves static files, and proxies requests to Gunicorn. Running Django on Gunicorn alone, exposed to the internet, is not recommended.

Can I deploy Django without Docker?

Yes. Option A above uses no Docker at all, just uv, Gunicorn, and systemd. Appliku can deploy either from a buildpack or your own Dockerfile, whichever you prefer.

Which VPS provider is cheapest for Django?

Hetzner is usually the lowest cost, with DigitalOcean and Vultr close behind. Because you bring your own server, you pay the provider directly and can move between them without changing how you deploy. See how the managed platforms compare on our comparison pages.

How do I move an existing app off Heroku?

The process is straightforward and your Heroku buildpack and Procfile are compatible. See Leave Heroku for a server you own, where we can also migrate your first app for you, live, on any paid plan.

Deploy your first app

You now know everything production Django needs, and two ways to provide it. If you want to skip the manual upkeep, start free and deploy a real app to your own server in a few minutes.

Start deploying free →  •  Compare Appliku to other platforms →