# 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:

1. **AWS Account**: Access to the AWS Management Console.
    
2. **Docker**: Installed on your local machine.
    
3. **AWS CLI**: Configured with appropriate permissions.
    
4. **EC2 Instance**: Running with appropriate security groups.
    
5. **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.

```bash
django-admin startproject myproject
cd myproject
```

### Step 2: Writing the Dockerfile

Create a `Dockerfile` in your project root directory:

```bash
# 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:

```bash
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:

```bash
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`](http://settings.py) file to use environment variables for database configuration:

```bash
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:

```bash
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:

```bash
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

1. **SSH into your EC2 Instance**:
    
    ```bash
    ssh -i path/to/your-key.pem ec2-user@your-ec2-instance-public-dns
    ```
    
2. **Install Docker on EC2**:
    
    ```bash
    sudo yum update -y
    sudo amazon-linux-extras install docker
    sudo service docker start
    sudo usermod -a -G docker ec2-user
    ```
    
3. **Clone your project from your repository**:
    
    ```bash
    git clone your-repository-url
    cd your-repository-directory
    ```
    
4. **Transfer environment variables to EC2**:
    
    ```bash
    scp -i path/to/your-key.pem .env ec2-user@your-ec2-instance-public-dns:/path/to/your-project
    ```
    
5. **Build and run Docker containers on EC2**:
    
    ```bash
    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.

1. **Install Certbot on EC2**:
    
    ```bash
    sudo amazon-linux-extras install epel
    sudo yum install -y certbot python2-certbot-nginx
    ```
    
2. **Stop the Docker container temporarily**:
    
    ```bash
    docker-compose down
    ```
    
3. **Run Certbot to obtain an SSL certificate**:
    
    ```bash
    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/`.
    
4. **Create a Dockerfile for Nginx**:
    
    Create a new file `nginx/Dockerfile`:
    
    ```bash
    FROM nginx:latest
    
    COPY nginx.conf /etc/nginx/nginx.conf
    COPY ssl/ /etc/letsencrypt/live/your-domain-name/
    ```
    
5. **Create Nginx Configuration File**:
    
    Create a new file `nginx/nginx.conf`:
    
    ```bash
    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;
        }
    }
    ```
    
6. **Update docker-compose.yml**:
    
    Update your `docker-compose.yml` to include the Nginx service:
    
    ```bash
    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:
    ```
    
7. **Build and run your services**:
    
    ```bash
    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.
