How To Deploy a Django App With Gunicorn and Nginx on Ubuntu
Goal
In this tutorial, you will take an existing Django project and put it into production on Ubuntu: run it through Gunicorn as a WSGI application server, manage Gunicorn as a persistent systemd service bound to a Unix socket, and configure Nginx as a reverse proxy in front of it that also serves static files directly.
Prerequisites
- An existing Django project with a requirements.txt, deployed to a directory on the server
- An Ubuntu server (Python 3 ships by default) with a non-root user that has sudo privileges
- A domain name with its DNS A record pointed at the server (or you can substitute the server's IP address throughout)
- Basic comfort with the Linux command line and a text editor
Let an AI agent do this for you
Copy a ready-made prompt for an AI coding assistant with terminal access to your server (Claude Code, Cursor, or similar) — it can carry out the steps below for you. Review what it plans to run before it executes anything.
Django's built-in `runserver` command is for local development only — Django's own documentation says explicitly not to use it in production. It's single-threaded and doesn't do real request queuing, which is fine while you're iterating on code locally but won't hold up under concurrent traffic. In production you need a real WSGI HTTP server in front of your Django code, and a reverse proxy in front of that server to handle client connections, TLS, static files, and slow clients efficiently. This tutorial covers the standard pairing: Gunicorn as the WSGI server running your Django app as a persistent systemd service, and Nginx as the reverse proxy that talks to it over a Unix socket.
Step 1 — Install Python and Nginx packages
Ubuntu ships Python 3 by default, but the `venv` module and `pip` aren't always installed alongside it. Install them from the Ubuntu repositories:
sudo apt install -y python3-pip python3-venvThis tutorial also uses Nginx as the reverse proxy in front of Gunicorn (Step 6), so install it now too. Refresh the package index first so apt has current package metadata, then install it:
sudo apt update
sudo apt install -y nginxStep 2 — Create a virtual environment and install dependencies
Isolate this project's Python packages from the system Python by creating a virtual environment inside the project directory. The examples below use /home/django/myproject as the project path — replace it with wherever your project actually lives.
cd /home/django/myproject
python3 -m venv venv
source venv/bin/activateWith the environment active (your shell prompt gets a `(venv)` prefix), install your project's own dependencies plus Gunicorn into it:
pip install -r requirements.txt gunicornStep 3 — Test Gunicorn on its own, before adding Nginx
Confirm Gunicorn can serve your app correctly before introducing systemd and Nginx into the picture. Testing it in isolation first makes it much easier later to tell whether a problem is in your Django code or in the proxy/service configuration.
“myproject.wsgi below is a placeholder — replace myproject with the actual name of the Python package that contains your project's wsgi.py (the directory django-admin startproject created alongside manage.py), not the name of the outer checkout directory.”
Tricknowtech VPS Hosting
Dedicated KVM resources and full root access — deployed in under 60 seconds, no ticket required.
Ready to try it yourself?
Create a free account and follow along.