Comprehensive Django Deployment Guide for Beginners
Table of contents
- Table of Contents
- 1. Introduction
- 2. Prerequisites
- 3. Setting Up Your VPS
- 4. Securing Your Server
- 5. Installing Required Software
- 6. Configuring Your Django Project
- 7. Nginx Configuration
- 8. Setting Up SSL with Let's Encrypt
- 9. Configuring Supervisor
- 10. Firewall Configuration
- 11. Deploying Your Django Application
- 12. Running the Redis Scheduler
- 13. Custom Scripts for Process Management
- 14. Monitoring and Maintenance
- 15. Troubleshooting
- 16. Conclusion
Table of Contents
Introduction
Prerequisites
Setting Up Your VPS
Securing Your Server
Installing Required Software
Configuring Your Django Project
Setting Up Nginx and Uvicorn
Configuring SSL with Let's Encrypt
Setting Up Supervisor
Firewall Configuration
Deploying Your Django Application
Running the Redis Scheduler
Monitoring and Maintenance
Troubleshooting
Conclusion
1. Introduction
This guide will walk you through the process of deploying a Django application with ASGI (Uvicorn) to a Virtual Private Server (VPS). We'll also cover setting up a Redis scheduler, configuring Nginx as a reverse proxy, securing your server with a firewall, and enabling HTTPS. This guide is designed for beginners, so we'll explain each step in detail.
2. Prerequisites
Before we begin, make sure you have:
A VPS running Ubuntu 22.04
A domain name (e.g., tymr.online) pointed to your VPS's IP address
Your Django project code (including requirements.txt)
Basic familiarity with command-line interfaces
3. Setting Up Your VPS
First, we need to access our VPS. We'll use SSH (Secure Shell) for this.
ssh root@your_server_ip
Replace your_server_ip
with your VPS's IP address. You'll be prompted for a password, which you should have received from your VPS provider or in most VPS you can directly login into server after pasting the local desktop’s ssh public key into the server during the setup process. for example, in digital ocean you have this feature here while creating a droplet ( VPS ) 👇
Once logged in, update your system:
sudo apt update
sudo apt upgrade -y
These commands update the list of available packages and upgrade them to their latest versions.
4. Securing Your Server
Creating a New User
It's best practice to avoid using the root user. Let's create a new user:
adduser username
Replace username
with your desired username. You'll be prompted to set a password and provide some optional information.
Grant this user sudo privileges:
usermod -aG sudo username
This command adds the user to the sudo group, allowing them to run commands with superuser privileges.
Setting Up SSH Key Authentication
SSH keys are more secure than passwords. On your local machine, generate an SSH key pair:
ssh-keygen -t rsa -b 4096
This creates a public/private key pair. The public key can be freely shared, while the private key must be kept secret.
Copy the public key to your server:
ssh-copy-id username@your_server_ip
Now, let's disable password authentication for SSH. On the server:
sudo nano /etc/ssh/sshd_config
Find and modify these lines:
PasswordAuthentication no
PermitRootLogin no
Save the file (Ctrl+X, then Y, then Enter) and restart the SSH service:
sudo systemctl restart sshd
Now login as non root user you just created.
5. Installing Required Software
Let's install the necessary software:
sudo apt install build-essential python3-dev python3.11 python3.11-venv python3-pip nginx redis
This installs Python 3.11, pip (Python package manager), and Nginx (web server).
6. Configuring Your Django Project
Create a directory for your project:
mkdir ~/myproject
cd ~/myproject
Upload your project files to this directory. You can use SCP, SFTP, or Git for this.
Create a virtual environment:
python3.11 -m venv venv
source venv/bin/activate
Install your project dependencies:
pip install -r requirements.txt
Also, install Uvicorn:
pip install uvicorn
Understanding and Setting Up User Permissions for our Django project
When deploying a Django application, proper file permissions and ownership are crucial for security and functionality. Here's a detailed guide tailored for beginners:
Understanding Users and Groups
In our setup, we'll work with three main entities:
Your user account (e.g., 'normaluser')
The web server user (usually 'www-data' for Nginx on Ubuntu)
The root user
Best Practices for Django Project Files
Project Directory Ownership: Your user should own the project directory and most files.
sudo chown -R normaluser:normaluser /home/normaluser/myproject
Project Directory Permissions: Set 755 (drwxr-xr-x) for directories and 644 (-rw-r--r--) for files.
find /home/normaluser/myproject -type d -exec chmod 755 {} \; find /home/normaluser/myproject -type f -exec chmod 644 {} \;
Sensitive Files: For files like
settings.py
, use more restrictive permissions.chmod 600 /home/normaluser/myproject/myproject/settings.py
Static and Media Directories: The web server needs read access to these.
sudo chown -R normaluser:www-data /home/normaluser/myproject/static sudo chown -R normaluser:www-data /home/normaluser/myproject/media sudo chmod -R 750 /home/normaluser/myproject/static sudo chmod -R 750 /home/normaluser/myproject/media
Log Directory: Create a logs directory within your project and set appropriate permissions.
mkdir -p /home/normaluser/myproject/logs sudo chown -R normaluser:www-data /home/normaluser/myproject/logs sudo chmod -R 770 /home/normaluser/myproject/logs
SQLite Database (if used): If you're using SQLite, secure the database file.
sudo chown normaluser:www-data /home/normaluser/myproject/db.sqlite3 sudo chmod 660 /home/normaluser/myproject/db.sqlite3
Virtual Environment: Keep your virtual environment secure.
chmod -R 750 /home/normaluser/myproject/venv
Explanation of Permissions
755 for directories: Owner can read/write/execute, others can read/execute.
644 for regular files: Owner can read/write, others can read.
600 for sensitive files: Only owner can read/write.
750 for static/media: Owner can read/write/execute, group (www-data) can read/execute.
770 for logs: Owner and group can read/write/execute.
660 for SQLite: Owner and group can read/write.
Security Best Practices
Principle of Least Privilege: Give only the permissions necessary for each file and directory.
Use a Non-Root User: Always run your Django application as a non-root user.
Separate Media Uploads: If possible, store user-uploaded files outside of the project directory.
Regular Audits: Periodically check and update file permissions.
Use Environment Variables: Store sensitive information like secret keys in environment variables, not in files.
Secure the Secret Key: Ensure Django's SECRET_KEY is not in version control and has restricted access.
Backup Permissions: When backing up, preserve file permissions.
Applying Changes
After setting permissions, restart your web server and Django application:
sudo systemctl restart nginx
sudo supervisorctl restart all
Verifying Permissions
You can verify permissions using the ls -l
command. For example:
ls -l /home/normaluser/myproject
This will show you the permissions for files and directories in your project root.
Remember, these settings are a starting point. You may need to adjust based on your specific setup and security requirements. Always test thoroughly after changing permissions to ensure your application functions correctly.
7. Nginx Configuration
Before we set up our Nginx configuration, let's remove the default configuration:
sudo rm /etc/nginx/sites-enabled/default
Now, let's create our configuration file:
sudo nano /etc/nginx/sites-available/myproject
Add the following content:
server {
# replace your domain names with placeholder tymr.online
server_name tymr.online www.tymr.online; # Your domain name(s)
location = /favicon.ico {
access_log off;
log_not_found off;
} # Efficiently handle favicon requests
location /static/ {
root /home/username/myproject; # Path to your static files
} # Serve static files directly
location / {
proxy_pass http://unix:/home/username/myproject/myproject.sock; # Pass requests to Uvicorn
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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 settings for Uvicorn
}
Let's break this down:
server_name
: Specifies which domain names this server block should respond to.location = /favicon.ico
: Efficiently handles favicon requests.location /static/
: Configures Nginx to serve static files directly, without passing the request to Django.location /
: The main block that handles all other requests.proxy_pass
: Forwards requests to our Uvicorn server.The
proxy_set_header
directives: Pass necessary headers to the Django application.
After creating this file, enable it:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
This creates a symbolic link, effectively enabling our configuration.
Test the Nginx configuration:
sudo nginx -t
If it's okay, restart Nginx:
sudo systemctl restart nginx
8. Setting Up SSL with Let's Encrypt
We'll use Snap to install Certbot, which automates the process of obtaining and renewing Let's Encrypt certificates.
Ensure Snap is up-to-date:
sudo snap install core; sudo snap refresh core
This installs and updates the core snap package.
Remove any old Certbot installations:
sudo apt remove certbot
Install Certbot via Snap:
sudo snap install --classic certbot
The
--classic
flag allows Certbot to access system resources outside of the snap's confined environment.Create a symbolic link for easy access:
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Obtain and install the certificate:
sudo certbot --nginx -d tymr.online -d www.tymr.online
This command will:
Obtain a certificate for your domains
Automatically configure Nginx to use the new certificate
Set up automatic renewal
Follow the prompts during the Certbot execution. It will ask for your email and agreement to terms of service.
For more detailed information, you can refer to this similar guide: How To Secure Nginx with Let's Encrypt on Ubuntu 22.04
9. Configuring Supervisor
Supervisor is a process control system that allows you to monitor and control a number of processes on UNIX-like operating systems. We use Supervisor because:
It automatically restarts processes if they crash.
It starts processes on system boot.
It provides an easy way to start, stop, and monitor processes.
It logs stdout and stderr of the processes it manages.
Here's how to set it up:
Install Supervisor:
sudo apt install supervisor
Create a configuration file:
sudo nano /etc/supervisor/conf.d/myproject.conf
Add the following content:
[program:myproject]
command=/home/username/myproject/venv/bin/uvicorn myproject.asgi:application --unix-socket /home/username/myproject/myproject.sock
directory=/home/username/myproject
user=username
autostart=true
autorestart=true
stderr_logfile=/var/log/myproject.err.log
stdout_logfile=/var/log/myproject.out.log
[program:celery]
command=/home/username/myproject/venv/bin/celery -A myproject worker -l info
directory=/home/username/myproject
user=username
autostart=true
autorestart=true
stderr_logfile=/var/log/celery.err.log
stdout_logfile=/var/log/celery.out.log
[program:redis_scheduler]
command=/home/username/myproject/venv/bin/python manage.py redis_scheduler
directory=/home/username/myproject
user=username
autostart=true
autorestart=true
stderr_logfile=/var/log/redis_scheduler.err.log
stdout_logfile=/var/log/redis_scheduler.out.log
This configuration sets up three processes:
Your Django application running with Uvicorn
A Celery worker for background tasks
Your custom Redis scheduler
Reload Supervisor to apply changes:
sudo supervisorctl reread sudo supervisorctl update
Supervisor is different from simple systemd services because it provides more fine-grained control and is specifically designed for managing application processes, making it ideal for complex setups like Django projects with multiple components.
10. Firewall Configuration
UFW (Uncomplicated Firewall) is a user-friendly interface for managing iptables, the default firewall management tool for Ubuntu.
Enable UFW:
sudo ufw enable
Allow necessary connections:
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
These commands allow SSH connections and both HTTP and HTTPS traffic for Nginx.
Check the status:
sudo ufw status
Final List of UFW Commands:
sudo ufw allow OpenSSH # You need to allow SSH so you can access your VPS remotely.
sudo ufw allow 'Nginx HTTP'
sudo ufw allow 'Nginx HTTPS'
sudo ufw allow 8000 # Optional, for development server
sudo ufw enable
sudo ufw status
11. Deploying Your Django Application
Collect static files:
python manage.py collectstatic
Apply migrations:
python manage.py migrate
12. Running the Redis Scheduler
The Redis scheduler should now be managed by Supervisor. You can check its status with:
sudo supervisorctl status
13. Custom Scripts for Process Management
To simplify starting and stopping all processes, you can create custom scripts. Here are examples:
Create a start script:
nano ~/start_all.sh
Add the following content:
#!/bin/bash sudo supervisorctl start all sudo systemctl start nginx
Create a stop script:
nano ~/stop_all.sh
Add the following content:
#!/bin/bash sudo supervisorctl stop all sudo systemctl stop nginx
Make these scripts executable:
chmod +x ~/start_all.sh ~/stop_all.sh
Now you can start all processes with ./start_
all.sh
and stop them with ./stop_
all.sh
.
Remember to run these scripts with sudo if your user doesn't have the necessary permissions.
14. Monitoring and Maintenance
Regularly update your system:
sudo apt update
sudo apt upgrade
Monitor your logs:
tail -f /var/log/myproject.err.log
tail -f /var/log/myproject.out.log
tail -f /var/log/redis_scheduler.err.log
tail -f /var/log/redis_scheduler.out.log
15. Troubleshooting
If your site isn't accessible, check Nginx status:
sudo systemctl status nginx
If Uvicorn isn't running, check Supervisor:
sudo supervisorctl status
Check Nginx error logs:
sudo tail -f /var/log/nginx/error.log
Ensure your firewall isn't blocking connections:
sudo ufw status
16. Conclusion
You've now deployed your Django application with Uvicorn, set up Nginx as a reverse proxy, configured SSL, and set up a Redis scheduler. Your application should be accessible via HTTPS at your domain.
Remember to keep your system and applications updated, monitor your logs, and maintain good security practices.
Subscribe to my newsletter
Read articles from Saurav Sharma directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Saurav Sharma
Saurav Sharma
I am a Self Taught Backend developer With 3 Years of Experience. Currently, I am working at a tech Startup based in The Bahamas. Here are my skills so far - 💪Expert at - 🔹Python 🔹Django 🔹Django REST framework 🔹Celery ( for distributed tasks ) 🔹ORM ( Know how to write fast queries & design models ) 🔹Django 3rd party packages along with postgresQL and mysql as Databases. 🔹Cache using Redis & Memcache 🔹Numpy + OpenCV for Image Processing 🔹ElasticSearch + HayStack 🔹Linux ( Debian ) 😎 Working Knowledge - Html, CSS, JavaScript, Ajax, Jquery, Git ( GitHub & BitBucket ), Basic React & React Native, Linux ( Arch ), MongoDB, VPS 🤠 Currently Learning - 🔹More Deep Dive into Django 🔹Docker 🔹Making APIs more Robust 🔹NeoVim 🔹System Design ☺️ Will Be Learn in upcoming months - 🔹GraphQL 🔹 Rust language Other than above, there is not a single technology ever exists that i can't master if needed.