A hands-on project building a production-grade 3-tier Java application on AWS using Auto Scaling, ALB, RDS MySQL with Proxy, Redis caching, and secure networking. The focus is on real-world architecture, security, scalability, and operational best practices rather than demo-level setups.
This article walks through everything I built, step by step, and explains why each component exists.
What We’re Building
At the end of this project, the application looks like this:
User
↓
Route 53
↓
CloudFront
↓
Application Load Balancer
↓
EC2 Auto Scaling Group
↓ ↓
Redis Cache RDS Proxy
↓
RDS MySQL + Read Replica
Technology Stack
- Backend:
Java, Spring Boot - Compute:
EC2 Auto Scaling Group - Networking:
VPC, Subnets, IGW, NAT Gateway - Load Balancing:
Application Load Balancer - Database:
Amazon RDS MySQL + Read Replica - DB Connections:
Amazon RDS Proxy - Secrets:
AWS Secrets Manager (automatic rotation) - Cache:
Amazon ElastiCache (Redis) - Edge:
CloudFront - DNS:
Route 53 - Access:
Bastion Host - Security:
IAM Roles, Security Groups
PHASE 1: NETWORKING (FOUNDATION)
- Create VPC
-
Create Subnets (8 total)
- Public Subnets (2 total)
- Used for Load Balancer, NAT Gateway, Bastion Host
- Private App Subnets (2 total)
- Used for EC2 Auto Scaling Group
- Private DB Subnets (2 total)
- Used for RDS, RDS Proxy, Read Replica
- Private Cache Subnets (2 total)
- Used for Redis (ElastiCache)
- Public Subnets (2 total)
-
Internet Gateway - Allows public subnets to access the internet.
- Create Internet Gateway
- Attach Internet Gateway to VPC
-
NAT Gateway - Private subnets need outbound-only internet access.
- Create a NAT Gateway in public subnet and allocate an elastic IP.
-
Route Tables
- Public Route Table
- Route:
0.0.0.0/0→Internet Gateway - Subnet Associate:
public-a,public-b
- Route:
- Private Route Table
- Route:
0.0.0.0/0→NAT Gateway - Subnet Associate:
private-app-*,private-db-*,private-cache-*
- Route:
- Public Route Table
-
Security Groups
- ALB Security Group (alb-sg)
- Inbound:
80, 443from0.0.0.0/0 - Outbound:
8080toapp-sg
- Inbound:
- Bastion Security Group (bastion-sg)
- Inbound:
SSH (22)from your IP - Outbound:
SSHtoapp-sg
- Inbound:
- App Security Group (app-sg)
- Inbound:
8080fromalb-sg,22frombastion-sg - Outbound:
All
- Inbound:
- DB Security Group (db-sg)
- Inbound:
3306fromapp-sg - Outbound:
Local
- Inbound:
- Redis Security Group (redis-sg)
- Inbound:
6379fromapp-sg - Outbound:
Local
- Inbound:
- ALB Security Group (alb-sg)
PHASE 2: COMPUTE LAYER
- Create a Bastion Host - This is the only SSH entry point.
- Subnet:
public-a - Public IP:
Enabled - SG:
bastion-sg
- Subnet:
- Create an Application Load Balancer
- Type:
Application - Scheme:
Internet-facing - Subnets:
public-a,public-b - SG:
alb-sg
- Type:
- Create a Target Group - ALB routes traffic to target groups, not directly to EC2.
- Target type:
Instance - Port:
8080 - Health check path:
/health
- Target type:
- Create a Launch Template
- AMI:
Ubuntu - Instance type:
t3.micro - SG:
app-sg - IAM Role:
ec2-app-role - User data:
#!/bin/bash sudo apt update -y && sudo apt upgrade -y sudo apt install default-jdk git -y sudo apt install maven -y
- AMI:
- Create an Auto Scaling Group
- Subnets:
private-app-a,private-app-b -
Min: 1|Desired: 2|Max: 3 - Attach ALB target group
- Subnets:
PHASE 3: DATABASE LAYER
- Create DB Subnet Group (RDS must know which private subnets to use) and select private DB subnets.
- Create RDS MySQL database
- Create AWS Secret Manager for DB password and enable autamatic rotation.
- Create Read Replica
- Create RDS Proxy
PHASE 4: REDIS CACHE
- Create Cache Subnet Group and select private cache subnets
- Create Redis Cluster
PHASE 5: Cloudfront & Route53
- Request SSL Certificate
- Create CloudFront Distribution
- Create a hosted zone record
Source Code Link
To run the application:
git clone https://github.com/dipakprasad22/AWS-3tier-Java-Spring-Boot-App.git
mvn clean package
java -Xms256m -Xmx512m -jar app.jar
curl http://localhost:8080/health
http://<ALB-DNS-NAME>/hello

Top comments (0)