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
- Development Environment: US East (N. Virginia) region
- Production Environment: US West (Oregon) region
- Technology Stack: LAMP (Linux, Apache, MySQL, PHP)
- Security: AWS Secrets Manager for sensitive configuration
- 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
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
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
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:
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
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
Create test webpage
echo '<html>Hello from the café web server!</html>' > /var/www/html/index.html
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/
Phase 5: Secrets Manager Configuration
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)
# Set root password and create database
cd ~/environment/db/
./set-root-password.sh
./create-db.sh
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;
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
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
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
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
# 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
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
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"
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."
Final Architecture
With the IAM role properly configured, our architecture includes:
Development Region (us-east-1):
- EC2 instance with CafeRole attached
- Access to Secrets Manager in us-east-1
- Full LAMP stack application
Production Region (us-west-2):
- EC2 instance with same CafeRole attached
- Access to Secrets Manager in us-west-2
- Identical application deployment
Global IAM Infrastructure:
- CafeRole with Secrets Manager permissions
- CafeInstanceProfile for EC2 attachment
- Cross-region consistency in access control
Lessons Learned
- IAM is Critical: Without proper IAM roles, the application cannot access Secrets Manager
- Regional Considerations: AWS resources are region-specific, requiring careful planning
- Security Best Practices: Using Secrets Manager significantly improves security
- 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)