How to Dockerize a Python Django App for AWS EC2 with AWS RDS as the Database and Secure it with HTTPS using Let’s Encrypt
Dockerizing a Python Django application, deploying it on AWS EC2, and securing it with HTTPS using Let’s Encrypt is a robust way to ensure scalability, manageability, and security. This guide will walk you through each step in detail.
Prerequisites
Before starting, ensure you have the following:
AWS Account: Access to the AWS Management Console.
Docker: Installed on your local machine.
AWS CLI: Configured with appropriate permissions.
EC2 Instance: Running with appropriate security groups.
RDS Instance: Configured and running with PostgreSQL (or another preferred database).
Step 1: Setting Up Your Django Project
First, let's create a Django project. If you already have one, you can skip to the next step.
django-admin startproject myproject
cd myproject
Step 2: Writing the Dockerfile
Create a Dockerfile
in your project root directory:
# Use the official Python image from the Docker Hub
FROM python:3.9
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Set the working directory
WORKDIR /app
# Install dependencies
COPY requirements.txt /app/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
# Copy the Django project
COPY . /app/
# Run the application
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "myproject.wsgi:application"]
Step 3: Creating the docker-compose.yml
Create a docker-compose.yml
file to define the services for your application:
version: '3.8'
services:
web:
build: .
command: gunicorn myproject.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:13
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
postgres_data:
Step 4: Configuring Environment Variables
Create a .env
file to store your environment variables:
DEBUG=1
SECRET_KEY=your-secret-key
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] your-ec2-public-dns
SQL_ENGINE=django.db.backends.postgresql
SQL_DATABASE=your-database-name
SQL_USER=your-database-user
SQL_PASSWORD=your-database-password
SQL_HOST=db
SQL_PORT=5432
DATABASE=postgres
Step 5: Updating Django Settings
Modify your Django settings.py
file to use environment variables for database configuration:
import os
import dj_database_url
DATABASES = {
'default': dj_database_url.config(
default=os.environ.get('DATABASE_URL')
)
}
# Update the ALLOWED_HOSTS setting
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS').split(' ')
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
Step 6: Building and Running Docker Containers
Build and run your Docker containers using Docker Compose:
docker-compose up --build
Your Django app should now be running in a Docker container.
Step 7: Preparing for AWS Deployment
Before deploying to AWS, ensure you have created an RDS instance and noted down the endpoint, database name, username, and password.
Step 8: Configuring AWS RDS in Django
Update your .env
file with your AWS RDS details:
SQL_ENGINE=django.db.backends.postgresql
SQL_DATABASE=your-rds-database-name
SQL_USER=your-rds-username
SQL_PASSWORD=your-rds-password
SQL_HOST=your-rds-endpoint
SQL_PORT=5432
Step 9: Deploying to AWS EC2
SSH into your EC2 Instance:
ssh -i path/to/your-key.pem ec2-user@your-ec2-instance-public-dns
Install Docker on EC2:
sudo yum update -y sudo amazon-linux-extras install docker sudo service docker start sudo usermod -a -G docker ec2-user
Clone your project from your repository:
git clone your-repository-url cd your-repository-directory
Transfer environment variables to EC2:
scp -i path/to/your-key.pem .env ec2-user@your-ec2-instance-public-dns:/path/to/your-project
Build and run Docker containers on EC2:
docker-compose up --build -d
Step 10: Configuring Security Groups
Ensure your EC2 instance's security group allows inbound traffic on port 8000 (or your configured port). Similarly, configure your RDS instance's security group to allow traffic from your EC2 instance.
Step 11: Securing the Site with HTTPS using Let’s Encrypt
To secure your site with HTTPS, use Let's Encrypt and Certbot.
Install Certbot on EC2:
sudo amazon-linux-extras install epel sudo yum install -y certbot python2-certbot-nginx
Stop the Docker container temporarily:
docker-compose down
Run Certbot to obtain an SSL certificate:
sudo certbot certonly --standalone -d your-domain-name --preferred-challenges http
Follow the prompts to obtain the certificate. Certbot will generate certificates and place them in
/etc/letsencrypt/live/your-domain-name/
.Create a Dockerfile for Nginx:
Create a new file
nginx/Dockerfile
:FROM nginx:latest COPY nginx.conf /etc/nginx/nginx.conf COPY ssl/ /etc/letsencrypt/live/your-domain-name/
Create Nginx Configuration File:
Create a new file
nginx/nginx.conf
:server { listen 80; server_name your-domain-name; location / { proxy_pass http://web:8000; 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; } location /.well-known/acme-challenge/ { root /var/www/certbot; } } server { listen 443 ssl; server_name your-domain-name; ssl_certificate /etc/letsencrypt/live/your-domain-name/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain-name/privkey.pem; location / { proxy_pass http://web:8000; 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; } }
Update docker-compose.yml:
Update your
docker-compose.yml
to include the Nginx service:version: '3.8' services: web: build: . command: gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 volumes: - .:/app env_file: - .env depends_on: - db db: image: postgres:13 volumes: - postgres_data:/var/lib/postgresql/data/ environment: - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} nginx: build: context: ./nginx volumes: - certbot-etc:/etc/letsencrypt ports: - "80:80" - "443:443" depends_on: - web volumes: postgres_data: certbot-etc:
Build and run your services:
docker-compose up --build -d
Conclusion
By following these steps, you can dockerize your Django application, configure it to use AWS RDS as the database, deploy it on AWS EC2, and secure it with HTTPS. This setup not only simplifies deployment but also ensures your application is scalable, manageable, and secure.