DEV Community

Mohamed Ammar
Mohamed Ammar

Posted on

Creating a Dynamic Café Website on AWS EC2: A DevOps Journey

In this technical walkthrough, I'll document how I built and deployed a dynamic café website across multiple AWS regions using EC2 instances, Secrets Manager, and a LAMP stack - all configured through AWS CLI and PowerShell.

Project Overview
The goal was to create a scalable web application for a café that can accept online orders, with separate development and production environments in different AWS regions.

Architecture Goals

  1. Development Environment: US East (N. Virginia) region
  2. Production Environment: US West (Oregon) region
  3. Technology Stack: LAMP (Linux, Apache, MySQL, PHP)
  4. Security: AWS Secrets Manager for sensitive configuration
  5. Deployment: Fully automated via AWS CLI

Prerequisites Setup
AWS CLI Configuration
Before starting, I configured AWS CLI with the appropriate credentials:

powershell

# Configure AWS CLI profile
aws configure set aws_access_key_id YOUR_ACCESS_KEY
aws configure set aws_secret_access_key YOUR_SECRET_KEY
aws configure set default.region us-east-1
aws configure set default.output json
Enter fullscreen mode Exit fullscreen mode

Phase 1: IAM Role Creation for Secrets Manager Access
Creating the IAM Role and Policy
powershell

# Create trust policy for EC2
$trustPolicy = @{
    "Version" = "2012-10-17"
    "Statement" = @(
        @{
            "Effect" = "Allow"
            "Principal" = @{
                "Service" = "ec2.amazonaws.com"
            }
            "Action" = "sts:AssumeRole"
        }
    )
} | ConvertTo-Json

$trustPolicy | Out-File -FilePath .\trust-policy.json -Encoding utf8

Enter fullscreen mode Exit fullscreen mode

Create IAM role

aws iam create-role `
    --role-name CafeRole `
    --assume-role-policy-document file://trust-policy.json `
    --description "Role for Cafe EC2 instances to access Secrets Manager"

# Create Secrets Manager policy
$secretsManagerPolicy = @{
    "Version" = "2012-10-17"
    "Statement" = @(
        @{
            "Effect" = "Allow"
            "Action" = @(
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret",
                "secretsmanager:ListSecrets",
                "secretsmanager:CreateSecret",
                "secretsmanager:UpdateSecret"
            )
            "Resource" = "*"
        }
    )
} | ConvertTo-Json

$secretsManagerPolicy | Out-File -FilePath .\secrets-manager-policy.json -Encoding utf8

# Create and attach policy
aws iam create-policy `
    --policy-name CafeSecretsManagerPolicy `
    --policy-document file://secrets-manager-policy.json

aws iam attach-role-policy `
    --role-name CafeRole `
    --policy-arn "arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/CafeSecretsManagerPolicy"

# Create instance profile
aws iam create-instance-profile `
    --instance-profile-name CafeInstanceProfile

aws iam add-role-to-instance-profile `
    --instance-profile-name CafeInstanceProfile `
    --role-name CafeRole
Enter fullscreen mode Exit fullscreen mode

Phase 2: Development Environment Setup
Launching EC2 Instance in US-East-1 with IAM Role
powershell

# Create EC2 instance in us-east-1 with IAM role
aws ec2 run-instances `
    --image-id ami-0c02fb55956c7d316 `
    --instance-type t2.small `
    --key-name CafeKeyPair `
    --security-group-ids sg-cafe `
    --subnet-id subnet-123 `
    --iam-instance-profile Name=CafeInstanceProfile `
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Lab IDE}]' `
    --region us-east-1

# Wait for instance to be running
$instanceId = aws ec2 describe-instances `
    --filters "Name=tag:Name,Values=Lab IDE" `
    --query 'Reservations[0].Instances[0].InstanceId' `
    --output text `
    --region us-east-1

aws ec2 wait instance-running `
    --instance-ids $instanceId `
    --region us-east-1
Connecting via SSH (PuTTY)
Since we're using Windows with PuTTY, convert the key:
Enter fullscreen mode Exit fullscreen mode

powershell

Use PuTTYgen to convert .pem to .ppk

Connect via: ec2-user@ with CafeKeyPair.ppk

Phase 3: LAMP Stack Configuration
Installing and Configuring Apache Web Server
bash

# Update system packages
sudo dnf update -y

# Install Apache (httpd)
sudo dnf install -y httpd

