Highly Available Multi-Tier Web Application on AWS
A single-server PHP and MySQL application re-architected into three tiers across two Availability Zones, with private subnets, Secrets Manager and auto scaling.
- When
- January 2026
- Context
- Personal project
- Role
- Solo build
- Amazon VPC
- EC2
- RDS MySQL
- Application Load Balancer
- Auto Scaling
- Secrets Manager
- Systems Manager
The problem
A single-server application is one failure away from an outage, and it keeps its database credentials and its database on the same public box.
Loads from YouTube when you press play. Watch on YouTube.
Network
- A custom VPC on 10.0.0.0/16 spanning two Availability Zones.
- Public subnets carry only the load balancer and NAT. The web and data tiers sit in private subnets with no inbound route from the internet.
- Security groups chain rather than open: the load balancer reaches the web tier, and only the web tier reaches the database.
Application tier
- EC2 User Data bootstraps the LAMP stack and the application on first boot, so an instance joins the fleet with no manual step.
- The load balancer health check hits /health.html, so a half-booted instance never takes traffic.
- An Auto Scaling group with CPU target tracking adds and removes instances without intervention.
Data and access
- RDS MySQL in isolated subnets, with credentials held in AWS Secrets Manager instead of a config file.
- Administrative access runs through SSM Session Manager, so there is no SSH port and no key material to lose.
Decisions
- Session Manager instead of a bastion host
- It removes an internet-facing instance, the SSH port and the key rotation problem, and every session is logged.
- Secrets Manager instead of environment files
- The credential never lands in the AMI, the repository or the User Data script.
The result
- Losing an instance, or an entire Availability Zone, no longer takes the application down.
- The database is unreachable from the internet, and no credential is stored on disk.
Keep reading