A secure, scalable, and highly available cloud environment designed to host a public web application across multiple Availability Zones, utilizing a decoupled two-tier architecture.
Fig 1. Two-Tier Cloud Architecture Diagram
When designing the Virtual Private Cloud (VPC), subnet sizing was carefully planned to balance efficiency, scalability, and security. We adhered to the "Rule of Thirds," ensuring sufficient IP address capacity for immediate needs while allowing room for growth and unexpected expansion.
We allocated large subnets first for optimal efficiency, keeping in mind that AWS reserves 5 IP addresses per subnet. Crucially, sizing was dictated by the tier's function:
- Public Subnets: Kept smaller to minimize the potential attack surface.
- Application (EC2) Private Subnets: Allocated the largest blocks to accommodate dynamic horizontal scaling handled by the Auto Scaling Group.
- Database Private Subnets: Sized smaller, as databases typically rely more on vertical scaling rather than horizontal expansion.
To ensure fault tolerance and handle traffic spikes, the web tier is fully decoupled. We deployed an Application Load Balancer (ALB) across two public subnets, which securely distributes incoming HTTP/HTTPS traffic to our private application instances.
The backend EC2 instances are managed by an Auto Scaling Group (ASG). Using target tracking scaling policies, the infrastructure automatically provisions new instances when the average request count per target exceeds a threshold, and terminates them when traffic subsides. To make this "self-healing," I engineered a robust User Data script that automatically installs the PHP environment and syncs the latest application files from an S3 bucket upon boot.
Fig 2. User Data Script for Automated Instance Configuration
A critical piece of the networking puzzle was bridging the gap between our AWS infrastructure and the end user gracefully. Rather than exposing the autogenerated, cumbersome AWS Load Balancer URL, I leveraged Cloudflare's DNS management to attach our custom domain.
By configuring a CNAME record to point our subdomain
(egl211.rirori.xyz) directly to the Load Balancer, we
established a clean, professional entry point. This setup not only
improved the user experience but also allowed us to funnel all
incoming traffic through Cloudflare's edge network for SSL
termination and traffic proxying.
My responsibilities also included engineering the storage architecture. We utilized Amazon S3 for durable, highly available object storage to handle user file uploads. However, decoupling the storage from the compute instances introduced a significant technical hurdle: cross-origin security blocks.
Initially, direct file uploads from the web application failed
silently. Because the application was being served via our custom
Cloudflare domain, the web browser blocked cross-origin requests
to the native AWS S3 endpoint. To resolve this, I had to dive deep
into S3 permissions and architect a strict Cross-Origin Resource
Sharing (CORS) policy. This policy explicitly allowed
PUT and POST methods exclusively from
https://egl211.rirori.xyz.
I paired this CORS configuration with a tightly scoped Bucket
Policy on our storage bucket
(grp2-prod-webapp-uploads-s3), ensuring the principle
of least privilege by explicitly defining allowed actions such as
s3:PutObject and s3:GetObject.
Figs 3-4. Securing S3 with Strict Bucket & CORS Policies
A major focus of this project was securing the perimeter. Following the principle of least privilege, I restricted the Load Balancer's security group to only allow traffic from Cloudflare's verified IP ranges. This hides the AWS infrastructure from the open internet and mitigates direct DDoS attacks.
To protect sensitive S3 upload and download functionalities without hardcoding authentication into the backend, I implemented Cloudflare Zero Trust. By setting up an identity-aware proxy, every user is forced to authenticate against a specific GitHub organization before their traffic is even routed to the internal AWS Load Balancer.
Figs 5-6. Custom DNS & Identity-Aware Proxy Configuration
Because the application and database servers sit inside private subnets without public IPs, direct SSH access is impossible. We deployed a Bastion host in the public subnet to act as a secure jump box.
Instead of leaving sensitive private key files sitting on the
Bastion host (a major security risk if the host is compromised), I
utilized SSH Agent Forwarding (ssh -A). This protocol
allows the local machine's SSH agent to seamlessly authenticate
the connection from the Bastion into the private EC2 instances,
ensuring the private key never leaves my local device.
Furthermore, we hardened the Bastion by installing Fail2ban to
immediately ban IPs attempting brute-force attacks.
Fig 7. Agent Forwarding through the Bastion Host
Serving as the Group Leader for this deployment was a massive exercise in coordination and architectural planning.
Managing a distributed system taught me that consistency is the foundation of security. Moving from manual configurations to automated deployments through the ALB and User Data scripts completely changed how I view infrastructure reliability.
A major technical hurdle I encountered was "session drift." Because the web application initially used local file-based PHP sessions, users frequently got logged out when the Load Balancer routed their subsequent requests to a different EC2 instance. This was a critical architectural lesson: true horizontal scaling requires statelessness. If I were to rebuild this architecture, I would implement a centralized session management system to store session data in a central "Source of Truth" like Redis (ElastiCache) or the RDS database.
Beyond the technical architecture, this project reinforced that team coordination is rarely straightforward. As reflected in the final documentation, compiling our report required me to take ownership of the overall structure, standardizing the styling and formatting across all team members' disparate contributions, and meticulously managing all figure references. It was a practical lesson in how clear communication and consistent documentation standards are just as critical to a successful deployment as the infrastructure itself.