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.
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 ID | Resource type |
|---|---|
| Route53route53 | AWS::Route53::HostedZone |
| CloudFrontcloudfront | AWS::CloudFront::Distribution |
| StaticAssetss3 | AWS::S3::Bucket |
| ArchitectdemoVPC10100016vpc | AWS::EC2::VPC |
| ArchitectdemoVPC10100016vpcedgewebsgSecurityGroup | AWS::EC2::SecurityGroup |
| ArchitectdemoVPC10100016vpcappruntimesgSecurityGroup | AWS::EC2::SecurityGroup |
| ArchitectdemoVPC10100016vpcappruntimesgSecurityGroupIngressRule | AWS::EC2::SecurityGroupIngress |
| ArchitectdemoVPC10100016vpcworkersgSecurityGroup | AWS::EC2::SecurityGroup |
| ArchitectdemoVPC10100016vpcdatastoresgSecurityGroup | AWS::EC2::SecurityGroup |
| ArchitectdemoVPC10100016vpcdatastoresgSecurityGroupIngressRule | AWS::EC2::SecurityGroupIngress |
| ArchitectdemoVPC10100016vpccontrolplanesgSecurityGroup | AWS::EC2::SecurityGroup |
| ArchitectdemoVPC10100016vpcPublicSubnet1 | AWS::EC2::Subnet |
| ArchitectdemoVPC10100016vpcPublicSubnet2 | AWS::EC2::Subnet |
| ArchitectdemoVPC10100016vpcPrivateSubnet1 | AWS::EC2::Subnet |
| ArchitectdemoVPC10100016vpcPrivateSubnet2 | AWS::EC2::Subnet |
| ArchitectdemoVPC10100016vpcPrivateSubnet3 | AWS::EC2::Subnet |
| ArchitectdemoVPC10100016vpcPrivateSubnet4 | AWS::EC2::Subnet |
| ArchitectdemoVPC10100016vpcInternetGateway | AWS::EC2::InternetGateway |
| ArchitectdemoVPC10100016vpcGatewayAttachment | AWS::EC2::VPCGatewayAttachment |
| ArchitectdemoVPC10100016vpcPublicRouteTable | AWS::EC2::RouteTable |
| ArchitectdemoVPC10100016vpcPublicRoute | AWS::EC2::Route |
| ArchitectdemoVPC10100016vpcPublicSubnet1RTA | AWS::EC2::SubnetRouteTableAssociation |
| ArchitectdemoVPC10100016vpcPublicSubnet2RTA | AWS::EC2::SubnetRouteTableAssociation |
| ArchitectdemoVPC10100016vpcNatEIP | AWS::EC2::EIP |
| ArchitectdemoVPC10100016vpcNatGateway | AWS::EC2::NatGateway |
| ArchitectdemoVPC10100016vpcPrivateRouteTable | AWS::EC2::RouteTable |
| ArchitectdemoVPC10100016vpcPrivateRoute | AWS::EC2::Route |
| ArchitectdemoVPC10100016vpcPrivateSubnet1RTA | AWS::EC2::SubnetRouteTableAssociation |
| ArchitectdemoVPC10100016vpcPrivateSubnet2RTA | AWS::EC2::SubnetRouteTableAssociation |
| ArchitectdemoVPC10100016vpcPrivateSubnet3RTA | AWS::EC2::SubnetRouteTableAssociation |
| ArchitectdemoVPC10100016vpcPrivateSubnet4RTA | AWS::EC2::SubnetRouteTableAssociation |
| ArchitectdemoVPC10100016vpcDbSubnetGroup | AWS::RDS::DBSubnetGroup |
| PublicALBelb | AWS::ElasticLoadBalancingV2::LoadBalancer |
| AppInstanceec2 | AWS::EC2::Instance |
| PostgreSQLDBrds | AWS::RDS::DBInstance |
| PostgreSQLDBrdsIngressSG | AWS::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
- Twitter/X Scale TestCloudFront behavior split, API Gateway VPC Link, public/internal ALBs, private app/data subnets, queues, media, and data stores
- HA Web AppSAA-C03: CloudFront + WAF → ALB → Auto Scaling EC2 fleet → RDS + ElastiCache
- Multi-Region DRSAA-C03: Route 53 failover → CloudFront → ALB → Auto Scaling EC2 → Aurora Global