Skip to main content

Django AWS Deployment

Introduction

Deploying a Django application to production requires a robust, scalable, and reliable hosting environment. Amazon Web Services (AWS) provides one of the most comprehensive cloud platforms available today, offering services that can handle everything from hosting your application code to managing your database and serving static files.

In this tutorial, we'll walk through the process of deploying a Django application on AWS, covering the following key AWS services:

  • EC2 (Elastic Compute Cloud) - Virtual servers to run your Django application
  • RDS (Relational Database Service) - Managed database service for your application data
  • S3 (Simple Storage Service) - Object storage for your static and media files
  • Elastic IP - Static IP address for your application
  • Route 53 - Domain name service (optional)

By the end of this guide, you'll have your Django application running in a production environment that can scale with your needs.

Prerequisites

Before starting this tutorial, make sure you have:

  1. A functioning Django application ready for deployment
  2. An AWS account
  3. Basic familiarity with Linux commands
  4. Git for version control
  5. Basic understanding of how Django works

Setting Up Your AWS Environment

Step 1: Create an EC2 Instance

Let's start by creating a virtual server using Amazon EC2:

  1. Log into your AWS Management Console
  2. Navigate to EC2 service
  3. Click "Launch Instance"
  4. Choose an Amazon Machine Image (AMI) - Ubuntu Server 22.04 LTS is recommended for beginners
  5. Select an instance type (t2.micro is eligible for free tier)
  6. Configure instance details (defaults are fine for now)
  7. Add storage (defaults are usually sufficient for a starter project)
  8. Add tags (optional but recommended, e.g., Name: django-app)
  9. Configure security group:
    • Allow SSH (port 22)
    • Allow HTTP (port 80)
    • Allow HTTPS (port 443)
  10. Review and launch
  11. Create or select an existing key pair (save the .pem file securely)

Step 2: Allocate an Elastic IP

To ensure your server has a fixed public IP address:

  1. In the EC2 dashboard, navigate to "Elastic IPs"
  2. Click "Allocate Elastic IP address"
  3. Click "Allocate"
  4. Select the newly allocated IP and click "Actions" → "Associate Elastic IP address"
  5. Select your EC2 instance and click "Associate"

Step 3: Connect to Your EC2 Instance

Open a terminal on your local machine and connect to your EC2 instance:

bash
chmod 400 your-key-pair.pem
ssh -i your-key-pair.pem ubuntu@your-elastic-ip

Setting Up Your Server

Step 1: Update the System

Once logged in to your EC2 instance, update the system packages:

bash
sudo apt update
sudo apt upgrade -y

Step 2: Install Required Packages

Install the necessary software for running Django:

bash
sudo apt install -y python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx git

Step 3: Create a Virtual Environment

Create and activate a Python virtual environment for your project:

bash
sudo pip3 install virtualenv
mkdir ~/myproject
cd ~/myproject
virtualenv venv
source venv/bin/activate

Setting Up a Database with RDS

Although you could install PostgreSQL directly on your EC2 instance, using Amazon RDS provides better scalability, automated backups, and maintenance.

Step 1: Create an RDS Instance

  1. Navigate to the RDS service in the AWS Management Console
  2. Click "Create database"
  3. Select "PostgreSQL"
  4. Choose "Free tier" if eligible
  5. Set the DB instance identifier (e.g., django-db)
  6. Set master username and password (save these securely)
  7. Under "Connectivity", select your EC2 instance's security group
  8. Create the database

Step 2: Configure Security Group

You need to allow your EC2 instance to connect to your RDS:

  1. Go to the RDS dashboard and click on your database
  2. Note the "Endpoint" (you'll need this later)
  3. Click on the security group used by your RDS
  4. Add an inbound rule allowing PostgreSQL (port 5432) from your EC2 security group

Deploying Your Django Project

Step 1: Clone Your Project

On your EC2 instance, clone your Django project repository:

bash
git clone https://github.com/yourusername/your-django-project.git
cd your-django-project

Step 2: Install Requirements

Install your project dependencies:

bash
pip install -r requirements.txt

If you don't have a requirements file, you should at least install:

bash
pip install django gunicorn psycopg2-binary

Step 3: Configure Django Settings

Create a production settings file or modify your existing settings to use environment variables for sensitive information:

python
# settings.py
import os

DEBUG = False
ALLOWED_HOSTS = ['your-elastic-ip', 'your-domain.com']

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'your_db_name',
'USER': 'your_db_username',
'PASSWORD': 'your_db_password',
'HOST': 'your-rds-endpoint.rds.amazonaws.com',
'PORT': '5432',
}
}