# Configure Apache to listen on port 8000
sudo sed -i 's/Listen 80/Listen 8000/g' /etc/httpd/conf/httpd.conf

# Start and enable Apache
sudo systemctl start httpd
sudo systemctl enable httpd

# Verify Apache status
sudo service httpd status

# Install PHP
sudo dnf install -y php php-mysqli php-json
php --version
Enter fullscreen mode Exit fullscreen mode

Installing and Configuring MariaDB
bash

# Install MariaDB database
sudo dnf install -y mariadb105-server

# Start and enable MariaDB
sudo systemctl start mariadb
sudo systemctl enable mariadb

# Verify installation
sudo mariadb --version
sudo service mariadb status
Setting Up Development Environment
bash
# Create symlink for IDE access
ln -s /var/www/ /home/ec2-user/environment

# Change ownership for web directory
sudo chown ec2-user:ec2-user /var/www/html

Enter fullscreen mode Exit fullscreen mode

Create test webpage

echo '<html>Hello from the café web server!</html>' > /var/www/html/index.html
Enter fullscreen mode Exit fullscreen mode

Phase 4: Application Deployment
Downloading and Extracting Application Files
bash

cd ~/environment

# Download application components
wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACACAD-3-113230/03-lab-mod5-challenge-EC2/s3/setup.zip
wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACACAD-3-113230/03-lab-mod5-challenge-EC2/s3/db.zip
wget https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACACAD-3-113230/03-lab-mod5-challenge-EC2/s3/cafe.zip

# Extract files
unzip setup.zip
unzip db.zip
unzip cafe.zip -d /var/www/html/

# Install AWS SDK for PHP
cd /var/www/html/cafe/
wget https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.zip
wget https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.phar
unzip aws -d /var/www/html/cafe/

# Set appropriate permissions
chmod -R +r /var/www/html/cafe/
Enter fullscreen mode Exit fullscreen mode
Phase 5: Secrets Manager Configuration
Enter fullscreen mode Exit fullscreen mode

Setting Application Parameters
bash

cd ~/environment/setup/
./set-app-parameters.sh
Verifying IAM Role Access
bash
# Test IAM role access
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Verify Secrets Manager access
aws secretsmanager list-secrets --region us-east-1
Phase 6: Database Setup
Configuring MySQL Database
bash
# Get database password from Secrets Manager
DB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id /cafe/dbPassword --region us-east-1 --query SecretString --output text)
Enter fullscreen mode Exit fullscreen mode

# Set root password and create database

cd ~/environment/db/
./set-root-password.sh
./create-db.sh
Enter fullscreen mode Exit fullscreen mode

Database Verification
bash

# Connect to MySQL database
mysql -u admin -p$DB_PASSWORD

# Within MySQL prompt:
show databases;
use cafe_db;
show tables;
select * from product;
exit;
Enter fullscreen mode Exit fullscreen mode

PHP Configuration
bash

# Configure PHP timezone
sudo sed -i "2i date.timezone = \"America/New_York\" " /etc/php.ini

# Restart Apache to apply changes
sudo service httpd restart
Enter fullscreen mode Exit fullscreen mode

Phase 7: Testing the Application
Accessing the Website
The café website should now be accessible at:

http://:8000/cafe

Testing Order Functionality

  • Navigate to the Menu page
  • Select items and submit orders
  • Check Order History to verify order persistence

Phase 8: Creating Production Environment
Preparing for AMI Creation
bash

# Set hostname
sudo hostname cafeserver

# Generate SSH key for future access
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ""

# Add public key to authorized keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
Creating AMI via AWS CLI
Enter fullscreen mode Exit fullscreen mode

powershell

# Create AMI from development instance
aws ec2 create-image `
    --instance-id $instanceId `
    --name "CafeServer" `
    --description "Cafe web server AMI" `
    --region us-east-1

# Wait for AMI to become available
aws ec2 wait image-available `
    --filters "Name=name,Values=CafeServer" `
    --region us-east-1
Enter fullscreen mode Exit fullscreen mode

Launching Production Instance in US-West-2
powershell

# Switch to Oregon region for EC2 operations
aws configure set region us-west-2

# Create security group in Oregon
aws ec2 create-security-group `
    --group-name cafe-sg-oregon `
    --description "Cafe security group for Oregon region" `
    --vpc-id vpc-0zzzzzzzzzz `
    --region us-west-2

