# 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 ![image](https://hackmd.io/_uploads/rkC09q5Nge.png) - Application and OS Images (Amazon Machine Image) - Amazon Linux ![image](https://hackmd.io/_uploads/ry_zi9qVel.png) - Amazon Linux 2023 kernel-6.1 AMI (Free tier eligible) ![image](https://hackmd.io/_uploads/HJTIi5q4xe.png) - Network Settings - Create security group (for inbound rule) ![image](https://hackmd.io/_uploads/S1h6oq5Ege.png) - Key pair (login) - proceed without a key pair (for just now) ![image](https://hackmd.io/_uploads/SypRjq94gl.png) - Wait until the status check are passed, and press Connect ![image](https://hackmd.io/_uploads/SkBGhq5Eex.png) ## 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 ![image](https://hackmd.io/_uploads/ByCVoNF4gg.png) #### 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 ![image](https://hackmd.io/_uploads/ByyauVYNxx.png) - Edit inbound rules ![image](https://hackmd.io/_uploads/BJolYNK4gg.png) - Add rule ![image](https://hackmd.io/_uploads/SyBHYEtExg.png) ## 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