Skip to content

About

A Django application deployed on AWS with high availability, behind an Application Load Balancer, running on an Auto Scaling Group of EC2 instances in private subnets, across two Availability Zones — provisioned entirely with Terraform.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django on AWS — IaC Deployment

A Django application deployed on AWS with high availability, behind an Application Load Balancer, running on an Auto Scaling Group of EC2 instances in private subnets, across two Availability Zones — provisioned entirely with Terraform.

Architecture Diagram

graph TD
    User([User / Browser]) -->|HTTPS:443 / HTTP:80| ALB[Application Load Balancer <br> Public Subnets]
    
    subgraph VPC [AWS VPC Boundary]
        subgraph PublicSubnets [Public Subnets]
            ALB
            NAT[NAT Gateways]
        end
        
        subgraph PrivateSubnets [Private Subnets]
            subgraph ASG [Auto Scaling Group]
                EC2_A[EC2 Instance - AZ A]
                EC2_B[EC2 Instance - AZ B]
            end
            
            RDS[(PostgreSQL Database)]
        end
        
        CW[CloudWatch Logs / Agent]
        S3[Amazon S3 Bucket <br> Encrypted Media Storage]
    end
    
    ALB -->|Forward:8000| EC2_A
    ALB -->|Forward:8000| EC2_B
    
    EC2_A -->|Database connection| RDS
    EC2_B -->|Database connection| RDS
    
    EC2_A -.->|Read/Write Media| S3
    EC2_B -.->|Read/Write Media| S3
    
    EC2_A -.->|Ship logs| CW
    EC2_B -.->|Ship logs| CW
    
    EC2_A -->|Outbound traffic| NAT
    EC2_B -->|Outbound traffic| NAT
    
    NAT -->|Outbound: Pull Docker Image| DockerHub[DockerHub Registry]
    NAT -->|Outbound: Package Updates| Internet[Public Internet]
    
    classDef aws fill:#FF9900,stroke:#333,stroke-width:1px,color:#fff;
    classDef database fill:#336699,stroke:#333,stroke-width:1px,color:#fff;
    classDef external fill:#777777,stroke:#333,stroke-width:1px,color:#fff;
    classDef vpc fill:#e1f5fe,stroke:#0288d1,stroke-width:2px;
    classDef subnet fill:#efebe9,stroke:#5d4037,stroke-width:1px,stroke-dasharray: 5 5;
    
    class ALB,NAT,EC2_A,EC2_B,S3,CW aws;
    class RDS database;
    class DockerHub,Internet,User external;
    class VPC vpc;
    class PublicSubnets,PrivateSubnets,ASG subnet;
Loading

Repository layout

├── .github/workflows/terraform.yml   # CI: terraform validate, django tests, docker build/push
├── images/IACdeploymentDjango.png    # Architecture diagram
├── infra/                            # All Terraform (Infrastructure as Code)
│   ├── modules/                      # Reusable, standalone modules
│   │   ├── vpc/                      # VPC, public/private subnets, IGW, NAT Gateways, routes
│   │   ├── security-groups/          # ALB SG (80/443) and EC2 SG (app port from ALB only)
│   │   ├── alb/                      # Application Load Balancer + target group + listeners
│   │   ├── asg/                      # Launch template + Auto Scaling Group (min1/desired2/max3)
│   │   └── iam/                      # EC2 instance role (SSM + CloudWatch)
│   ├── scripts/
│   │   └── user_data.sh.tpl          # Installs Docker, pulls image from DockerHub, runs it
│   └── environments/
│       └── production/               # Wires all modules together into a deployable stack
│           ├── main.tf
│           ├── variables.tf
│           ├── outputs.tf
│           ├── provider.tf
│           ├── backend.tf
│           └── terraform.tfvars.example
├── django_app/                       # The Django application itself
│   ├── config/
│   │   ├── settings/
│   │   │   ├── base.py               # Shared settings
│   │   │   ├── local.py              # Dev settings (sqlite, DEBUG=True)
│   │   │   └── production.py         # Prod settings (DATABASE_URL, HSTS, secure cookies)
│   │   ├── urls.py
│   │   ├── wsgi.py / asgi.py
│   ├── apps/
│   │   └── core/                     # Health check + home view
│   ├── manage.py
│   ├── requirements.txt / requirements-dev.txt
│   ├── Dockerfile                    # Multi-stage build, gunicorn on port 8000
│   ├── docker-compose.yml            # Local dev: Django + Postgres
│   └── .env.example
└── docs/

How the pieces map to the architecture diagram

Diagram element Terraform resource
VPC (10.0.0.0/16) infra/modules/vpc
Public Subnets AZ1/AZ2 aws_subnet.public in vpc module
Private Subnets AZ1/AZ2 aws_subnet.private in vpc module
NAT Gateway 1 / 2 aws_nat_gateway.this (one per public subnet)
Application Load Balancer infra/modules/alb
ASG (Min 1, Desired 2, Max 3) infra/modules/asg → aws_autoscaling_group.app
EC2 Instances Launch template in asg module, AL2023 AMI
Port Mapping 8000 → 8000 container_port / app_port vars, set in user_data.sh.tpl's docker run -p
Pull django-app (DockerHub) docker pull ${docker_image} in user_data.sh.tpl
Manages / Manages ASG manages EC2 instance lifecycle across both private subnets

Deploying

  1. Push the Django image to DockerHub (CI does this automatically on merge to main, or manually):

    cd django_app
    docker build -t yourdockerhubuser/django-app:latest .
    docker push yourdockerhubuser/django-app:latest
  2. Create remote state resources once (S3 bucket + DynamoDB table), then fill in infra/environments/production/backend.tf.

  3. Configure variables:

    cd infra/environments/production
    cp terraform.tfvars.example terraform.tfvars
    # edit terraform.tfvars: docker_image, region, sizing, etc.
  4. Deploy:

    terraform init
    terraform plan -var="django_secret_key=$(openssl rand -hex 32)" -var="database_url=postgres://..."
    terraform apply -var="django_secret_key=$(openssl rand -hex 32)" -var="database_url=postgres://..."
  5. Terraform outputs alb_dns_name — that's your public URL.

This stack provisions compute/network/load-balancing only. For a managed database, add an RDS module (not included here since it wasn't in the source diagram) and point database_url at it.

Local development

cd django_app
cp .env.example .env
docker compose up --build
# App: http://localhost:8000  Health check: http://localhost:8000/health/

Or without Docker:

cd django_app
python -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
python manage.py migrate
python manage.py runserver

CI/CD

.github/workflows/terraform.yml runs on every push/PR:

  • terraform fmt -check and terraform validate for all infra
  • Django manage.py check and manage.py test
  • On main: builds and pushes the Docker image to DockerHub, ready for the next terraform apply / instance refresh to roll it out.

About

A Django application deployed on AWS with high availability, behind an Application Load Balancer, running on an Auto Scaling Group of EC2 instances in private subnets, across two Availability Zones — provisioned entirely with Terraform.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages