Building a Scalable Web Application on AWS: A Step-by-Step Guide
In this comprehensive guide, we'll walk through building an end-to-end scalable web application on AWS, leveraging a robust set of services to host a PHP-based "Guestbook" application. This project demonstrates how to utilize AWS's infrastructure for scalability, reliability, and efficiency, all configured via the AWS Management Console in the us-east-1 region. Whether you're a cloud beginner or a seasoned developer, this hands-on tutorial will help you understand AWS architecture in action.
Project Overview
The Guestbook app allows users to submit and view messages, stored in a MySQL database, with static assets in Amazon S3, shared storage via Amazon EFS, and metadata caching in DynamoDB. The application is hosted on EC2 instances, scaled via an Auto Scaling Group (ASG), and fronted by an Application Load Balancer (ALB). Here's the architecture:
Step-by-Step Implementation
Step 1: Set Up Amazon RDS MySQL Database
RDS provides a managed MySQL database for reliable message storage.
Why? RDS ensures a scalable, managed database separate from compute resources.
Step 2: Create DynamoDB Table for Caching
DynamoDB caches metadata like message counts to reduce RDS load.
Why? DynamoDB's NoSQL capabilities offer fast reads for frequently accessed metadata.
Step 3: Set Up S3 Bucket for App Code and Static Files
S3 stores PHP code and static assets like CSS, with versioning and event notifications enabled.
Example index.php (simplified):
<?php
$host = 'guestbook-db.xxxxx.us-east-1.rds.amazonaws.com'; // Replace with RDS endpoint
$user = 'admin';
$pass = 'SecurePass123!'; // Replace with your password
$db = 'guestbook';
$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) die("Connection failed: " . $conn->connect_error);
// Create table
$conn->query("CREATE TABLE IF NOT EXISTS messages (id INT AUTO_INCREMENT PRIMARY KEY, message TEXT, timestamp TIMESTAMP)");
// DynamoDB integration
require 'vendor/autoload.php';
use Aws\DynamoDb\DynamoDbClient;
$dynamodb = new DynamoDbClient(['region' => 'us-east-1', 'version' => 'latest']);
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$message = $_POST['message'];
$conn->query("INSERT INTO messages (message) VALUES ('$message')");
$dynamodb->putItem([
'TableName' => 'guestbook-metadata',
'Item' => ['key' => ['S' => 'message_count'], 'value' => ['N' => (string)getMessageCount($conn)]]
]);
}
// Function to get message count
function getMessageCount($conn) {
global $dynamodb;
try {
$result = $dynamodb->getItem(['TableName' => 'guestbook-metadata', 'Key' => ['key' => ['S' => 'message_count']]]);
if (isset($result['Item'])) return (int)$result['Item']['value']['N'];
} catch (Exception $e) {}
$result = $conn->query("SELECT COUNT(*) as count FROM messages");
return $result->fetch_assoc()['count'];
}
// Display UI
echo "<html><head><link rel='stylesheet' href='styles.css'></head><body>";
echo "<h1>Guestbook</h1><p>Total messages: " . getMessageCount($conn) . "</p>";
echo "<form method='post'><input name='message' placeholder='Enter message'><button>Submit</button></form>";
$result = $conn->query("SELECT * FROM messages ORDER BY timestamp DESC");
while ($row = $result->fetch_assoc()) echo "<p>" . $row['message'] . " (" . $row['timestamp'] . ")</p>";
echo "</body></html>";
$conn->close();
?>
Example styles.css:
body { font-family: Arial; background: #f0f0f0; }
h1 { color: blue; }
Why? S3 is cost-effective for static content and app code distribution.
Step 4: Configure Amazon EFS for Shared Storage
EFS enables shared storage across EC2 instances for logs or uploads.
Why? EFS ensures consistent file access across scaled instances.
Step 5: Launch and Configure EC2 Instance
EC2 hosts the PHP app, tested as a template for scaling.
#!/bin/bash
yum update -y
amazon-linux-extras install php8.0 -y
yum install httpd php-mysqlnd php-dom git -y
systemctl start httpd
systemctl enable httpd
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
mkdir /var/www/html/vendor
cd /var/www/html
composer require aws/aws-sdk-php
aws s3 cp s3://guestbook-app-bucket/index.php /var/www/html/index.php
aws s3 cp s3://guestbook-app-bucket/styles.css /var/www/html/styles.css
chown -R apache:apache /var/www/html
yum install amazon-efs-utils -y
mkdir /mnt/efs
mount -t efs fs-xxxxxxxx:/ /mnt/efs # Replace with EFS ID
echo "fs-xxxxxxxx:/ /mnt/efs efs defaults,_netdev 0 0" >> /etc/fstab
Why? EC2 provides the compute power for the web application.
Step 6: Create AMI for Scaling
An AMI ensures consistent instance launches in the ASG.
Step 7: Set Up Auto Scaling Group (ASG)
ASG scales EC2 instances based on demand.
Why? ASG ensures the app scales dynamically with load.
Step 8: Configure Application Load Balancer (ALB)
ALB distributes traffic across instances.
Why? ALB ensures high availability and load distribution.
Step 9: Test the Application
Why? Testing confirms end-to-end functionality and scalability.
Step 10: Clean Up
To avoid costs and respect sandbox limits:
Key Takeaways
This project showcases AWS's power in building scalable, reliable web applications. By integrating RDS, DynamoDB, S3, EFS, EC2, Auto Scaling, and ALB, you create a robust system that handles dynamic workloads efficiently. Practice these steps in the AWS Console to deepen your cloud expertise!