A deep-dive, end-to-end guide on AWS CloudFormation + AWS Infrastructure
Composer using a
WordPress architecture as the working example.
Focus:
- Aonceptual
explanation,
- Architecture
patterns,
- YAML
- Snippets,
- Best
practices,
- CI/CD
integrations.
Breakdown:
- WordPress Architecture,
- The concept AWS Infrastructure Composer,
- Why Combine CloudFormation + Infrastructure Composer,
- WordPress on AWS (CloudFormation + Composer Architecture),
- How to Build this in Infrastructure Composer,
- Production-Grade CloudFormation Blueprint,
- Deployment Workflow (CloudFormation Stack),
- Advantages of Using Infrastructure Composer for
WordPress,
- Deployment Workflow (CloudFormation Stack),
CloudFormation
+ Infrastructure Composer
– Deep Dive (Using WordPress Architecture)
1. The concept AWS Infrastructure Composer
AWS Infrastructure Composer
is a visual builder for Infrastructure-as-Code (IaC) that
allows twtech to:
- Drag-and-drop AWS services
- Visually design relationships (networking,
security, dependencies)
- Export the final design as CloudFormation templates
- Integrate with IaC pipelines (CDK/CloudFormation/SAM)
NB:
- WordPress Architecture helps reduce
errors by showing validated architecture components, compatible configs, and
best-practice wiring.
2. Why Combine CloudFormation + Infrastructure Composer
|
Feature |
CloudFormation |
Infrastructure
Composer |
Combined
Value |
|
IaC |
Declarative YAML/JSON |
Visual
designer |
Faster + easier IaC authoring |
|
Error
prevention |
Template validation |
UI
compatibility guidance |
Lower risk |
|
Architecture |
Text-based logical blocks |
Drag-and-drop
diagrams |
Visual clarity |
|
Modularity |
Nested & reusable stacks |
Blueprint
generation |
Production-ready reusable patterns |
|
Automation |
CI/CD & drift detection |
Git-integrated |
End-to-end automation |
NB the Result:
twtech visually design:
- Composer →
Export CloudFormation → Commit →
Deploy automatically.
3. WordPress on AWS (CloudFormation
+ Composer Architecture)
- A typical high-availability WordPress deployment includes:
Core Components
- Amazon EC2 Auto Scaling Group (WordPress
web tier)
- Amazon RDS MySQL (database tier)
- Amazon EFS (shared file system for wp-content)
- Elastic Load Balancer (public entry point)
- VPC + subnets + NAT gateways
- Security groups
- S3 bucket for Media Offload (optional)
- CloudFront (optional)
Diagram – WordPress Architecture Built Using Composer (layout):
4. How to Build This in Infrastructure Composer
Step-by-Step
Blueprint
Step
1: Start a new design
- Open Infrastructure Composer in AWS console
- Choose “Blank Project”
- Select Region and Framework: CloudFormation
Step
2: Drag-and-drop components
twtech adds:
- VPC (Composer auto-generates subnets & routing options)
- Internet Gateway + NAT Gateways
- EC2 Auto Scaling Group
- RDS (MySQL/Aurora)
- EFS File System
- Elastic Load Balancer
- IAM roles
- S3 bucket (optional)
- CloudFront (optional)
Composer automatically:
- Creates SG
connections
- Maps subnets
- Ensures
best-practice architecture
Step
3: Connect the components
Example:
- Connect ALB → ASG
- Connect ASG → EFS
- Connect
WordPress EC2 role → S3
- Connect Web
tier SG → DB SG → RDS
Composer automatically:
- Creates
dependency order
- Inserts
required CFN resources
- Validates
configuration
Step
4: Export the CloudFormation template
Click:
Export
→ CloudFormation YAML
NB:
This gives twtech a
ready-to-deploy
IaC template.
5. Production-Grade CloudFormation Blueprint (WordPress)
- Below is a high-level YAML excerpt (simplified for readability):
# CloudFormatiion-blueprint-wordPress.yamlResources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 PublicSubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: true ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Subnets: - !Ref PublicSubnetA FileSystem: Type: AWS::EFS::FileSystem WordPressLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateData: ImageId: ami-xxxxxxxx UserData: !Base64 | #!/bin/bash yum install -y amazon-efs-utils mkdir /var/www/html/wp-content mount -t efs ${FileSystem}.efs.${AWS::Region}.amazonaws.com:/ /var/www/html/wp-content WordPressASG: Type: AWS::AutoScaling::AutoScalingGroup Properties: MinSize: 2 MaxSize: 5 DesiredCapacity: 2 LaunchTemplate: LaunchTemplateId: !Ref WordPressLaunchTemplate Version: !GetAtt WordPressLaunchTemplate.LatestVersionNumber WordPressDB: Type: AWS::RDS::DBInstance Properties: Engine: mysql DBInstanceClass: db.t3.micro AllocatedStorage: 20 MasterUsername: twtech MasterUserPassword: twtechsuperpassword# Done:
The real template (from
Composer) would include:
- All
subnets
- Route
tables
- Security
groups
- ALB
target groups
- EFS
mount targets
- IAM
roles
- Auto
scaling policies
- Outputs
& parameters
- Dependencies
NB:
- If twtech wants, I can generate a full
production template (350–600 lines).
6. Deployment Workflow (CloudFormation
Stack)
Option
1: Manual
1.
Upload YAML into CloudFormation console
2.
Provide parameters (DB password,
keypair)
3.
Deploy the stack
4.
Access the ALB DNS to launch WordPress
Option
2: CI/CD Pipeline
Using
CodePipeline + GitHub/CodeCommit:
Pipeline stages:
1.
Source: Git
repository
2.
Build/Lint: cfn-lint,
cfn-nag
3.
Deploy: CloudFormation
create/update stack
4.
Post Deployment: Smoke tests
7. Advantages of Using Infrastructure Composer for
WordPress
1.
Visual Architecture
- Non-experts
can understand the design instantly
- Auto-validated
connections minimize mistakes
2.
Auto-Generated CloudFormation
- Fast IaC generation
- Reduces YAML
complexity
- Ensures
relationships & dependencies
3.
Reusability
- Use blueprint
to create dozens of WordPress environments
- Easily
modify: dev → test →
prod
4.
Cost & Resilience Recommendations
Composer UI flags:
- Missing best
practices
- Redundant
components
- Sizing
recommendations
5.
Perfect for DevOps & Cloud Engineers
- Great for
workshops
- Fast
prototyping
- Excellent for
drift detection & IaC pipelines
8. Add-Ons for a Production WordPress Architecture
Add the
following if needed:
- Amazon ElastiCache (Redis) → WordPress Object Caching
- Amazon S3 + CloudFront → Offload Media
- ALB + WAF + Shield Advanced
- Amazon Backup (RDS/EFS)
- Secrets Manager
(WP DB password)
- AWS Auto Scaling scheduled scaling
- CloudWatch Alarms + Dashboard
Insights:
A
complete Infrastructure Composer blueprint
# WordPress-CloudFormation.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: >-
Infrastructure Composer style CloudFormation template for a
highly-available
WordPress
deployment. 2 AZs, ALB, AutoScaling group, EFS for wp-content,
RDS MySQL,
S3 for media offload, and IAM roles. Parametrized and
production-ready blueprint (tweak sizes and AMIs for your environment).
Parameters:
VpcCidr:
Type:
String
Default: 10.0.0.0/16
Description: CIDR block for the VPC
PublicSubnetACidr:
Type:
String
Default: 10.0.1.0/24
PublicSubnetBCidr:
Type:
String
Default: 10.0.2.0/24
PrivateSubnetACidr:
Type:
String
Default: 10.0.11.0/24
PrivateSubnetBCidr:
Type:
String
Default: 10.0.12.0/24
KeyName:
Type:
AWS::EC2::KeyPair::twtechKeyName
Description:
EC2 KeyPair for SSH
access
InstanceType:
Type:
String
Default: t3.medium
Description: EC2
instance type for WordPress web servers
DesiredCapacity:
Type:
Number
Default: 2
Description:
Desired capacity for ASG
MinSize:
Type:
Number
Default: 2
MaxSize:
Type:
Number
Default: 4
DBUsername:
Type:
String
Default: wpadmin
MinLength:
1
DBPassword:
Type:
String
NoEcho:
true
MinLength:
8
Description:
RDS master user password
DBAllocatedStorage:
Type:
Number
Default: 20
Description: Allocated
storage (GB) for
RDS
UseMultiAZDB:
Type:
String
AllowedValues: ["true","false"]
Default:
"true"
Mappings:
AWSRegionToAMI:
us-east-1:
AMI:
ami-0c94855ba95xxxx
us-east-2:
AMI:
ami-0b59bfac6be0xxxx
us-west-2:
AMI:
ami-04b9e92b5572xxxx
Resources:
# VPC and Networking
VPC:
Type:
AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key:
Name
Value: !Sub "wordpress-vpc-${AWS::StackName}"
InternetGateway:
Type:
AWS::EC2::InternetGateway
Properties:
Tags:
- Key:
Name
Value:
!Sub "igw-${AWS::StackName}"
VPCGatewayAttachment:
Type:
AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
!Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnetA:
Type:
AWS::EC2::Subnet
Properties:
VpcId:
!Ref VPC
CidrBlock: !Ref PublicSubnetACidr
AvailabilityZone: !Select [0, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key:
Name
Value: !Sub "public-a-${AWS::StackName}"
PublicSubnetB:
Type:
AWS::EC2::Subnet
Properties:
VpcId:
!Ref VPC
CidrBlock: !Ref PublicSubnetBCidr
AvailabilityZone: !Select [1, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key:
Name
Value: !Sub "public-b-${AWS::StackName}"
PrivateSubnetA:
Type:
AWS::EC2::Subnet
Properties:
VpcId:
!Ref VPC
CidrBlock: !Ref PrivateSubnetACidr
AvailabilityZone: !Select [0, !GetAZs ""]
MapPublicIpOnLaunch: false
Tags:
- Key:
Name
Value: !Sub "private-a-${AWS::StackName}"
PrivateSubnetB:
Type:
AWS::EC2::Subnet
Properties:
VpcId:
!Ref VPC
CidrBlock: !Ref PrivateSubnetBCidr
AvailabilityZone: !Select [1, !GetAZs ""]
MapPublicIpOnLaunch: false
Tags:
- Key:
Name
Value: !Sub "private-b-${AWS::StackName}"
PublicRouteTable:
Type:
AWS::EC2::RouteTable
Properties:
VpcId:
!Ref VPC
Tags:
- Key:
Name
Value: !Sub "public-rt-${AWS::StackName}"
PublicRoute:
Type:
AWS::EC2::Route
DependsOn:
VPCGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
!Ref InternetGateway
PublicSubnetARouteTableAssociation:
Type:
AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId:
!Ref PublicRouteTable
PublicSubnetBRouteTableAssociation:
Type:
AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetB
RouteTableId:
!Ref PublicRouteTable
EIPNatA:
Type:
AWS::EC2::EIP
Properties:
Domain:
vpc
NATGatewayA:
Type:
AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIPNatA.AllocationId
SubnetId: !Ref PublicSubnetA
Tags:
- Key:
Name
Value: !Sub "nat-a-${AWS::StackName}"
EIPNatB:
Type:
AWS::EC2::EIP
Properties:
Domain:
vpc
NATGatewayB:
Type:
AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIPNatB.AllocationId
SubnetId: !Ref PublicSubnetB
Tags:
- Key:
Name
Value: !Sub "nat-b-${AWS::StackName}"
PrivateRouteTableA:
Type:
AWS::EC2::RouteTable
Properties:
VpcId:
!Ref VPC
Tags:
- Key:
Name
Value: !Sub "private-a-rt-${AWS::StackName}"
PrivateRouteA:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableA
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGatewayA
PrivateSubnetARouteTableAssociation:
Type:
AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId:
!Ref PrivateRouteTableA
PrivateRouteTableB:
Type:
AWS::EC2::RouteTable
Properties:
VpcId:
!Ref VPC
Tags:
- Key:
Name
Value: !Sub "private-b-rt-${AWS::StackName}"
PrivateRouteB:
Type:
AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTableB
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGatewayB
PrivateSubnetBRouteTableAssociation:
Type:
AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetB
RouteTableId:
!Ref PrivateRouteTableB
# Security Groups
ALBSecurityGroup:
Type:
AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP/HTTPS from
internet to ALB
VpcId:
!Ref VPC
SecurityGroupIngress:
-
IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
-
IpProtocol:
tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
WebSecurityGroup:
Type:
AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow traffic from ALB and outbound to internet
VpcId:
!Ref VPC
SecurityGroupIngress:
-
IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
SecurityGroupEgress:
-
IpProtocol: -1
FromPort: 0
ToPort: 65535
CidrIp: 0.0.0.0/0
DatabaseSecurityGroup:
Type:
AWS::EC2::SecurityGroup
Properties:
GroupDescription: MySQL
access from web servers
VpcId:
!Ref VPC
SecurityGroupIngress:
-
IpProtocol:
tcp
FromPort: 3306
ToPort: 3306
SourceSecurityGroupId: !Ref WebSecurityGroup
EFSSecurityGroup:
Type:
AWS::EC2::SecurityGroup
Properties:
GroupDescription: EFS
mount points
VpcId: !Ref VPC
SecurityGroupIngress:
-
IpProtocol: tcp
FromPort:
2049
ToPort: 2049
SourceSecurityGroupId: !Ref
WebSecurityGroup
# Load Balancer and Target Group
ApplicationLoadBalancer:
Type:
AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub
"alb-${AWS::StackName}"
Subnets:
- !Ref
PublicSubnetA
- !Ref
PublicSubnetB
SecurityGroups:
- !Ref
ALBSecurityGroup
Scheme:
internet-facing
ALBTargetGroup:
Type:
AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name:
!Sub "tg-${AWS::StackName}"
Port: 80
Protocol: HTTP
VpcId: !Ref VPC
HealthCheckProtocol: HTTP
HealthCheckPath: /
TargetType: instance
ALBListener:
Type:
AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref
ApplicationLoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
-
Type: forward
TargetGroupArn:
!Ref ALBTargetGroup
# IAM Role and Profile for EC2
EC2InstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
-
sts:AssumeRole
Path: /
ManagedPolicyArns:
-
arn:aws:iam::aws:policy/AmazonS3FullAccess
-
arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
EC2InstanceProfile:
Type:
AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref
EC2InstanceRole
# EFS
EFSFileSystem:
Type:
AWS::EFS::FileSystem
Properties:
Encrypted: true
PerformanceMode: generalPurpose
FileSystemTags:
- Key:
Name
Value: !Sub "efs-wp-${AWS::StackName}"
EFSMountTargetA:
Type:
AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref
EFSFileSystem
SubnetId: !Ref PrivateSubnetA
SecurityGroups:
- !Ref
EFSSecurityGroup
EFSMountTargetB:
Type:
AWS::EFS::MountTarget
Properties:
FileSystemId: !Ref
EFSFileSystem
SubnetId: !Ref PrivateSubnetB
SecurityGroups:
- !Ref
EFSSecurityGroup
# Launch Template (for ASG)
WordPressLaunchTemplate:
Type:
AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
ImageId: !FindInMap [AWSRegionToAMI, !Ref "AWS::Region", AMI]
InstanceType: !Ref
InstanceType
KeyName: !Ref
KeyName
IamInstanceProfile:
Name: !Ref EC2InstanceProfile
SecurityGroupIds:
-
!Ref WebSecurityGroup
UserData: !Base64
|
#!/bin/bash -xe
yum
update -y
amazon-linux-extras install -y php7.4
yum
install -y httpd php-mysqlnd
systemctl enable httpd
systemctl start httpd
# Install EFS utils & mount
yum
install -y amazon-efs-utils
mkdir -p /var/www/html/wp-content
mount -t efs -o tls ${EFS_ID}:/ /var/www/html/wp-content || true
# Set permissions
chown -R ec2-user:ec2-user /var/www/html/wp-content
# Fetch and install WordPress if
not present
if [
! -f /var/www/html/index.php ]; then
curl -o /tmp/wp.tar.gz https://wordpress.org/latest.tar.gz
tar -xzf /tmp/wp.tar.gz -C /tmp
rsync -a /tmp/wordpress/ /var/www/html/
chown -R ec2-user:ec2-user /var/www/html
fi
#
Replace placeholder DB config (CloudFormation will provide values via metadata)
cat
> /var/www/html/wp-config.php <<'WP'
<?php
define('DB_NAME', '${DBName}');
define('DB_USER', '${DBUser}');
define('DB_PASSWORD', '${DBPassword}');
define('DB_HOST', '${DBEndpoint}');
WP
WordPressASG:
Type:
AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
- !Ref
PrivateSubnetA
- !Ref
PrivateSubnetB
MinSize:
!Ref MinSize
MaxSize:
!Ref MaxSize
DesiredCapacity: !Ref
DesiredCapacity
LaunchTemplate:
LaunchTemplateId: !Ref
WordPressLaunchTemplate
Version: !GetAtt
WordPressLaunchTemplate.LatestVersionNumber
TargetGroupARNs:
- !Ref
ALBTargetGroup
Tags:
- Key: Name
Value: !Sub
"wp-asg-${AWS::StackName}"
PropagateAtLaunch:
true
# RDS MySQL
WordPressDBSubnetGroup:
Type:
AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: Subnet group for WordPress RDS
SubnetIds:
- !Ref
PrivateSubnetA
- !Ref
PrivateSubnetB
WordPressDB:
Type:
AWS::RDS::DBInstance
Properties:
AllocatedStorage: !Ref
DBAllocatedStorage
DBInstanceClass: db.t3.medium
Engine: mysql
EngineVersion: '8.0'
MasterUsername: !Ref
DBUsername
MasterUserPassword: !Ref
DBPassword
DBSubnetGroupName: !Ref
WordPressDBSubnetGroup
VPCSecurityGroups:
- !Ref
DatabaseSecurityGroup
MultiAZ:
!Equals [!Ref UseMultiAZDB,
"true"]
PubliclyAccessible: false
StorageEncrypted: true
BackupRetentionPeriod: 7
# S3 bucket for media offload
WordPressMediaBucket:
Type:
AWS::S3::Bucket
Properties:
BucketName: !Sub
"wp-media-${AWS::AccountId}-${AWS::Region}-${AWS::StackName}"
VersioningConfiguration:
Status: Enabled
# CloudWatch Log Group (for web logs)
WebLogGroup:
Type:
AWS::Logs::LogGroup
Properties:
RetentionInDays: 14
# Outputs
Outputs:
LoadBalancerDNS:
Description: DNS name for the load balancer
Value:
!GetAtt ApplicationLoadBalancer.DNSName
RDS_Endpoint:
Description: RDS
endpoint
Value: !GetAtt WordPressDB.Endpoint.Address
EFS_Id:
Description: EFS
FileSystem Id
Value: !Ref EFSFileSystem
S3BucketName:
Description: S3
bucket for media
Value: !Ref WordPressMediaBucket
VPCId:
Description: VPC
Id
Value: !Ref VPC
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Network
Configuration"
Parameters:
-
VpcCidr
-
PublicSubnetACidr
-
PublicSubnetBCidr
-
PrivateSubnetACidr
-
PrivateSubnetBCidr
- Label:
default: "EC2 Configuration"
Parameters:
-
KeyName
-
InstanceType
-
MinSize
-
DesiredCapacity
-
MaxSize
- Label:
default: "Database"
Parameters:
-
DBUsername
-
DBPassword
-
DBAllocatedStorage
# Done
No comments:
Post a Comment