Skip to content

Instantly share code, notes, and snippets.

@nijogeorgep
Created June 5, 2025 03:35
Show Gist options
  • Select an option

  • Save nijogeorgep/111ca169eeaf59966a47813c7e8f3a1d to your computer and use it in GitHub Desktop.

Select an option

Save nijogeorgep/111ca169eeaf59966a47813c7e8f3a1d to your computer and use it in GitHub Desktop.
CloudFormation Template to Deploy NGINX Servers behind an ELB
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
@nijogeorgep
Copy link
Author

Made Public

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment