Learn how to deploy Django on AlmaLinux 10 using Gunicorn as the WSGI application server and Nginx as the reverse proxy. This setup is widely used in production environments because it is stable, efficient, and easy to maintain.
Introduction
Deploying a Django application to production requires a reliable web server, a stable application server, and a clean configuration that ensures performance and security.
Our goal is to create a deployment structure that is secure, scalable, and suitable for real-world applications.
Prerequisites
Before we begin, ensure we have the following:
- An AlmaLinux 10 on dedicated server or KVM VPS.
- Basic Linux Command Line Knowledge.
- A domain name pointing A DNS record to server IP.
- Set SELinux permissive because with SELinux it will give 504 error.
- Execute setenforce 0.
Step 1 - Update the Server
We begin by ensuring the system packages are fully updated.
sudo dnf update
Install essential development packages required for building Python dependencies.
sudo dnf install -y python3 python3-pip python3-devel gcc git
These packages allow Python modules with compiled extensions to install correctly.
Step 2 - Create a Project Directory
Production deployments should never run directly from a home directory.
We create a clean application directory.
sudo mkdir -p /usr/share/nginx/django_app
Give ownership to the current user.
sudo chown -R $USER:$USER /usr/share/nginx/django_app
Move inside the directory.
cd /usr/share/nginx/django_app
Step 3 - Create Python Virtual Environment
A virtual environment isolates project dependencies and prevents conflicts with system packages.
Create the environment:
python3 -m venv venv
Activate it:
source venv/bin/activate
Upgrade pip:
pip install --upgrade pip
Step 4 - Install Django and Gunicorn
Install the core dependencies.
pip install django gunicorn
If the project uses additional dependencies, install them from the requirements file.
pip install -r requirements.txt
Step 5 - Create or Upload the Django Project
If starting fresh, create the project.
django-admin startproject project .
Run database migrations.
python manage.py migrate
Create an admin user.
python manage.py createsuperuser
This ensures static assets are served efficiently by Nginx rather than Django.
Step 6 - Configure Django for Production
Open the Django settings file.
nano project/settings.py
Update the ALLOWED_HOSTS setting.
ALLOWED_HOSTS = ["server_ip", "domain.com"]
Add static file configuration.
STATIC_ROOT = "/usr/share/nginx/django_app/static"
Save and exit.
Collect static files.
python manage.py collectstatic
Step 7 - Install and Configure Nginx
Install Nginx.
sudo dnf install nginx -y
Allow HTTP through the firewall.
sudo firewall-cmd --add-port={80,443}/tcp --permanent
sudo firewall-cmd --reload
Create a new site configuration.
sudo nano /etc/nginx/conf.d/django_app.conf
Add the following configuration.
server {
listen 80;
server_name domain.com server_ip;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /var/www/django_app;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unix:/run/gunicorn/gunicorn.sock;
}
}
Test configuration.
sudo nginx -t
Reload Nginx.
sudo systemctl restart nginx
Step 8 - Create Gunicorn Systemd Service
Gunicorn creates the socket file used by Nginx. Ensure proper permissions exist.
Create runtime directory.
sudo mkdir -p /run/gunicorn
Set permissions.
sudo chown nginx:nginx /run/gunicorn
Running Gunicorn manually is not suitable for production. We configure systemd so the application runs automatically.
Create the service file.
sudo nano /etc/systemd/system/gunicorn.service
Add the configuration below.
[Unit]
Description=Gunicorn daemon for Django
After=network.target
[Service]
User=nginx
Group=nginx
WorkingDirectory=/usr/share/nginx/django_app
ExecStart=/usr/share/nginx/django_app/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/gunicorn/gunicorn.sock \
project.wsgi:application
[Install]
WantedBy=multi-user.target
Save the file.
Reload systemd.
sudo systemctl daemon-reload
Start Gunicorn.
sudo systemctl start gunicorn
Enable it on boot.
sudo systemctl enable gunicorn
Verify status.
sudo systemctl status gunicorn
Step 9 - Configure Static File Serving
Nginx should handle static assets to improve performance.
Ensure static files exist.
python manage.py collectstatic
Nginx already serves /static/ from:
/usr/share/nginx/django_app/static
This avoids unnecessary load on Gunicorn.
Step 10 - Secure the Application with HTTPS
Production deployments should always use SSL.
Install Certbot.
sudo dnf install certbot python3-certbot-nginx -y
Generate the certificate.
sudo certbot --nginx -d domain.com
Certbot automatically updates the Nginx configuration and sets up automatic renewal.
Troubleshooting
If you get error in gunicorn service, try to run gunicorn manually in debug mode:
gunicorn project.wsgi:application --bind 0.0.0.0:8000 --workers 2 --log-level debug
Step 12 - Production Optimization
A stable deployment requires a few practical optimizations.
Increase Gunicorn workers
workers = (2 × CPU cores) + 1
Example:
--workers 5
Enable logging
Logs help diagnose production issues.
Gunicorn logs can be viewed with:
journalctl -u gunicorn
Nginx logs are located at:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
Restart services after updates
sudo systemctl restart gunicorn
sudo systemctl reload nginx
Final Thoughts
Deploying Django with Gunicorn and Nginx on AlmaLinux 10 creates a production-ready environment capable of serving real applications reliably.
Gunicorn manages Python application execution, while Nginx efficiently handles HTTP requests, static files, and reverse proxy responsibilities. This architecture ensures stability, performance, and scalability.
By following this deployment approach, we build a clean and maintainable infrastructure that can support both small projects and large production workloads.

