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)