Deploying a web application can seem daunting, but it's a manageable process with a structured approach. This guide walks you through setting up a secure Linux server and deploying your Django application using two popular stacks: Apache with mod_wsgi
or Nginx with Gunicorn.
Note: The core principles in this guide remain best practices for modern Django deployments.
🔐 Step 1: Server Initialization & Security
A secure, well-configured server is the foundation of any deployment.
1.1. System Update
First, log into your new Linux server (e.g., Ubuntu, Debian) and ensure all system packages are up-to-date.
# On Debian/Ubuntu-based systems
sudo apt update && sudo apt upgrade -y
1.2. Create a Non-Root User
Running commands as root
is a major security risk. Create a new user with administrative privileges instead.
# Create a new user (you'll be prompted for a password)
adduser your_username
# Add the new user to the 'sudo' group
usermod -aG sudo your_username
# Log out of root and log back in as your new user
exit
1.3. Harden SSH Access with Keys
Disable password-based logins in favor of more secure SSH keys.
On your local machine, generate a new SSH key pair.
ssh-keygen -t rsa -b 4096
Follow the prompts. Adding a passphrase is a good extra layer of security.
Next, copy your public key to the server. The easiest method is using ssh-copy-id
.
ssh-copy-id your_username@your_server_ip
1.4. Disable Password & Root Login
On your server, edit the SSH daemon configuration.
sudo nano /etc/ssh/sshd_config
Find and modify these lines to enhance security:
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
Restart the SSH service to apply the changes.
sudo systemctl restart ssh
🚨 Critical: Before you close your current terminal, open a new one and confirm you can log in with your SSH key. If you can't, you'll be locked out! Revert the changes if it fails.
🔥 Step 2: Configure the Firewall with UFW
UFW (Uncomplicated Firewall) is an easy way to manage your server's network rules.
# Deny all incoming traffic and allow all outgoing by default
sudo ufw default deny incoming
sudo ufw default allow outgoing
# CRITICAL: Allow SSH access before enabling the firewall
sudo ufw allow ssh
# Allow HTTP and HTTPS traffic for your web app
sudo ufw allow http
sudo ufw allow https
# Enable the firewall
sudo ufw enable
You can check the status at any time with sudo ufw status
.
📦 Step 3: Prepare Your Django Project
Get your project code and dependencies ready for the server.
3.1. Create requirements.txt
On your local machine, inside your project's virtual environment, generate a list of its Python dependencies.
pip freeze > requirements.txt
3.2. Transfer Project to Server
You can use scp
for a simple copy or git
for version-controlled projects.
-
Using
scp
(Secure Copy):
scp -r /path/to/local/project your_username@your_server_ip:~/
-
Using
git
(Recommended):
git clone your_repository_url
🐍 Step 4: Set Up a Python Virtual Environment
Isolate your project's dependencies from the system's Python packages on the server.
sudo apt install python3-pip python3-venv -y
# Navigate to your project directory
cd your_project_name
# Create a virtual environment named 'venv'
python3 -m venv venv
# Activate it
source venv/bin/activate
Your shell prompt will now be prefixed with (venv)
.
⚙️ Step 5: Install Dependencies & Configure Django
With the virtual environment active, install your packages and adjust your settings for production.
5.1. Install Packages
pip install -r requirements.txt
5.2. Adjust settings.py
Edit your project's settings.py
file for production.
# your_project/settings.py
import os
# ... other settings ...
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ['your_server_ip', 'your_domain.com']
# Define the location for all static files
STATIC_ROOT = os.path.join(BASE_DIR, 'static_root')
5.3. Collect Static Files
Run Django's collectstatic
command to gather all static assets (CSS, JS, images) into the STATIC_ROOT
directory you just defined.
python manage.py collectstatic
🐘 Step 6: Set Up PostgreSQL Database
A robust database like PostgreSQL is essential for production.
6.1. Install PostgreSQL
sudo apt install postgresql postgresql-contrib -y
6.2. Create Database & User
Switch to the postgres
user to create your database and a dedicated user for your app.
sudo -u postgres psql
Inside the psql
shell, run these commands:
CREATE DATABASE myprojectdb;
CREATE USER myprojectuser WITH PASSWORD 'a_very_strong_password';
ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE myprojectdb TO myprojectuser;
-- Exit the psql shell
\q
6.3. Update settings.py
Update the DATABASES
setting in settings.py
with your new credentials.
# your_project/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'myprojectdb',
'USER': 'myprojectuser',
'PASSWORD': 'a_very_strong_password',
'HOST': 'localhost',
'PORT': '', # Default is 5432
}
}
Important: Don't hardcode passwords! We'll secure these credentials in Step 8. You'll also need to install the database adapter: pip install psycopg2-binary
.
6.4. Run Migrations
Apply your project's database schema.
python manage.py migrate
🚀 Step 7: Configure a Production Web Server
Django's development server isn't for production. Choose one of the following setups.
Option A: Apache & mod_wsgi
A classic and powerful combination.
-
Install Packages:
sudo apt install apache2 libapache2-mod-wsgi-py3 -y sudo a2enmod wsgi
-
Configure Apache Virtual Host: Create a new configuration file for your site.
sudo nano /etc/apache2/sites-available/your_project.conf
Paste and edit the following configuration.
<VirtualHost *:80> ServerName your_domain.com ServerAlias www.your_domain.com Alias /static /home/your_username/your_project_name/static_root <Directory /home/your_username/your_project_name/static_root> Require all granted </Directory> <Directory /home/your_username/your_project_name/your_project/ > <Files wsgi.py> Require all granted </Files> </Directory> WSGIDaemonProcess your_project python-home=/home/your_username/your_project_name/venv python-path=/home/your_username/your_project_name WSGIProcessGroup your_project WSGIScriptAlias / /home/your_username/your_project_name/your_project/wsgi.py </VirtualHost>
-
Enable Site & Reload:
sudo a2ensite your_project.conf sudo a2dissite 000-default.conf # Disable the default page sudo systemctl restart apache2
Option B: Nginx & Gunicorn (Recommended)
A modern, high-performance stack. Nginx acts as a reverse proxy, passing requests to the Gunicorn application server.
-
Install Packages:
sudo apt install nginx -y pip install gunicorn # Install inside your venv
-
Configure Nginx Server Block: Create a new Nginx configuration file.
sudo nano /etc/nginx/sites-available/your_project
Paste and edit the following. This tells Nginx to serve static files directly and proxy other requests to Gunicorn.
server { listen 80; server_name your_domain.com www.your_domain.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/your_username/your_project_name; } location / { proxy_set_header Host $http_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.sock; } }
-
Enable Site & Reload:
sudo ln -s /etc/nginx/sites-available/your_project /etc/nginx/sites-enabled sudo nginx -t # Test configuration for errors sudo systemctl restart nginx
-
Create a
systemd
Service for Gunicorn: To ensure Gunicorn runs reliably and starts on boot, create a service file.
sudo nano /etc/systemd/system/gunicorn.service
Paste and edit the following.
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=your_username Group=www-data WorkingDirectory=/home/your_username/your_project_name ExecStart=/home/your_username/your_project_name/venv/bin/gunicorn \ --access-logfile - \ --workers 3 \ --bind unix:/run/gunicorn.sock \ your_project.wsgi:application [Install] WantedBy=multi-user.target
-
Create a
systemd
Socket File:
sudo nano /etc/systemd/system/gunicorn.socket
```
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
```
-
Start and Enable Gunicorn:
sudo systemctl start gunicorn.socket sudo systemctl enable gunicorn.socket
🤫 Step 8: Secure Environment Variables
Never store sensitive keys, passwords, or secrets directly in settings.py
. Use environment variables. A clean way to manage this is with a .env
file.
-
Install
python-decouple
:
pip install python-decouple
-
Create a
.env
file in your project's root directory (next tomanage.py
). Add this file to your.gitignore
immediately!
# .env file SECRET_KEY='your-django-secret-key-goes-here' DEBUG=False DATABASE_URL='postgres://myprojectuser:a_very_strong_password@localhost:5432/myprojectdb' ALLOWED_HOSTS='.your_domain.com,your_server_ip'
-
Update
settings.py
to usedecouple
:
# your_project/settings.py from decouple import config, Csv import dj_database_url # ... SECRET_KEY = config('SECRET_KEY') DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv()) # Database DATABASES = { 'default': dj_database_url.config(default=config('DATABASE_URL')) }
✅ Final Step: Verification
Navigate to your server's IP address or domain name in your web browser. You should now see your live Django application!
Next Steps
- HTTPS: Use Let's Encrypt to get a free SSL/TLS certificate. It's essential.
- Backups: Set up a regular backup strategy for your database and user-uploaded files.
- Logging & Monitoring: Configure logging to monitor application health and track errors.
Happy deploying!
Top comments (4)
Man, thanks a lot! This guide has all I needed. It saved my day! I even sign up here to say thanks!)
You're welcome! I'm glad the guide helped you out.
Is there a video to this? And does this work with a django app that take react as frontend. I’ve created APIS with django rest framework and built the front end with react.
Will this work ?
you have to deploy them separately. Yes you can use this guide to deploy django apps with DRF.
youtube.com/watch?v=Sa_kQheCnds (refer this video)