DEV Community

Cover image for How to set up and deploy a Django application on a Linux server
Ajith Kumar P M
Ajith Kumar P M

Posted on • Edited on

How to set up and deploy a Django application on a Linux server

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

1.4. Disable Password & Root Login

On your server, edit the SSH daemon configuration.

sudo nano /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode

Find and modify these lines to enhance security:

PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
Enter fullscreen mode Exit fullscreen mode

Restart the SSH service to apply the changes.

sudo systemctl restart ssh
Enter fullscreen mode Exit fullscreen mode

🚨 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:~/
Enter fullscreen mode Exit fullscreen mode
  • Using git (Recommended):
git clone your_repository_url
Enter fullscreen mode Exit fullscreen mode

🐍 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

🐘 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

🚀 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.

  1. Install Packages:

    sudo apt install apache2 libapache2-mod-wsgi-py3 -y
    sudo a2enmod wsgi
    
  2. 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>
    
  3. 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.

  1. Install Packages:

    sudo apt install nginx -y
    pip install gunicorn # Install inside your venv
    
  2. 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;
        }
    }
    
  3. 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
    
  4. 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
    
  5. 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
```
Enter fullscreen mode Exit fullscreen mode
  1. 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.

  1. Install python-decouple:

    pip install python-decouple
    
  2. Create a .env file in your project's root directory (next to manage.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'
    
  3. Update settings.py to use decouple:

    # 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)

Collapse
 
agas0077 profile image
Andrey • Edited

Man, thanks a lot! This guide has all I needed. It saved my day! I even sign up here to say thanks!)

Collapse
 
ajth-in profile image
Ajith Kumar P M

You're welcome! I'm glad the guide helped you out.

Collapse
 
izenish profile image
Zenish

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 ?

Collapse
 
ajth-in profile image
Ajith Kumar P M • Edited

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)