$oregonSGId = aws ec2 describe-security-groups `
    --group-names cafe-sg-oregon `
    --query 'SecurityGroups[0].GroupId' `
    --output text `
    --region us-west-2

# Configure security group rules
aws ec2 authorize-security-group-ingress `
    --group-id $oregonSGId `
    --protocol tcp `
    --port 22 `
    --cidr 0.0.0.0/0 `
    --region us-west-2

aws ec2 authorize-security-group-ingress `
    --group-id $oregonSGId `
    --protocol tcp `
    --port 8000 `
    --cidr 0.0.0.0/0 `
    --region us-west-2
Enter fullscreen mode Exit fullscreen mode

# Launch production instance with IAM role

aws ec2 run-instances `
    --image-id ami-0yyyyyyyyyyy `
    --instance-type t2.small `
    --security-group-ids $oregonSGId `
    --subnet-id subnet-0yyyyyyyyyyy `
    --iam-instance-profile Name=CafeInstanceProfile `
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ProdCafeServer}]' `
    --region us-west-2

# Wait for instance to be running
$prodInstanceId = aws ec2 describe-instances `
    --filters "Name=tag:Name,Values=ProdCafeServer" `
    --query 'Reservations[0].Instances[0].InstanceId' `
    --output text `
    --region us-west-2

aws ec2 wait instance-running `
    --instance-ids $prodInstanceId `
    --region us-west-2
Enter fullscreen mode Exit fullscreen mode

Phase 9: Configuring Production Secrets
Creating Secrets in Oregon Region
bash

# On development instance, create Oregon region secrets
cd ~/environment/setup/

# Create modified script for Oregon
cat > set-app-parameters-oregon.sh << 'EOF'
#!/bin/bash
region="us-west-2"

publicDNS=$(aws ec2 describe-instances \
    --filters "Name=tag:Name,Values=ProdCafeServer" \
    --query 'Reservations[0].Instances[0].PublicDnsName' \
    --output text \
    --region $region)

# Create secrets in Oregon region
aws secretsmanager create-secret \
    --name /cafe/dbPassword \
    --description "Database password for cafe application" \
    --secret-string "dbPassword123" \
    --region $region

aws secretsmanager create-secret \
    --name /cafe/dbName \
    --description "Database name for cafe application" \
    --secret-string "cafe_db" \
    --region $region

echo "Secrets created successfully in $region"
EOF

chmod +x set-app-parameters-oregon.sh
./set-app-parameters-oregon.sh
Enter fullscreen mode Exit fullscreen mode

Phase 10: Production Verification
Testing Production Environment
bash

# Get production instance public IP
PROD_IP=$(aws ec2 describe-instances `
    --instance-ids $prodInstanceId `
    --query 'Reservations[0].Instances[0].PublicIpAddress' `
    --output text `
    --region us-west-2)

echo "Production site URL: http://$PROD_IP:8000/cafe"
Enter fullscreen mode Exit fullscreen mode

IAM Role Verification Script
bash

#!/bin/bash
# iam-role-test.sh

echo "Testing IAM Role Configuration..."
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
aws sts get-caller-identity
aws secretsmanager list-secrets --max-items 5
echo "IAM Role test completed."
Enter fullscreen mode Exit fullscreen mode

Final Architecture
With the IAM role properly configured, our architecture includes:

Development Region (us-east-1):

  1. EC2 instance with CafeRole attached
  2. Access to Secrets Manager in us-east-1
  3. Full LAMP stack application

Production Region (us-west-2):

  1. EC2 instance with same CafeRole attached
  2. Access to Secrets Manager in us-west-2
  3. Identical application deployment

Global IAM Infrastructure:

  1. CafeRole with Secrets Manager permissions
  2. CafeInstanceProfile for EC2 attachment
  3. Cross-region consistency in access control

Lessons Learned

  1. IAM is Critical: Without proper IAM roles, the application cannot access Secrets Manager
  2. Regional Considerations: AWS resources are region-specific, requiring careful planning
  3. Security Best Practices: Using Secrets Manager significantly improves security
  4. Automation Benefits: AWS CLI commands enable reproducible deployments

Conclusion
This project successfully demonstrated a complete DevOps workflow for deploying a dynamic web application across multiple AWS regions. The café now has a robust, scalable ordering system with proper IAM role configuration for secure Secrets Manager access, ensuring both development and production environments function correctly.

The entire infrastructure can be recreated programmatically using the AWS CLI commands and scripts documented in this post.

Top comments (0)