TheArchitect

3-Tier Web App

AWS architecture template · CDN → Load Balancer → EC2 → RDS + S3

3-Tier Web App is a free AWS architecture template built with CloudFront, EC2, Load Balancer, RDS, Route 53 and S3. Open it in TheArchitect to edit the diagram, estimate monthly cost, and export the CloudFormation or Terraform that deploys it.

Public edge subnets A/BPrivate app subnets A/BPrivate data subnets A/BArchitect demo VPC 10.10.0.0/16Route 53CloudFrontStatic AssetsPublic ALBApp InstancePostgreSQL DB
3-Tier Web App architecture diagram

AWS services in this template

  • CloudFront
  • EC2
  • Load Balancer
  • RDS
  • Route 53
  • S3

Deployment notes

Deploy-ready

  • Uses the shared demo VPC, private app/data subnets, managed DB password, and generated EC2 AMI reference.

Generated CloudFormation — 36 resources

Logical IDResource type
Route53route53AWS::Route53::HostedZone
CloudFrontcloudfrontAWS::CloudFront::Distribution
StaticAssetss3AWS::S3::Bucket
ArchitectdemoVPC10100016vpcAWS::EC2::VPC
ArchitectdemoVPC10100016vpcedgewebsgSecurityGroupAWS::EC2::SecurityGroup
ArchitectdemoVPC10100016vpcappruntimesgSecurityGroupAWS::EC2::SecurityGroup
ArchitectdemoVPC10100016vpcappruntimesgSecurityGroupIngressRuleAWS::EC2::SecurityGroupIngress
ArchitectdemoVPC10100016vpcworkersgSecurityGroupAWS::EC2::SecurityGroup
ArchitectdemoVPC10100016vpcdatastoresgSecurityGroupAWS::EC2::SecurityGroup
ArchitectdemoVPC10100016vpcdatastoresgSecurityGroupIngressRuleAWS::EC2::SecurityGroupIngress
ArchitectdemoVPC10100016vpccontrolplanesgSecurityGroupAWS::EC2::SecurityGroup
ArchitectdemoVPC10100016vpcPublicSubnet1AWS::EC2::Subnet
ArchitectdemoVPC10100016vpcPublicSubnet2AWS::EC2::Subnet
ArchitectdemoVPC10100016vpcPrivateSubnet1AWS::EC2::Subnet
ArchitectdemoVPC10100016vpcPrivateSubnet2AWS::EC2::Subnet
ArchitectdemoVPC10100016vpcPrivateSubnet3AWS::EC2::Subnet
ArchitectdemoVPC10100016vpcPrivateSubnet4AWS::EC2::Subnet
ArchitectdemoVPC10100016vpcInternetGatewayAWS::EC2::InternetGateway
ArchitectdemoVPC10100016vpcGatewayAttachmentAWS::EC2::VPCGatewayAttachment
ArchitectdemoVPC10100016vpcPublicRouteTableAWS::EC2::RouteTable
ArchitectdemoVPC10100016vpcPublicRouteAWS::EC2::Route
ArchitectdemoVPC10100016vpcPublicSubnet1RTAAWS::EC2::SubnetRouteTableAssociation
ArchitectdemoVPC10100016vpcPublicSubnet2RTAAWS::EC2::SubnetRouteTableAssociation
ArchitectdemoVPC10100016vpcNatEIPAWS::EC2::EIP
ArchitectdemoVPC10100016vpcNatGatewayAWS::EC2::NatGateway
ArchitectdemoVPC10100016vpcPrivateRouteTableAWS::EC2::RouteTable
ArchitectdemoVPC10100016vpcPrivateRouteAWS::EC2::Route
ArchitectdemoVPC10100016vpcPrivateSubnet1RTAAWS::EC2::SubnetRouteTableAssociation
ArchitectdemoVPC10100016vpcPrivateSubnet2RTAAWS::EC2::SubnetRouteTableAssociation
ArchitectdemoVPC10100016vpcPrivateSubnet3RTAAWS::EC2::SubnetRouteTableAssociation
ArchitectdemoVPC10100016vpcPrivateSubnet4RTAAWS::EC2::SubnetRouteTableAssociation
ArchitectdemoVPC10100016vpcDbSubnetGroupAWS::RDS::DBSubnetGroup
PublicALBelbAWS::ElasticLoadBalancingV2::LoadBalancer
AppInstanceec2AWS::EC2::Instance
PostgreSQLDBrdsAWS::RDS::DBInstance
PostgreSQLDBrdsIngressSGAWS::EC2::SecurityGroup
View the full CloudFormation template
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
  "Metadata": {
    "TheArchitect": {
      "Edges": [
        {
          "From": "CloudFrontcloudfront",
          "To": "PublicALBelb"
        },
        {
          "From": "AppInstanceec2",
          "To": "PostgreSQLDBrds",
          "Label": "SQL"
        },
        {
          "From": "AppInstanceec2",
          "To": "StaticAssetss3",
          "Label": "static"
        }
      ]
    }
  },
  "Resources": {
    "Route53route53": {
      "Type": "AWS::Route53::HostedZone",
      "Properties": {
        "Name": "demo.example.com.",
        "HostedZoneConfig": {
          "Comment": "Public hosted zone for the demo web application."
        }
      }
    },
    "CloudFrontcloudfront": {
      "Type": "AWS::CloudFront::Distribution",
      "Properties": {
        "DistributionConfig": {
          "Enabled": true,
          "Comment": "CDN for the demo web application.",
          "DefaultRootObject": "index.html",
          "PriceClass": "PriceClass_100",
          "HttpVersion": "http2",
          "DefaultCacheBehavior": {
            "TargetOriginId": "LoadBalancerOrigin",
            "ViewerProtocolPolicy": "redirect-to-https",
            "ForwardedValues": {
              "QueryString": false,
              "Cookies": {
                "Forward": "none"
              }
            }
          },
          "ViewerCertificate": {
            "CloudFrontDefaultCertificate": true
          },
          "Origins": [
            {
              "DomainName": {
                "Fn::GetAtt": [
                  "PublicALBelb",
                  "DNSName"
                ]
              },
              "Id": "LoadBalancerOrigin",
              "CustomOriginConfig": {
                "HTTPPort": 80,
                "HTTPSPort": 443,
                "OriginProtocolPolicy": "http-only",
                "OriginSSLProtocols": [
                  "TLSv1.2"
                ]
              }
            }
          ]
        }
      }
    },
    "StaticAssetss3": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": "architect-demo-assets",
        "VersioningConfiguration": {
          "Status": "Enabled"
        },
        "OwnershipControls": {
          "Rules": [
            {
              "ObjectOwnership": "BucketOwnerEnforced"
            }
          ]
        },
        "BucketEncryption": {
          "ServerSideEncryptionConfiguration": [
            {
              "ServerSideEncryptionByDefault": {
                "SSEAlgorithm": "AES256"
              }
            }
          ]
        },
        "PublicAccessBlockConfiguration": {
          "BlockPublicAcls": true,
          "BlockPublicPolicy": true,
          "IgnorePublicAcls": true,
          "RestrictPublicBuckets": true
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-assets"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpc": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "CidrBlock": "10.10.0.0/16",
        "EnableDnsHostnames": true,
        "EnableDnsSupport": true,
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-vpc"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcedgewebsgSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "edge-web-sg",
        "GroupDescription": "Allow HTTPS from the internet to public load balancers",
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "edge-web-sg"
          }
        ],
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": 443,
            "ToPort": 443,
            "CidrIp": "0.0.0.0/0"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcappruntimesgSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "app-runtime-sg",
        "GroupDescription": "Allow application traffic from the edge tier",
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "app-runtime-sg"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcappruntimesgSecurityGroupIngressRule": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties": {
        "GroupId": {
          "Ref": "ArchitectdemoVPC10100016vpcappruntimesgSecurityGroup"
        },
        "IpProtocol": "tcp",
        "FromPort": 80,
        "ToPort": 80,
        "SourceSecurityGroupId": {
          "Ref": "ArchitectdemoVPC10100016vpcedgewebsgSecurityGroup"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcworkersgSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "worker-sg",
        "GroupDescription": "Private worker runtime egress only",
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "worker-sg"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcdatastoresgSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "data-store-sg",
        "GroupDescription": "Allow PostgreSQL from application runtimes",
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "data-store-sg"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcdatastoresgSecurityGroupIngressRule": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties": {
        "GroupId": {
          "Ref": "ArchitectdemoVPC10100016vpcdatastoresgSecurityGroup"
        },
        "IpProtocol": "tcp",
        "FromPort": 5432,
        "ToPort": 5432,
        "SourceSecurityGroupId": {
          "Ref": "ArchitectdemoVPC10100016vpcappruntimesgSecurityGroup"
        }
      }
    },
    "ArchitectdemoVPC10100016vpccontrolplanesgSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupName": "control-plane-sg",
        "GroupDescription": "Private EKS control plane attachment group",
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "control-plane-sg"
          }
        ],
        "SecurityGroupEgress": [
          {
            "IpProtocol": "-1",
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPublicSubnet1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "CidrBlock": "10.10.1.0/24",
        "AvailabilityZone": "us-east-1a",
        "MapPublicIpOnLaunch": true,
        "Tags": [
          {
            "Key": "Name",
            "Value": "public-edge-a"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPublicSubnet2": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "CidrBlock": "10.10.2.0/24",
        "AvailabilityZone": "us-east-1b",
        "MapPublicIpOnLaunch": true,
        "Tags": [
          {
            "Key": "Name",
            "Value": "public-edge-b"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet1": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "CidrBlock": "10.10.11.0/24",
        "AvailabilityZone": "us-east-1a",
        "MapPublicIpOnLaunch": false,
        "Tags": [
          {
            "Key": "Name",
            "Value": "private-app-a"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet2": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "CidrBlock": "10.10.12.0/24",
        "AvailabilityZone": "us-east-1b",
        "MapPublicIpOnLaunch": false,
        "Tags": [
          {
            "Key": "Name",
            "Value": "private-app-b"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet3": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "CidrBlock": "10.10.21.0/24",
        "AvailabilityZone": "us-east-1a",
        "MapPublicIpOnLaunch": false,
        "Tags": [
          {
            "Key": "Name",
            "Value": "private-data-a"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet4": {
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "CidrBlock": "10.10.22.0/24",
        "AvailabilityZone": "us-east-1b",
        "MapPublicIpOnLaunch": false,
        "Tags": [
          {
            "Key": "Name",
            "Value": "private-data-b"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcInternetGateway": {
      "Type": "AWS::EC2::InternetGateway",
      "Properties": {
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-vpc-igw"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcGatewayAttachment": {
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "InternetGatewayId": {
          "Ref": "ArchitectdemoVPC10100016vpcInternetGateway"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPublicRouteTable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-vpc-public-rt"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPublicRoute": {
      "Type": "AWS::EC2::Route",
      "DependsOn": [
        "ArchitectdemoVPC10100016vpcGatewayAttachment"
      ],
      "Properties": {
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPublicRouteTable"
        },
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId": {
          "Ref": "ArchitectdemoVPC10100016vpcInternetGateway"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPublicSubnet1RTA": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPublicSubnet1"
        },
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPublicRouteTable"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPublicSubnet2RTA": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPublicSubnet2"
        },
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPublicRouteTable"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcNatEIP": {
      "Type": "AWS::EC2::EIP",
      "DependsOn": [
        "ArchitectdemoVPC10100016vpcGatewayAttachment"
      ],
      "Properties": {
        "Domain": "vpc"
      }
    },
    "ArchitectdemoVPC10100016vpcNatGateway": {
      "Type": "AWS::EC2::NatGateway",
      "Properties": {
        "AllocationId": {
          "Fn::GetAtt": [
            "ArchitectdemoVPC10100016vpcNatEIP",
            "AllocationId"
          ]
        },
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPublicSubnet1"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-vpc-nat"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateRouteTable": {
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-vpc-private-rt"
          }
        ]
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateRoute": {
      "Type": "AWS::EC2::Route",
      "Properties": {
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateRouteTable"
        },
        "DestinationCidrBlock": "0.0.0.0/0",
        "NatGatewayId": {
          "Ref": "ArchitectdemoVPC10100016vpcNatGateway"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet1RTA": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet1"
        },
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateRouteTable"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet2RTA": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet2"
        },
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateRouteTable"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet3RTA": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet3"
        },
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateRouteTable"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcPrivateSubnet4RTA": {
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet4"
        },
        "RouteTableId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateRouteTable"
        }
      }
    },
    "ArchitectdemoVPC10100016vpcDbSubnetGroup": {
      "Type": "AWS::RDS::DBSubnetGroup",
      "Properties": {
        "DBSubnetGroupDescription": "Private subnets for architect-demo-vpc",
        "SubnetIds": [
          {
            "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet1"
          },
          {
            "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet2"
          },
          {
            "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet3"
          },
          {
            "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet4"
          }
        ],
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-vpc-db-subnet-group"
          }
        ]
      }
    },
    "PublicALBelb": {
      "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties": {
        "Name": "architect-demo-web-alb",
        "Type": "application",
        "Scheme": "internet-facing",
        "IpAddressType": "ipv4",
        "Subnets": [
          {
            "Ref": "ArchitectdemoVPC10100016vpcPublicSubnet1"
          },
          {
            "Ref": "ArchitectdemoVPC10100016vpcPublicSubnet2"
          }
        ],
        "SecurityGroups": [
          {
            "Ref": "ArchitectdemoVPC10100016vpcedgewebsgSecurityGroup"
          }
        ]
      }
    },
    "AppInstanceec2": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}",
        "InstanceType": "t3.micro",
        "Tags": [
          {
            "Key": "Name",
            "Value": "architect-demo-app"
          }
        ],
        "SubnetId": {
          "Ref": "ArchitectdemoVPC10100016vpcPrivateSubnet1"
        },
        "SecurityGroupIds": [
          {
            "Ref": "ArchitectdemoVPC10100016vpcappruntimesgSecurityGroup"
          }
        ],
        "MetadataOptions": {
          "HttpTokens": "required"
        },
        "UserData": {
          "Fn::Base64": "#!/bin/bash\nyum update -y\nyum install -y nginx\nsystemctl enable nginx\nsystemctl start nginx"
        }
      }
    },
    "PostgreSQLDBrds": {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "DBInstanceIdentifier": "architect-demo-appdb",
        "Engine": "postgres",
        "DBName": "appdb",
        "DBInstanceClass": "db.t4g.micro",
        "DBSubnetGroupName": {
          "Ref": "ArchitectdemoVPC10100016vpcDbSubnetGroup"
        },
        "VPCSecurityGroups": [
          {
            "Ref": "ArchitectdemoVPC10100016vpcdatastoresgSecurityGroup"
          },
          {
            "Ref": "PostgreSQLDBrdsIngressSG"
          }
        ],
        "PubliclyAccessible": false,
        "AllocatedStorage": "20",
        "MaxAllocatedStorage": 100,
        "StorageType": "gp3",
        "MasterUsername": "appadmin",
        "ManageMasterUserPassword": true,
        "StorageEncrypted": true,
        "BackupRetentionPeriod": 7
      }
    },
    "PostgreSQLDBrdsIngressSG": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": "Allow connected compute to RDS postgres on port 5432",
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": 5432,
            "ToPort": 5432,
            "SourceSecurityGroupId": {
              "Ref": "ArchitectdemoVPC10100016vpcappruntimesgSecurityGroup"
            }
          }
        ],
        "VpcId": {
          "Ref": "ArchitectdemoVPC10100016vpc"
        }
      }
    }
  }
}

Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.

Related templates