Monday, December 8, 2025

CloudFormation + Infrastructure Composer (using WordPress Architecture) | Deep Dive.

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 CloudFormationCommit 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 ASGEFS
  •         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.yaml
Resources:
  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

Amazon EventBridge | Overview.

Amazon EventBridge - Overview. Scope: Intro, Core Concepts, Key Benefits, Link to official documentation, Insights. Intro: Amazon EventBridg...