# Deploy Django App on AWS EC2 Instance with docker and nginx
This guide explains how to deploy a Django web app to AWS EC2 using Docker, Nginx, and DuckDNS (free dynamic DNS).
⭐ **If you found this helpful, please give the repo a star!**
## Required
`Check out my github repo` [Github/MichaelYang84](https://github.com/MichaelYang84/CS50-FinalProject)
```
project-root/
├── docker-compose.yml
├── Dockerfile
├── .env
├── nginx.conf
├── app/
│ ├── manage.py
│ ├── ... (your Django app files)
```
## EC2 Launch Instance

- Application and OS Images (Amazon Machine Image)
- Amazon Linux

- Amazon Linux 2023 kernel-6.1 AMI (Free tier eligible)

- Network Settings
- Create security group (for inbound rule)

- Key pair (login)
- proceed without a key pair (for just now)

- Wait until the status check are passed, and press Connect

## Deploy on Instance
#### Install package
###### git | docker | docker-compose
```bash
sudo yum upgrade
sudo yum install -y git docker
# check version
git --version
docker --version
# add docker group to omit sudo everytime
sudo usermod -aG docker $USER
newgrp docker
# test docker
docker run hello-world
```
```bash
# Amazon Linux does not have docker-compose-plugin in YUM repository
# Create Docker plugin path
sudo mkdir -p /usr/local/lib/docker/cli-plugins
# Download docker compose plugin
curl -SL https://github.com/docker/compose/releases/download/v2.27.1/docker-compose-linux-x86_64 -o docker-compose
# Authorize exec permission
chmod +x docker-compose
# move to plugins folder
sudo mv docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
docker compose --version
```
#### Match instance public IP to Duckdns domain
- Copy your Public IP to register on Duckdns

#### Clone project & Set .env file & Activate Container
You can use my GitHub repo at the top ⬆️
```bash
git clone <url>
# Add .env file to the root folder
cd <Project>
nano .env
# paste your env variable
# ctrl + O, enter (save) ctrl + X (leave)
docker compose up -d
```
- .env
```
DJANGO_SECRET_KEY=<your django key>
DJANGO_DEBUG=FALSE
DJANGO_ALLOWED_HOSTS=<domain name>
```
- Create your own secret key
```bash
python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'
```
## Setting Inbound rules on Security Group
- Click Security Group from the instance

- Edit inbound rules

- Add rule

## Network Flow
🌐 User enters:`http://<sub domain>.duckdns.org` in their browser
🔽 DuckDNS resolves the domain to the EC2 public IP (e.g., `13.115.87.21`)
🔽 EC2 Security Group allows Inbound traffic on port 80(HTTP, where Nginx listens)
🔽 External request reached the EC2 instance → received by the Nginx container running via Docker Compose(Nginx is listening on port 80)
🔽 Nginx matches the `server_name` with `<sub domain>.duckdns.org` in Nginx config
🔽 Nginx config:
```
proxy_pass http://web:8000;
```
The request is forwarded to the Docker service named `web` on port 8000
🔽 The `web` services is Gunicorn Django app, which is listening on 0.0.0.0:8000 inside the container (Gunicorn open 0.0.0.0:8000 in docker container)
🔽 Gunicorn processes the request and returns the HTML or data response
🔼 The response flows back through Nginx, then back to user's browser