HA Web App
AWS architecture template · SAA-C03: CloudFront + WAF → ALB → Auto Scaling EC2 fleet → RDS + ElastiCache
HA Web App is a free AWS architecture template built with Auto Scaling, CloudFront, EC2, ElastiCache, Load Balancer, RDS and WAF. 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
- Auto Scaling
- CloudFront
- EC2
- ElastiCache
- Load Balancer
- RDS
- WAF
Deployment notes
Needs input
- Add a Launch Template ID to the Auto Scaling group before deployment.
- Uses demo VPC, private subnets, and managed RDS password.
Generated CloudFormation — 39 resources
| Logical ID | Resource type |
|---|---|
| WAFwaf | AWS::WAFv2::WebACL |
| CloudFrontcloudfront | AWS::CloudFront::Distribution |
| HAWebAppVPC10100016vpc | AWS::EC2::VPC |
| HAWebAppVPC10100016vpcedgewebsgSecurityGroup | AWS::EC2::SecurityGroup |
| HAWebAppVPC10100016vpcappruntimesgSecurityGroup | AWS::EC2::SecurityGroup |
| HAWebAppVPC10100016vpcappruntimesgSecurityGroupIngressRule | AWS::EC2::SecurityGroupIngress |
| HAWebAppVPC10100016vpcworkersgSecurityGroup | AWS::EC2::SecurityGroup |
| HAWebAppVPC10100016vpcdatastoresgSecurityGroup | AWS::EC2::SecurityGroup |
| HAWebAppVPC10100016vpcdatastoresgSecurityGroupIngressRule | AWS::EC2::SecurityGroupIngress |
| HAWebAppVPC10100016vpccontrolplanesgSecurityGroup | AWS::EC2::SecurityGroup |
| HAWebAppVPC10100016vpcPublicSubnet1 | AWS::EC2::Subnet |
| HAWebAppVPC10100016vpcPublicSubnet2 | AWS::EC2::Subnet |
| HAWebAppVPC10100016vpcPrivateSubnet1 | AWS::EC2::Subnet |
| HAWebAppVPC10100016vpcPrivateSubnet2 | AWS::EC2::Subnet |
| HAWebAppVPC10100016vpcPrivateSubnet3 | AWS::EC2::Subnet |
| HAWebAppVPC10100016vpcPrivateSubnet4 | AWS::EC2::Subnet |
| HAWebAppVPC10100016vpcInternetGateway | AWS::EC2::InternetGateway |
| HAWebAppVPC10100016vpcGatewayAttachment | AWS::EC2::VPCGatewayAttachment |
| HAWebAppVPC10100016vpcPublicRouteTable | AWS::EC2::RouteTable |
| HAWebAppVPC10100016vpcPublicRoute | AWS::EC2::Route |
| HAWebAppVPC10100016vpcPublicSubnet1RTA | AWS::EC2::SubnetRouteTableAssociation |
| HAWebAppVPC10100016vpcPublicSubnet2RTA | AWS::EC2::SubnetRouteTableAssociation |
| HAWebAppVPC10100016vpcNatEIP | AWS::EC2::EIP |
| HAWebAppVPC10100016vpcNatGateway | AWS::EC2::NatGateway |
| HAWebAppVPC10100016vpcPrivateRouteTable | AWS::EC2::RouteTable |
| HAWebAppVPC10100016vpcPrivateRoute | AWS::EC2::Route |
| HAWebAppVPC10100016vpcPrivateSubnet1RTA | AWS::EC2::SubnetRouteTableAssociation |
| HAWebAppVPC10100016vpcPrivateSubnet2RTA | AWS::EC2::SubnetRouteTableAssociation |
| HAWebAppVPC10100016vpcPrivateSubnet3RTA | AWS::EC2::SubnetRouteTableAssociation |
| HAWebAppVPC10100016vpcPrivateSubnet4RTA | AWS::EC2::SubnetRouteTableAssociation |
| HAWebAppVPC10100016vpcDbSubnetGroup | AWS::RDS::DBSubnetGroup |
| HAWebAppVPC10100016vpcCacheSubnetGroup | AWS::ElastiCache::SubnetGroup |
| PublicALBelb | AWS::ElasticLoadBalancingV2::LoadBalancer |
| WebASGautoscaling | AWS::AutoScaling::AutoScalingGroup |
| WebInstanceec2 | AWS::EC2::Instance |
| PostgreSQLDBrds | AWS::RDS::DBInstance |
| RedisCacheelasticache | AWS::ElastiCache::CacheCluster |
| PostgreSQLDBrdsIngressSG | AWS::EC2::SecurityGroup |
| RedisCacheelasticacheIngressSG | AWS::EC2::SecurityGroup |
View the full CloudFormation template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
"Metadata": {
"TheArchitect": {
"Edges": [
{
"From": "WAFwaf",
"To": "CloudFrontcloudfront",
"Label": "protect"
},
{
"From": "CloudFrontcloudfront",
"To": "PublicALBelb"
},
{
"From": "PublicALBelb",
"To": "WebASGautoscaling"
},
{
"From": "WebInstanceec2",
"To": "PostgreSQLDBrds",
"Label": "SQL"
},
{
"From": "WebInstanceec2",
"To": "RedisCacheelasticache",
"Label": "cache"
}
]
}
},
"Resources": {
"WAFwaf": {
"Type": "AWS::WAFv2::WebACL",
"Properties": {
"Name": "saa-ha-web-acl",
"Scope": "CLOUDFRONT",
"DefaultAction": {
"Allow": {}
},
"VisibilityConfig": {
"CloudWatchMetricsEnabled": true,
"MetricName": "SaaHaWebACL",
"SampledRequestsEnabled": true
},
"Description": "WAF protecting the CloudFront distribution."
}
},
"CloudFrontcloudfront": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"Enabled": true,
"Comment": "CDN for the HA 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"
]
}
}
]
}
}
},
"HAWebAppVPC10100016vpc": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.10.0.0/16",
"EnableDnsHostnames": true,
"EnableDnsSupport": true,
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc"
}
]
}
},
"HAWebAppVPC10100016vpcedgewebsgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "edge-web-sg",
"GroupDescription": "Allow HTTPS from the internet to public load balancers",
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"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"
}
]
}
},
"HAWebAppVPC10100016vpcappruntimesgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "app-runtime-sg",
"GroupDescription": "Allow application traffic from the edge tier",
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "app-runtime-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"HAWebAppVPC10100016vpcappruntimesgSecurityGroupIngressRule": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "HAWebAppVPC10100016vpcappruntimesgSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": 80,
"ToPort": 80,
"SourceSecurityGroupId": {
"Ref": "HAWebAppVPC10100016vpcedgewebsgSecurityGroup"
}
}
},
"HAWebAppVPC10100016vpcworkersgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "worker-sg",
"GroupDescription": "Private worker runtime egress only",
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "worker-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"HAWebAppVPC10100016vpcdatastoresgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "data-store-sg",
"GroupDescription": "Allow PostgreSQL from application runtimes",
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "data-store-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"HAWebAppVPC10100016vpcdatastoresgSecurityGroupIngressRule": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "HAWebAppVPC10100016vpcdatastoresgSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": 5432,
"ToPort": 5432,
"SourceSecurityGroupId": {
"Ref": "HAWebAppVPC10100016vpcappruntimesgSecurityGroup"
}
}
},
"HAWebAppVPC10100016vpccontrolplanesgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "control-plane-sg",
"GroupDescription": "Private EKS control plane attachment group",
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "control-plane-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"HAWebAppVPC10100016vpcPublicSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"CidrBlock": "10.10.1.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": true,
"Tags": [
{
"Key": "Name",
"Value": "public-edge-a"
}
]
}
},
"HAWebAppVPC10100016vpcPublicSubnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"CidrBlock": "10.10.2.0/24",
"AvailabilityZone": "us-east-1b",
"MapPublicIpOnLaunch": true,
"Tags": [
{
"Key": "Name",
"Value": "public-edge-b"
}
]
}
},
"HAWebAppVPC10100016vpcPrivateSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"CidrBlock": "10.10.11.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-app-a"
}
]
}
},
"HAWebAppVPC10100016vpcPrivateSubnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"CidrBlock": "10.10.12.0/24",
"AvailabilityZone": "us-east-1b",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-app-b"
}
]
}
},
"HAWebAppVPC10100016vpcPrivateSubnet3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"CidrBlock": "10.10.21.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-data-a"
}
]
}
},
"HAWebAppVPC10100016vpcPrivateSubnet4": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"CidrBlock": "10.10.22.0/24",
"AvailabilityZone": "us-east-1b",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-data-b"
}
]
}
},
"HAWebAppVPC10100016vpcInternetGateway": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc-igw"
}
]
}
},
"HAWebAppVPC10100016vpcGatewayAttachment": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"InternetGatewayId": {
"Ref": "HAWebAppVPC10100016vpcInternetGateway"
}
}
},
"HAWebAppVPC10100016vpcPublicRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc-public-rt"
}
]
}
},
"HAWebAppVPC10100016vpcPublicRoute": {
"Type": "AWS::EC2::Route",
"DependsOn": [
"HAWebAppVPC10100016vpcGatewayAttachment"
],
"Properties": {
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPublicRouteTable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "HAWebAppVPC10100016vpcInternetGateway"
}
}
},
"HAWebAppVPC10100016vpcPublicSubnet1RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPublicSubnet1"
},
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPublicRouteTable"
}
}
},
"HAWebAppVPC10100016vpcPublicSubnet2RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPublicSubnet2"
},
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPublicRouteTable"
}
}
},
"HAWebAppVPC10100016vpcNatEIP": {
"Type": "AWS::EC2::EIP",
"DependsOn": [
"HAWebAppVPC10100016vpcGatewayAttachment"
],
"Properties": {
"Domain": "vpc"
}
},
"HAWebAppVPC10100016vpcNatGateway": {
"Type": "AWS::EC2::NatGateway",
"Properties": {
"AllocationId": {
"Fn::GetAtt": [
"HAWebAppVPC10100016vpcNatEIP",
"AllocationId"
]
},
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPublicSubnet1"
},
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc-nat"
}
]
}
},
"HAWebAppVPC10100016vpcPrivateRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc-private-rt"
}
]
}
},
"HAWebAppVPC10100016vpcPrivateRoute": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPrivateRouteTable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"NatGatewayId": {
"Ref": "HAWebAppVPC10100016vpcNatGateway"
}
}
},
"HAWebAppVPC10100016vpcPrivateSubnet1RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet1"
},
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPrivateRouteTable"
}
}
},
"HAWebAppVPC10100016vpcPrivateSubnet2RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet2"
},
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPrivateRouteTable"
}
}
},
"HAWebAppVPC10100016vpcPrivateSubnet3RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet3"
},
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPrivateRouteTable"
}
}
},
"HAWebAppVPC10100016vpcPrivateSubnet4RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet4"
},
"RouteTableId": {
"Ref": "HAWebAppVPC10100016vpcPrivateRouteTable"
}
}
},
"HAWebAppVPC10100016vpcDbSubnetGroup": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"DBSubnetGroupDescription": "Private subnets for saa-ha-vpc",
"SubnetIds": [
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet1"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet2"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet3"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet4"
}
],
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc-db-subnet-group"
}
]
}
},
"HAWebAppVPC10100016vpcCacheSubnetGroup": {
"Type": "AWS::ElastiCache::SubnetGroup",
"Properties": {
"Description": "Private subnets for saa-ha-vpc",
"SubnetIds": [
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet1"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet2"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet3"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet4"
}
],
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-vpc-cache-subnet-group"
}
]
}
},
"PublicALBelb": {
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"Properties": {
"Name": "saa-ha-web-alb",
"Type": "application",
"Scheme": "internet-facing",
"IpAddressType": "ipv4",
"Subnets": [
{
"Ref": "HAWebAppVPC10100016vpcPublicSubnet1"
},
{
"Ref": "HAWebAppVPC10100016vpcPublicSubnet2"
}
],
"SecurityGroups": [
{
"Ref": "HAWebAppVPC10100016vpcedgewebsgSecurityGroup"
}
]
}
},
"WebASGautoscaling": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AutoScalingGroupName": "saa-ha-web-asg",
"MinSize": "2",
"MaxSize": "10",
"DesiredCapacity": "2",
"HealthCheckType": "ELB",
"HealthCheckGracePeriod": 300,
"VPCZoneIdentifier": [
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet1"
},
{
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet2"
}
]
}
},
"WebInstanceec2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": "t3.small",
"Tags": [
{
"Key": "Name",
"Value": "saa-ha-web-instance"
}
],
"SubnetId": {
"Ref": "HAWebAppVPC10100016vpcPrivateSubnet1"
},
"SecurityGroupIds": [
{
"Ref": "HAWebAppVPC10100016vpcappruntimesgSecurityGroup"
}
],
"MetadataOptions": {
"HttpTokens": "required"
}
}
},
"PostgreSQLDBrds": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"DBInstanceIdentifier": "saa-ha-appdb",
"Engine": "postgres",
"DBName": "appdb",
"DBInstanceClass": "db.t4g.micro",
"DBSubnetGroupName": {
"Ref": "HAWebAppVPC10100016vpcDbSubnetGroup"
},
"VPCSecurityGroups": [
{
"Ref": "HAWebAppVPC10100016vpcdatastoresgSecurityGroup"
},
{
"Ref": "PostgreSQLDBrdsIngressSG"
}
],
"PubliclyAccessible": false,
"AllocatedStorage": "20",
"MaxAllocatedStorage": 100,
"StorageType": "gp3",
"MasterUsername": "appadmin",
"ManageMasterUserPassword": true,
"StorageEncrypted": true,
"BackupRetentionPeriod": 7
}
},
"RedisCacheelasticache": {
"Type": "AWS::ElastiCache::CacheCluster",
"Properties": {
"ClusterName": "saa-ha-cache",
"Engine": "redis",
"CacheNodeType": "cache.t4g.micro",
"NumCacheNodes": 1,
"CacheSubnetGroupName": {
"Ref": "HAWebAppVPC10100016vpcCacheSubnetGroup"
},
"VpcSecurityGroupIds": [
{
"Fn::GetAtt": [
"HAWebAppVPC10100016vpc",
"DefaultSecurityGroup"
]
},
{
"Ref": "RedisCacheelasticacheIngressSG"
}
]
}
},
"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": "HAWebAppVPC10100016vpcappruntimesgSecurityGroup"
}
}
],
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
}
}
},
"RedisCacheelasticacheIngressSG": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow connected compute to ElastiCache redis on port 6379",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": 6379,
"ToPort": 6379,
"SourceSecurityGroupId": {
"Ref": "HAWebAppVPC10100016vpcappruntimesgSecurityGroup"
}
}
],
"VpcId": {
"Ref": "HAWebAppVPC10100016vpc"
}
}
}
}
}Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.