# Static files configuration for S3
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

Amazon S3 is great for serving static and media files. Let's configure it:

  1. Create an S3 bucket in the AWS Management Console
  2. Install django-storages and boto3:
bash
pip install django-storages boto3
  1. Add to your settings.py:
python
# settings.py
INSTALLED_APPS += ['storages']

AWS_ACCESS_KEY_ID = 'your-access-key'
AWS_SECRET_ACCESS_KEY = 'your-secret-key'
AWS_STORAGE_BUCKET_NAME = 'your-bucket-name'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
AWS_DEFAULT_ACL = 'public-read'

# Static files
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/'

# Media files
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/media/'

Step 5: Deploy Django

Initialize your Django project on the server:

bash
python manage.py migrate
python manage.py collectstatic
python manage.py createsuperuser

Setting Up Gunicorn

Gunicorn is a Python WSGI HTTP server that will run your Django application.

Step 1: Create a Gunicorn Service File

Create a systemd service file for Gunicorn:

bash
sudo nano /etc/systemd/system/gunicorn.service

Add the following:

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/your-django-project
ExecStart=/home/ubuntu/myproject/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/home/ubuntu/your-django-project/myproject.sock \
your_project_name.wsgi:application

[Install]
WantedBy=multi-user.target

Start and enable the Gunicorn service:

bash
sudo systemctl start gunicorn
sudo systemctl enable gunicorn

Setting Up Nginx

Nginx will act as a reverse proxy to Gunicorn.

Step 1: Create an Nginx Configuration

bash
sudo nano /etc/nginx/sites-available/myproject

Add the following configuration:

server {
listen 80;
server_name your-elastic-ip your-domain.com;

location = /favicon.ico { access_log off; log_not_found off; }

location /static/ {
alias /home/ubuntu/your-django-project/staticfiles/;
}

location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/your-django-project/myproject.sock;
}
}

Create a symbolic link to enable the site:

bash
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Test the Nginx configuration and restart:

bash
sudo nginx -t
sudo systemctl restart nginx

Step 2: Configure Firewall (Optional)

If you have UFW enabled, allow Nginx and SSH:

bash
sudo ufw allow 'Nginx Full'
sudo ufw allow 'OpenSSH'
sudo ufw enable

Setting Up HTTPS with Let's Encrypt (Optional)

If you have a domain name pointed to your server, you can secure it with Let's Encrypt:

bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com

Follow the prompts to complete the HTTPS configuration.

Automating Deployments with GitHub Actions (Advanced)

For automatic deployments when you push to your Git repository, you can set up GitHub Actions:

  1. Create an SSH key on your EC2 instance:
bash
ssh-keygen -t rsa -b 4096 -C "[email protected]"
  1. Add the public key to ~/.ssh/authorized_keys
  2. Add the private key as a GitHub secret in your repository
  3. Create a GitHub workflow file:
yml
name: Deploy to AWS

on:
push:
branches: [ main ]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd ~/your-django-project
git pull
source ~/myproject/venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
sudo systemctl restart gunicorn

Summary

In this guide, we've covered:

  1. Creating an EC2 instance for hosting your Django application
  2. Setting up a PostgreSQL database with Amazon RDS
  3. Deploying your Django application code
  4. Configuring static files with Amazon S3
  5. Setting up Gunicorn as an application server
  6. Configuring Nginx as a reverse proxy
  7. Securing your site with HTTPS (optional)
  8. Setting up automatic deployments (advanced)

AWS provides a robust platform for Django applications of any size. This setup can handle everything from small personal projects to large-scale applications with thousands of users. As your traffic grows, you can easily scale by:

  • Increasing the size of your EC2 instance
  • Setting up auto-scaling groups
  • Implementing load balancing
  • Adding caching layers like Redis or ElastiCache

Additional Resources

Exercises

  1. Set up a staging environment using a separate EC2 instance with the same configuration.
  2. Configure CloudFront CDN to serve your static files from S3 for improved performance.
  3. Set up regular database backups using AWS RDS automated backup feature.
  4. Implement monitoring for your EC2 instance using AWS CloudWatch.
  5. Set up a CI/CD pipeline using GitHub Actions or AWS CodePipeline to automatically test and deploy your code.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)