Hosting a Django application involves multiple components to ensure it runs efficiently and securely. In this blog, we'll cover the step-by-step process of hosting a Django application with a PostgreSQL database, using Gunicorn as the application server managed by Supervisor, Nginx as the web server, and Redis for caching.
Connect to your instance via SSH, and proceed with the necessary setup.
I have used AWS EC2 t4g.small instance with Ubuntu AMI for this Hosting post.
Step 1: Installing and Setting Up PostgreSQL
# Install PostgreSQL
sudo apt update
sudo apt install postgresql postgresql-contrib
# Enable and start Postgresql
sudo systemctl enable postgresql
sudo systemctl start postgresql
# Create database and role:
sudo su - postgres
createdb db_name
echo "CREATE ROLE db_user WITH PASSWORD 'db_password';" | psql
echo "ALTER ROLE db_user WITH LOGIN;" | psql
echo "GRANT ALL PRIVILEGES ON DATABASE "db_name" to db_user;" | psql
exit
Replace db_name with your database name, db_user with your database user and db_password with your database password
Step 2: Organizing project structure
cd
mkdir repo.git app conf logs media static
These directories will respectively hold your Git repository, application code, configuration files, logs, media files, and static files. This organized structure ensures that all components of your Django project are neatly separated, making it easier to manage and maintain the application throughout its lifecycle.
Step 3: Initialize and Configuring Git Repository
Initialize a bare Git repository. A bare repository is used to manage code collaboration without working copies.
cd repo.git
git init --bare
git --bare update-server-info
# Configure the repository to work with our deployment setup
git config core.bare false
git config receive.denycurrentbranch ignore
git config core.worktree /home/ubuntu/app/
The core.bare false configuration makes the repository behave like a non-bare repository. The receive.denycurrentbranch ignore allows us to push to the currently checked-out branch. The core.worktree configuration points to the directory where our application code will live.
Create a Post-Receive Hook
A Git hook is a script that is executed at certain points in the Git workflow. We'll use a post-receive hook to automatically deploy the code whenever a push is made to the repository.
cat > hooks/post-receive <<EOF
#!/bin/sh
git checkout -f
. ../env/bin/activate
cd ../app
pip install -r requirements/prod.txt
python manage.py collectstatic --noinput
python manage.py migrate -v 0
sudo supervisorctl reload
EOF
# Make the script executable
chmod +x hooks/post-receive
Step 4: Adding remote repository in local machine
# In Your Project, in Local Machine
git remote add prod ubuntu@ip_address:/home/ubuntu/repo.git/
ssh-copy-id ubuntu@ip_address
git push prod master
Step 5: Setup Virtual environment
Using a virtual environment is a best practice for Python projects, as it isolates your project dependencies from the system-wide packages.
sudo apt install python3-pip
sudo apt install python3-virtualenv
pip3 install virtualenv
cd
virtualenv env -p python3
source env/bin/activate
Step 6: Project Setup in Server
cd app
pip install -r requirements/prod.txt
pip install gunicorn
python manage.py migrate
python manage.py collectstatic
Step 7: Installing and Configuring Supervisor
Supervisor is a process control system that helps manage and monitor your applications. It keeps your processes running by automatically restarting them if they fail. It ensures that your applications stay up and running, providing a simple way to manage long-running processes.
sudo apt install supervisor
sudo systemctl enable supervisor
sudo systemctl start supervisor
vi conf/supervisor.conf
[program:django_project]
command=/home/ubuntu/env/bin/gunicorn config.wsgi:application --workers 3 --bind 127.0.0.1:8000
user=ubuntu
directory=/home/ubuntu/app/
autostart=true
autorestart=true
stdout_logfile=/home/ubuntu/logs/django.log
stderr_logfile=/home/ubuntu/logs/django_err.log
config.wsgi:application change this to your wsgi folder path
This Supervisor configuration file manages the Django project by running the Gunicorn server with three worker processes, binding it to 127.0.0.1:8000. The django_project program runs under the ubuntu user within the /home/ubuntu/app/ directory. The process is set to autostart with the system and automatically restart if it fails. Logs are directed to /home/ubuntu/logs/django.log for standard output and /home/ubuntu/logs/django_err.log for errors, ensuring comprehensive monitoring and management of the application.
# Soft-link supervisor configuration to supervisor conf.d directory
sudo ln -s /home/ubuntu/conf/supervisor.conf /etc/supervisor/conf.d/project_name.conf
sudo supervisorctl reload
Step 8: Installing and Configuring Nginx
Nginx is a high-performance web server and reverse proxy that efficiently handles incoming requests and serves static content. It enhances the performance and scalability of Django application by forwarding requests to backend servers like Gunicorn, ensuring your application can manage high traffic with stability and low resource consumption.
sudo apt install nginx
sudo systemctl enable nginx
sudo rm /etc/nginx/sites-enabled/default
vim conf/nginx.conf
upstream django_project {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name domain_name.com;
access_log /home/ubuntu/logs/nginx.access.log;
error_log /home/ubuntu/logs/nginx.error.log;
# limit_conn conn_limit_per_ip 100;
# limit_req zone=req_limit_per_ip burst=100 nodelay;
location /robots.txt {
alias /home/ubuntu/static/robots.txt;
}
location /favicon.ico {
alias /home/ubuntu/static/img/favicon.ico;
}
location ~ ^/(media|static)/ {
root /home/ubuntu/;
expires 30d;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_pass http://django_project;
client_max_body_size 50m;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options SAMEORIGIN;
}
# Prevent hidden files (beginning with a period) from being served
location ~ /\. { access_log off; log_not_found off; deny all; }
}
This Nginx configuration sets up a reverse proxy for a Django application running on 127.0.0.1:8000. It listens on port 80 and uses the server name domain_name.com. Access and error logs are stored in specified directories. Static and media files are served directly from the /home/ubuntu/ directory, with caching enabled for 30 days. The configuration also handles robots.txt and favicon.ico requests directly.
In the main location block, it sets various headers for security and proxies requests to the Django application. It limits the maximum client request body size to 50MB and includes security headers to enforce HTTPS, prevent content sniffing, XSS attacks, and clickjacking. Additionally, it denies access to hidden files, enhancing security by preventing unauthorized access.
Don't forget to replace domain_name with your own domain.
Soft-link this configuration to nginx conf.d directory
sudo ln -s /home/ubuntu/conf/nginx.conf /etc/nginx/conf.d/django_project.conf
Step 9: Securing Server with SSL
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx
# Follow the on-screen instructions to complete the setup.
Step 10: Reload Nginx and Supervisor
# Checking Nginx configuration
sudo nginx -t
# Restarting Nginx
sudo systemctl restart nginx
# Restarting supervisor
sudo supervisorctl reload
Whenever you make changes to your Nginx or Supervisor configuration, it's crucial to restart these services to apply the updates.
Troubleshooting 403 Forbidden Errors
If you're encountering a "403 Forbidden" error while trying to access a web page on your server, one common cause is insufficient permissions for the web server to access the necessary files. In many cases, this issue can be resolved by ensuring that the user running the web server is part of the www-data group.
sudo usermod -a -G ubuntu www-data
This command adds the ubuntu user to the www-data group, granting it the necessary permissions to access and serve web content.
After running this command, be sure to restart your web server to apply the changes. This simple step can often resolve frustrating "403 Forbidden" errors and ensure that your web server operates smoothly.
Top comments (0)