Basic tutorial on Docker + Django + Nginx + uWSGI + PostgreSQL – From Zero to Deployment.
Learn how to build a production-ready stack using Docker with Django, Nginx, uWSGI, and PostgreSQL 📝
If you're new to Docker, I recommend starting with this beginner-friendly guide:
👉 Docker Beginners Guide – Build Django + PostgreSQL using Docker 📝
- PART 1 – Overview
- PART 2 – Architecture & Steps
- PART 3 – Hands-on Project
- Nginx Log Analysis: PV & UV – Quick Article Link
- Nginx Auth Basic Tutorial – Quick Article Link
Already covered in my Docker Beginners Guide, so we won’t go over it again here 😛
Reference guides:
For more Django examples, visit my GitHub repositories
Nginx is a lightweight, high-performance web server known for its efficiency and stability. One of the key things it solves is the C10K problem (supporting 10,000+ concurrent clients). More on that here: The C10K problem
But Nginx can't handle dynamic content (like Python). That's where uWSGI comes in. Here’s the architecture:
🌐 Web Client → 🌐 Nginx → 🔗 Unix Socket → 🔌 uWSGI → 🐍 Django
Why uWSGI? uWSGI acts as a bridge between Nginx and Django, communicating using the uWSGI protocol.
Why still use Nginx?
- Nginx serves static content (HTML, CSS, JS, images) efficiently.
- Better performance than uWSGI for static files.
- Supports caching, reverse proxying, and load balancing.
💡 Tip: To learn more about reverse proxying, check out this explanation: Forward Proxy vs Reverse Proxy
When developing locally with python manage.py runserver
, Django runs its own lightweight server. It’s fine for development but not suitable for production due to performance and security limitations.
In Heroku, Gunicorn is recommended, and I’ve used it in these tutorials:
Both uWSGI and Gunicorn are great—choose based on your specific deployment needs.
Both Nginx and Apache are excellent. It depends on your requirements and environment. There’s no single "best" server—choose what works best for your case 👍
We'll use Docker to create three containers:
- Nginx
- Django + uWSGI
- PostgreSQL
This is based on uWSGI + Django + Nginx tutorial, with some custom tweaks.
Check out the nginx/Dockerfile
:
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
COPY my_nginx.conf /etc/nginx/sites-available/
RUN mkdir -p /etc/nginx/sites-enabled/ \
&& ln -s /etc/nginx/sites-available/my_nginx.conf /etc/nginx/sites-enabled/
CMD ["nginx", "-g", "daemon off;"]
Explanation:
-
Copy
nginx.conf
to/etc/nginx/nginx.conf
.
You can grab the original config from a running nginx container at/etc/nginx/nginx.conf
.
See the original:nginx_origin.conf
-
Modify:
user root;
And:
# include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-available/*;
This disables the default config and enables our custom site config.
-
Copy
my_nginx.conf
to/etc/nginx/sites-available/
.Note: If you're using
nginx:latest
, the directories/etc/nginx/sites-available/
and/etc/nginx/sites-enabled/
may not exist. You can create them yourself (see Dockerfile commands). -
Use a symbolic link to enable the site:
ln -s /etc/nginx/sites-available/my_nginx.conf /etc/nginx/sites-enabled/
upstream uwsgi {
server unix:/docker_api/app.sock;
}
server {
listen 80;
server_name twtrubiks.com www.twtrubiks.com;
charset utf-8;
client_max_body_size 75M;
location /static {
alias /docker_api/static;
}
location / {
uwsgi_pass uwsgi;
include /etc/nginx/uwsgi_params;
}
}