Created
June 5, 2025 03:35
-
-
Save nijogeorgep/111ca169eeaf59966a47813c7e8f3a1d to your computer and use it in GitHub Desktop.
CloudFormation Template to Deploy NGINX Servers behind an ELB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| AWSTemplateFormatVersion: '2010-09-09' | |
| Description: 'CloudFormation template to deploy NGINX server behind an ELB' | |
| Parameters: | |
| InstanceType: | |
| Description: EC2 instance type | |
| Type: String | |
| Default: t2.micro | |
| AllowedValues: | |
| - t2.micro | |
| - t2.small | |
| - t2.medium | |
| ConstraintDescription: Must be a valid EC2 instance type. | |
| KeyName: | |
| Description: Name of an existing EC2 KeyPair to enable SSH access to the instances | |
| Type: AWS::EC2::KeyPair::KeyName | |
| ConstraintDescription: Must be the name of an existing EC2 KeyPair. | |
| SSHLocation: | |
| Description: The IP address range that can be used to SSH to the EC2 instances | |
| Type: String | |
| MinLength: 9 | |
| MaxLength: 18 | |
| Default: 0.0.0.0/0 | |
| AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) | |
| ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x. | |
| HostedZoneName: | |
| Description: The name of the private hosted zone | |
| Type: String | |
| Default: lab.cloudwalker.com | |
| AllowedPattern: (?!-)[a-zA-Z0-9-.]{1,63}(?<!-) | |
| ConstraintDescription: Must be a valid DNS zone name. | |
| Resources: | |
| VPC: | |
| Type: AWS::EC2::VPC | |
| Properties: | |
| CidrBlock: 10.0.0.0/16 | |
| EnableDnsSupport: true | |
| EnableDnsHostnames: true | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-VPC | |
| InternetGateway: | |
| Type: AWS::EC2::InternetGateway | |
| Properties: | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-IGW | |
| InternetGatewayAttachment: | |
| Type: AWS::EC2::VPCGatewayAttachment | |
| Properties: | |
| InternetGatewayId: !Ref InternetGateway | |
| VpcId: !Ref VPC | |
| PublicSubnet1: | |
| Type: AWS::EC2::Subnet | |
| Properties: | |
| VpcId: !Ref VPC | |
| AvailabilityZone: !Select [ 0, !GetAZs '' ] | |
| CidrBlock: 10.0.1.0/24 | |
| MapPublicIpOnLaunch: true | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-Public-Subnet-1 | |
| PublicSubnet2: | |
| Type: AWS::EC2::Subnet | |
| Properties: | |
| VpcId: !Ref VPC | |
| AvailabilityZone: !Select [ 1, !GetAZs '' ] | |
| CidrBlock: 10.0.2.0/24 | |
| MapPublicIpOnLaunch: true | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-Public-Subnet-2 | |
| PublicRouteTable: | |
| Type: AWS::EC2::RouteTable | |
| Properties: | |
| VpcId: !Ref VPC | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-Public-RT | |
| DefaultPublicRoute: | |
| Type: AWS::EC2::Route | |
| DependsOn: InternetGatewayAttachment | |
| Properties: | |
| RouteTableId: !Ref PublicRouteTable | |
| DestinationCidrBlock: 0.0.0.0/0 | |
| GatewayId: !Ref InternetGateway | |
| PublicSubnet1RouteTableAssociation: | |
| Type: AWS::EC2::SubnetRouteTableAssociation | |
| Properties: | |
| RouteTableId: !Ref PublicRouteTable | |
| SubnetId: !Ref PublicSubnet1 | |
| PublicSubnet2RouteTableAssociation: | |
| Type: AWS::EC2::SubnetRouteTableAssociation | |
| Properties: | |
| RouteTableId: !Ref PublicRouteTable | |
| SubnetId: !Ref PublicSubnet2 | |
| WebServerSecurityGroup: | |
| Type: AWS::EC2::SecurityGroup | |
| Properties: | |
| GroupDescription: Enable HTTP access via port 80 and SSH access | |
| VpcId: !Ref VPC | |
| SecurityGroupIngress: | |
| - IpProtocol: tcp | |
| FromPort: 80 | |
| ToPort: 80 | |
| CidrIp: 0.0.0.0/0 | |
| - IpProtocol: tcp | |
| FromPort: 22 | |
| ToPort: 22 | |
| CidrIp: !Ref SSHLocation | |
| ELBSecurityGroup: | |
| Type: AWS::EC2::SecurityGroup | |
| Properties: | |
| GroupDescription: Enable HTTP access to ELB | |
| VpcId: !Ref VPC | |
| SecurityGroupIngress: | |
| - IpProtocol: tcp | |
| FromPort: 80 | |
| ToPort: 80 | |
| CidrIp: 0.0.0.0/0 | |
| WebServerLaunchTemplate: | |
| Type: AWS::EC2::LaunchTemplate | |
| Properties: | |
| LaunchTemplateName: !Sub "${AWS::StackName}-launch-template" | |
| VersionDescription: Initial version | |
| LaunchTemplateData: | |
| ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI] | |
| InstanceType: !Ref InstanceType | |
| SecurityGroupIds: | |
| - !Ref WebServerSecurityGroup | |
| KeyName: !Ref KeyName | |
| UserData: | |
| Fn::Base64: !Sub | | |
| #!/bin/bash -xe | |
| yum update -y | |
| amazon-linux-extras install nginx1 -y | |
| systemctl start nginx | |
| systemctl enable nginx | |
| echo "<h1>Hello from NGINX on $(hostname -f)</h1>" > /usr/share/nginx/html/index.html | |
| WebServerGroup: | |
| Type: AWS::AutoScaling::AutoScalingGroup | |
| Properties: | |
| VPCZoneIdentifier: | |
| - !Ref PublicSubnet1 | |
| - !Ref PublicSubnet2 | |
| LaunchTemplate: | |
| LaunchTemplateId: !Ref WebServerLaunchTemplate | |
| Version: !GetAtt WebServerLaunchTemplate.LatestVersionNumber | |
| MinSize: 2 | |
| MaxSize: 4 | |
| DesiredCapacity: 2 | |
| TargetGroupARNs: | |
| - !Ref WebServerTargetGroup | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-WebServer | |
| PropagateAtLaunch: true | |
| MetricsCollection: | |
| - Granularity: 1Minute | |
| Metrics: | |
| - GroupMinSize | |
| - GroupMaxSize | |
| - GroupDesiredCapacity | |
| - GroupInServiceInstances | |
| - GroupInServiceCapacity | |
| - GroupPendingInstances | |
| - GroupPendingCapacity | |
| - GroupTerminatingInstances | |
| - GroupTerminatingCapacity | |
| - GroupStandbyInstances | |
| - GroupStandbyCapacity | |
| - GroupTotalInstances | |
| - GroupTotalCapacity | |
| WebServerTargetGroup: | |
| Type: AWS::ElasticLoadBalancingV2::TargetGroup | |
| Properties: | |
| HealthCheckIntervalSeconds: 30 | |
| HealthCheckPath: / | |
| HealthCheckProtocol: HTTP | |
| HealthCheckTimeoutSeconds: 5 | |
| HealthyThresholdCount: 2 | |
| Port: 80 | |
| Protocol: HTTP | |
| UnhealthyThresholdCount: 5 | |
| VpcId: !Ref VPC | |
| TargetType: instance | |
| ApplicationLoadBalancer: | |
| Type: AWS::ElasticLoadBalancingV2::LoadBalancer | |
| Properties: | |
| Subnets: | |
| - !Ref PublicSubnet1 | |
| - !Ref PublicSubnet2 | |
| SecurityGroups: | |
| - !Ref ELBSecurityGroup | |
| Tags: | |
| - Key: Name | |
| Value: NGINX-ALB | |
| ALBListener: | |
| Type: AWS::ElasticLoadBalancingV2::Listener | |
| Properties: | |
| DefaultActions: | |
| - Type: forward | |
| TargetGroupArn: !Ref WebServerTargetGroup | |
| LoadBalancerArn: !Ref ApplicationLoadBalancer | |
| Port: 80 | |
| Protocol: HTTP | |
| CPUHighAlarm: | |
| Type: AWS::CloudWatch::Alarm | |
| Properties: | |
| AlarmDescription: Scale up if CPU > 70% for 2 consecutive periods of 60 seconds | |
| MetricName: CPUUtilization | |
| Namespace: AWS/EC2 | |
| Statistic: Average | |
| Period: 60 | |
| EvaluationPeriods: 2 | |
| Threshold: 70 | |
| AlarmActions: | |
| - !Ref ScaleUpPolicy | |
| Dimensions: | |
| - Name: AutoScalingGroupName | |
| Value: !Ref WebServerGroup | |
| ComparisonOperator: GreaterThanThreshold | |
| CPULowAlarm: | |
| Type: AWS::CloudWatch::Alarm | |
| Properties: | |
| AlarmDescription: Scale down if CPU < 30% for 2 consecutive periods of 60 seconds | |
| MetricName: CPUUtilization | |
| Namespace: AWS/EC2 | |
| Statistic: Average | |
| Period: 60 | |
| EvaluationPeriods: 2 | |
| Threshold: 30 | |
| AlarmActions: | |
| - !Ref ScaleDownPolicy | |
| Dimensions: | |
| - Name: AutoScalingGroupName | |
| Value: !Ref WebServerGroup | |
| ComparisonOperator: LessThanThreshold | |
| ScaleUpPolicy: | |
| Type: AWS::AutoScaling::ScalingPolicy | |
| Properties: | |
| AdjustmentType: ChangeInCapacity | |
| AutoScalingGroupName: !Ref WebServerGroup | |
| Cooldown: 300 | |
| ScalingAdjustment: 1 | |
| ScaleDownPolicy: | |
| Type: AWS::AutoScaling::ScalingPolicy | |
| Properties: | |
| AdjustmentType: ChangeInCapacity | |
| AutoScalingGroupName: !Ref WebServerGroup | |
| Cooldown: 300 | |
| ScalingAdjustment: -1 | |
| TargetTrackingScalingPolicy: | |
| Type: AWS::AutoScaling::ScalingPolicy | |
| Properties: | |
| AutoScalingGroupName: !Ref WebServerGroup | |
| PolicyType: TargetTrackingScaling | |
| TargetTrackingConfiguration: | |
| PredefinedMetricSpecification: | |
| PredefinedMetricType: ASGAverageCPUUtilization | |
| TargetValue: 50.0 | |
| DisableScaleIn: false | |
| # Route 53 Private Hosted Zone | |
| PrivateHostedZone: | |
| Type: AWS::Route53::HostedZone | |
| Properties: | |
| Name: !Ref HostedZoneName | |
| VPCs: | |
| - VPCId: !Ref VPC | |
| VPCRegion: !Ref "AWS::Region" | |
| HostedZoneConfig: | |
| Comment: Private hosted zone for NGINX ELB | |
| # DNS Record for ELB | |
| NginxDNSRecord: | |
| Type: AWS::Route53::RecordSet | |
| DependsOn: ApplicationLoadBalancer | |
| Properties: | |
| HostedZoneId: !Ref PrivateHostedZone | |
| Name: !Sub "nginx.${HostedZoneName}" | |
| Type: A | |
| AliasTarget: | |
| DNSName: !GetAtt ApplicationLoadBalancer.DNSName | |
| HostedZoneId: !GetAtt ApplicationLoadBalancer.CanonicalHostedZoneID | |
| EvaluateTargetHealth: true | |
| Mappings: | |
| RegionMap: | |
| us-east-1: | |
| AMI: ami-0c02fb55956c7d316 | |
| us-east-2: | |
| AMI: ami-05fb0b8c1424f266b | |
| us-west-1: | |
| AMI: ami-04669a22aad391419 | |
| us-west-2: | |
| AMI: ami-0cf6f5c8a62fa5da6 | |
| eu-west-1: | |
| AMI: ami-0ce1e3f77cd41957e | |
| ap-northeast-1: | |
| AMI: ami-0ab0bbbd329f565e6 | |
| ap-southeast-1: | |
| AMI: ami-0f86a70488991335e | |
| ap-southeast-2: | |
| AMI: ami-0310483fb2b488153 | |
| Outputs: | |
| WebsiteURL: | |
| Description: URL of the website via ELB | |
| Value: !Sub http://${ApplicationLoadBalancer.DNSName} | |
| PrivateWebsiteURL: | |
| Description: URL of the website via private DNS | |
| Value: !Sub http://nginx.${HostedZoneName} | |
| PrivateHostedZoneId: | |
| Description: ID of the private hosted zone | |
| Value: !Ref PrivateHostedZone |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Made Public