AWSTemplateFormatVersion: '2010-09-09' Description: >- AWS CloudFormation template to stand up CS:GO server Parameters: NginxVpcId: Description: 'VPC ID in which to start the server' Type: 'AWS::EC2::VPC::Id' AlbSubnets: Type: List Description: A list of public SubnetIds in your Virtual Private Cloud (VPC) ConstraintDescription: must be a list of at least two existing subnets associated with at least two different availability zones. They should be residing in the selected Virtual Private Cloud and must be public facing. BackendSubnets: Type: List Description: A list of private SubnetIds in your Virtual Private Cloud (VPC) ConstraintDescription: must be a list of at least two existing subnets associated with at least two different availability zones. They should be residing in the selected Virtual Private Cloud and should be private but not isolated. Amzn2LatestAmiId: Description: 'AMI ID for most recent Ubuntu image' Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs' RootDiskSize: Description: 'Size of root disk in GB' Type: String AllowedPattern: '[0-9]+' Default: 8 InstanceType: Description: 'Server instance type' Type: String Default: t2.micro # SshKeyName: # 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. SshAccessFromThisCidrOnly: 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. # OperatorEMail: # Description: EMail address to notify if there are any scaling operations # Type: String # AllowedPattern: ([a-zA-Z0-9_\-\.\+]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?) # ConstraintDescription: must be a valid email address. AccessLogPath: Description: Base path for cloudwatch logs Type: String AllowedPattern: (/[a-zA-Z0-9\-\_]+)+ Default: /fis-workshop LoadGenFunctionName: Description: Name of goad-redux function to identify metrics source Type: String AllowedPattern: ([a-zA-Z0-9\-\_]+) Resources: NotificationTopic: Type: AWS::SNS::Topic Properties: DisplayName: "HookForNotificationEmail" # Subscription: # - Endpoint: !Ref 'OperatorEMail' # Protocol: email WebServerGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: !Ref 'BackendSubnets' LaunchConfigurationName: !Ref 'LaunchConfig' MinSize: "1" MaxSize: "3" MetricsCollection: - Granularity: 1Minute Metrics: - GroupMinSize - GroupMaxSize - GroupDesiredCapacity - GroupInServiceInstances - GroupPendingInstances - GroupStandbyInstances - GroupTerminatingInstances - GroupTotalInstances - GroupInServiceCapacity - GroupPendingCapacity - GroupStandbyCapacity - GroupTerminatingCapacity - GroupTotalCapacity TargetGroupARNs: - !Ref 'ALBTargetGroup' NotificationConfigurations: - TopicARN: !Ref 'NotificationTopic' NotificationTypes: - autoscaling:EC2_INSTANCE_LAUNCH - autoscaling:EC2_INSTANCE_LAUNCH_ERROR - autoscaling:EC2_INSTANCE_TERMINATE - autoscaling:EC2_INSTANCE_TERMINATE_ERROR Tags: - Key: Name Value: fis-asg-server PropagateAtLaunch: true CreationPolicy: ResourceSignal: Timeout: PT15M Count: 1 UpdatePolicy: AutoScalingRollingUpdate: MinInstancesInService: 1 MaxBatchSize: 1 PauseTime: PT15M WaitOnResourceSignals: true # Useful link for cleanup - https://cloudonaut.io/migrating-to-amazon-linux-2/ LaunchConfig: Type: AWS::AutoScaling::LaunchConfiguration Metadata: Comment: Install a simple application AWS::CloudFormation::Init: config: # packages: # yum: # httpd: [] files: # /var/www/html/index.html: # content: !Join # - "\n" # - - AWS CloudFormation Logo # -

Congratulations, you have successfully launched the AWS CloudFormation # sample.

/opt/aws/amazon-cloudwatch-agent/bin/config.json: content: !Sub | {"agent":{"metrics_collection_interval":10,"run_as_user":"root"},"logs":{"logs_collected":{"files":{"collect_list":[{"file_path":"/var/log/nginx/access.log","log_group_name":"${AccessLogPath}/asg-access-log","log_stream_name":"{instance_id}"},{"file_path":"/var/log/nginx/error.log","log_group_name":"${AccessLogPath}/asg-error-log","log_stream_name":"{instance_id}"}]}}},"metrics":{"append_dimensions":{"AutoScalingGroupName":"${!aws:AutoScalingGroupName}","ImageId":"${!aws:ImageId}","InstanceId":"${!aws:InstanceId}","InstanceType":"${!aws:InstanceType}"},"metrics_collected":{"collectd":{"metrics_aggregation_interval":60},"cpu":{"measurement":["cpu_usage_idle","cpu_usage_iowait","cpu_usage_user","cpu_usage_system"],"metrics_collection_interval":10,"resources":["*"],"totalcpu":false},"disk":{"measurement":["used_percent","inodes_free"],"metrics_collection_interval":10,"resources":["*"]},"diskio":{"measurement":["io_time","write_bytes","read_bytes","writes","reads"],"metrics_collection_interval":10,"resources":["*"]},"mem":{"measurement":["mem_used_percent"],"metrics_collection_interval":10},"netstat":{"measurement":["tcp_established","tcp_time_wait"],"metrics_collection_interval":10},"statsd":{"metrics_aggregation_interval":60,"metrics_collection_interval":10,"service_address":":8125"},"swap":{"measurement":["swap_used_percent"],"metrics_collection_interval":10}}}} mode: '000644' owner: root group: root /usr/share/nginx/html/phpinfo.php: content: | mode: '000644' owner: root group: root /usr/share/nginx/html/pi.php: content: | mode: '000644' owner: root group: root /usr/share/nginx/html/index.html: content: |

Hello world

mode: '000644' owner: root group: root /usr/share/nginx/html/rumtest.html: content: |

Hello world

mode: '000644' owner: root group: root # /usr/share/nginx/html/rumexp.html: # content: | # # # #

Hello world

# # mode: '000644' # owner: root # group: root /etc/cfn/cfn-hup.conf: content: !Join - '' - - "[main]\n" - stack= - !Ref 'AWS::StackId' - "\n" - region= - !Ref 'AWS::Region' - "\n" mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Join - '' - - "[cfn-auto-reloader-hook]\n" - "triggers=post.update\n" - "path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\n" - 'action=/opt/aws/bin/cfn-init -v ' - ' --stack ' - !Ref 'AWS::StackName' - ' --resource LaunchConfig ' - ' --region ' - !Ref 'AWS::Region' - "\n" - "runas=root\n" mode: '000400' owner: root group: root services: # sysvinit: # httpd: # enabled: 'true' # ensureRunning: 'true' cfn-hup: enabled: 'true' ensureRunning: 'true' files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf Properties: # KeyName: !Ref SshKeyName ImageId: !Ref Amzn2LatestAmiId SecurityGroups: - !Ref InstanceSecurityGroup InstanceType: !Ref 'InstanceType' IamInstanceProfile: !Ref NginxInstanceProfile BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeType: "gp2" DeleteOnTermination: true VolumeSize: !Ref RootDiskSize UserData: Fn::Base64: !Sub | #!/bin/bash -xe # Run system updates yum update -y yum update -y aws-cfn-bootstrap yum update -y aws-cli /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LaunchConfig --region ${AWS::Region} # Install NGINX 1.12 amazon-linux-extras install nginx1.12 # Install PHP 7.2 amazon-linux-extras install php7.2 # Update php-fpm config mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.orig cat >/etc/php-fpm.d/www.conf <<"EOF" [www] user = nginx group = nginx listen = /run/php-fpm/www.sock listen.acl_users = apache,nginx listen.allowed_clients = 127.0.0.1 pm = dynamic pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35 slowlog = /var/log/php-fpm/www-slow.log php_admin_value[error_log] = /var/log/php-fpm/www-error.log php_admin_flag[log_errors] = on php_value[session.save_handler] = files php_value[session.save_path] = /var/lib/php/session php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache EOF # Update nginx config mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig mv /etc/nginx/conf.d/php-fpm.conf /etc/nginx/conf.d/php-fpm.conf.orig mv /etc/nginx/default.d/php.conf /etc/nginx/default.d/php.conf.orig cat >/etc/nginx/nginx.conf <<"EOT" user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status": "$status",' '"body_bytes_sent":$body_bytes_sent,' '"request_time":$request_time,' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent"' '}'; access_log /var/log/nginx/access.log json_combined; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; server { listen 80 default_server; listen [::]:80 default_server; # server_name 34.218.235.51; server_name _; root /usr/share/nginx/html; index index.php index.html index.htm; include /etc/nginx/default.d/*.conf; location / { # This is cool because no php is touched for static content. # include the "?" part so non-default permalinks doesn't break when using query string # try_files \$uri \$uri/ /index.php?\$args; # try_files \$uri \$uri/ =404; } location ~ \.php$ { # try_files $uri /index.php =404; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } } EOT # Start services and set to start on boot systemctl start nginx systemctl enable nginx systemctl start php-fpm systemctl enable php-fpm # install CW unified agent yum install -y amazon-cloudwatch-agent amazon-linux-extras install -y collectd # rely on /opt/aws/amazon-cloudwatch-agent/bin/config.json systemctl start collectd systemctl enable collectd /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json systemctl start amazon-cloudwatch-agent /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerGroup --region ${AWS::Region} # NginxServerSecurityGroup: # Type: AWS::EC2::SecurityGroup # Properties: # GroupDescription: Enable SSH access and open Nginx ports # VpcId: !Ref NginxVpcId # SecurityGroupIngress: # - IpProtocol: tcp # FromPort: 22 # ToPort: 22 # CidrIp: !Ref 'SshAccessFromThisCidrOnly' # - IpProtocol: tcp # FromPort: 80 # ToPort: 80 # CidrIp: '0.0.0.0/0' # Tags: # - Key: Name # Value: fis-server NginxInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref NginxInstanceRole NginxInstanceRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Tags: - Key: Name Value: fis-server Path: / ManagedPolicyArns: # Allow SSM access - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy # IPAddress: # Type: AWS::EC2::EIP # Properties: # Tags: # - Key: Name # Value: fis-server # IPAssoc: # Type: AWS::EC2::EIPAssociation # Properties: # InstanceId: !Ref 'NginxServer' # EIP: !Ref 'IPAddress' # Outputs: # InstanceId: # Description: InstanceId of the newly created EC2 instance # Value: !Ref 'NginxServer' # InstanceIPAddress: # Description: IP address of the newly created EC2 instance # Value: !Ref 'IPAddress' WebServerScaleUpPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AdjustmentType: ChangeInCapacity AutoScalingGroupName: !Ref 'WebServerGroup' Cooldown: '60' ScalingAdjustment: 1 WebServerScaleDownPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AdjustmentType: ChangeInCapacity AutoScalingGroupName: !Ref 'WebServerGroup' Cooldown: '60' ScalingAdjustment: -1 CPUAlarmHigh: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: Scale-up if CPU > 90% for 1 minute MetricName: CPUUtilization Namespace: AWS/EC2 Statistic: Average Period: 60 EvaluationPeriods: 1 Threshold: 90.0 AlarmActions: - !Ref 'WebServerScaleUpPolicy' Dimensions: - Name: AutoScalingGroupName Value: !Ref 'WebServerGroup' ComparisonOperator: GreaterThanThreshold CPUAlarmLow: Type: AWS::CloudWatch::Alarm Properties: AlarmDescription: Scale-down if CPU < 70% for 5 minutes MetricName: CPUUtilization Namespace: AWS/EC2 Statistic: Average Period: 60 EvaluationPeriods: 5 Threshold: 20.0 AlarmActions: - !Ref 'WebServerScaleDownPolicy' Dimensions: - Name: AutoScalingGroupName Value: !Ref 'WebServerGroup' ComparisonOperator: LessThanThreshold ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Subnets: !Ref 'AlbSubnets' SecurityGroups: - !Ref ALBSecurityGroup ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref 'ALBTargetGroup' LoadBalancerArn: !Ref 'ApplicationLoadBalancer' Port: 80 Protocol: HTTP ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 20 HealthCheckTimeoutSeconds: 15 HealthyThresholdCount: 2 Port: 80 Protocol: HTTP UnhealthyThresholdCount: 10 VpcId: !Ref 'NginxVpcId' ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable SSH HTTP to the load balancer SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: "0.0.0.0/0" - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIpv6: "::/0" VpcId: !Ref 'NginxVpcId' InstanceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable SSH access and HTTP from the load balancer only SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: !Ref 'SshAccessFromThisCidrOnly' - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Select - 0 - !GetAtt 'ApplicationLoadBalancer.SecurityGroups' VpcId: !Ref 'NginxVpcId' NginxLogGroupAccess: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "${AccessLogPath}/asg-access-log" NginxMetricsFilterRequestTime: Type: AWS::Logs::MetricFilter Properties: FilterPattern: "{$.request_time >= 0}" # LogGroupName: !Sub "${AccessLogPath}/asg-access-log" LogGroupName: !Ref NginxLogGroupAccess MetricTransformations: - MetricValue: "$.request_time" MetricNamespace: "fisworkshop" MetricName: "duration" DefaultValue: 0 NginxMetricsFilter2xx: Type: AWS::Logs::MetricFilter Properties: FilterPattern: "{$.status = 2*}" # LogGroupName: !Sub "${AccessLogPath}/asg-access-log" LogGroupName: !Ref NginxLogGroupAccess MetricTransformations: - MetricValue: "1" MetricNamespace: "fisworkshop" MetricName: "2xx" DefaultValue: 0 NginxMetricsFilter5xx: Type: AWS::Logs::MetricFilter Properties: FilterPattern: "{$.status = 5*}" # LogGroupName: !Sub "${AccessLogPath}/asg-access-log" LogGroupName: !Ref NginxLogGroupAccess MetricTransformations: - MetricValue: "1" MetricNamespace: "fisworkshop" MetricName: "5xx" DefaultValue: 0 # Dashboard based on goad metrics coming from EMF NginxAsgDashboard: Type: AWS::CloudWatch::Dashboard Properties: DashboardName: !Sub 'fis-dashboard-asg-${AWS::Region}' DashboardBody: !Sub | { "widgets": [ { "height": 6, "width": 12, "y": 0, "x": 0, "type": "metric", "properties": { "metrics": [ [ { "expression": "AVG(SEARCH('goad AND error_connect', 'Sum', 1))", "id": "error_connect", "period": 1, "color": "#d62728", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND error_read', 'Sum', 1))", "id": "error_read", "period": 1, "color": "#e377c2", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND status_5xx', 'Sum', 1))", "id": "status_5xx", "period": 1, "color": "#ff9896", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND status_4xx', 'Sum', 1))", "id": "status_4xx", "period": 1, "color": "#f7b6d2", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND status_2xx', 'Sum', 1))", "id": "status_2xx", "period": 1, "color": "#98df8a", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND success', 'Sum', 1))", "id": "success", "period": 1, "color": "#bcbd22", "region": "${AWS::Region}" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "goad connection status", "yAxis": { "left": { "min": 0, "max": 100 }, "right": { "min": 0 } } } }, { "height": 6, "width": 12, "y": 6, "x": 0, "type": "metric", "properties": { "metrics": [ [ { "expression": "AVG(SEARCH('goad AND duration_max', 'Average', 1))", "id": "duration_max", "period": 1, "color": "#1f77b4", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND duration_avg', 'Average', 1))", "id": "duration_avg", "period": 1, "color": "#17becf", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('goad AND duration_min', 'Average', 1))", "id": "duration_min", "period": 1, "color": "#9edae5", "region": "${AWS::Region}" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "goad response times", "yAxis": { "left": { "min": 0 }, "right": { "min": 0, "max": 100 } } } }, { "height": 6, "width": 12, "y": 0, "x": 12, "type": "metric", "properties": { "metrics": [ [ "fisworkshop", "2xx", { "color": "#2ca02c" } ], [ ".", "5xx" ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "nginx connection status", "yAxis": { "left": { "min": 0, "max": 1 } } } }, { "height": 6, "width": 12, "y": 12, "x": 12, "type": "metric", "properties": { "metrics": [ [ { "expression": "SUM(SEARCH('CWAgent AND ${WebServerGroup} AND netstat_tcp_established', 'Maximum', 1))", "id": "sum_tcp_established", "period": 1, "color": "#2ca02c", "region": "${AWS::Region}" } ], [ { "expression": "SUM(SEARCH('CWAgent AND ${WebServerGroup} AND netstat_tcp_time_wait', 'Maximum', 1))", "id": "sum_tcp_time_wait", "period": 1, "color": "#d62728", "region": "${AWS::Region}" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "network status", "yAxis": { "left": { "min": 0 }, "right": { "min": 0 } } } }, { "height": 6, "width": 12, "y": 6, "x": 12, "type": "metric", "properties": { "metrics": [ [ "fisworkshop", "duration" ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "nginx response time", "yAxis": { "left": { "min": 0 } } } }, { "height": 6, "width": 12, "y": 12, "x": 0, "type": "metric", "properties": { "metrics": [ [ { "expression": "AVG(SEARCH('CWAgent AND ${WebServerGroup} AND cpu_usage_idle', 'Average', 1))", "id": "avg_cpu_idle", "period": 1, "color": "#2ca02c", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('CWAgent AND ${WebServerGroup} AND cpu_usage_user', 'Average', 1))", "id": "avg_cpu_user", "period": 1, "color": "#1f77b4", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('CWAgent AND ${WebServerGroup} AND cpu_usage_system', 'Average', 1))", "id": "avg_cpu_system", "period": 1, "color": "#ff7f0e", "region": "${AWS::Region}" } ], [ { "expression": "AVG(SEARCH('CWAgent AND ${WebServerGroup} AND cpu_usage_iowait', 'Average', 1))", "id": "avg_cpu_iowait", "period": 1, "color": "#d62728", "region": "${AWS::Region}" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "server cpu" } }, { "height": 6, "width": 12, "y": 18, "x": 0, "type": "metric", "properties": { "metrics": [ [ "AWS/AutoScaling", "GroupMaxSize", "AutoScalingGroupName", "${WebServerGroup}" ], [ ".", "GroupDesiredCapacity", ".", "." ], [ ".", "GroupInServiceInstances", ".", "." ], [ ".", "GroupMinSize", ".", ".", { "color": "#1f77b4" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "ASG number of instances", "yAxis": { "left": { "min": 0 } } } } ] } NginxAsgDashboard1: Type: AWS::CloudWatch::Dashboard Properties: DashboardName: !Sub 'fis-dashboard-1-${AWS::Region}' DashboardBody: !Sub | { "widgets": [ { "height": 6, "width": 12, "y": 0, "x": 0, "type": "metric", "properties": { "metrics": [ [ "fisworkshop", "2xx", { "color": "#2ca02c" } ], [ ".", "5xx" ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "nginx connection status", "yAxis": { "left": { "min": 0, "max": 1 } } } }, { "height": 6, "width": 12, "y": 6, "x": 0, "type": "metric", "properties": { "metrics": [ [ "fisworkshop", "duration" ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "nginx response time", "yAxis": { "left": { "min": 0 } } } }, { "height": 6, "width": 12, "y": 0, "x": 12, "type": "metric", "properties": { "metrics": [ [ "AWS/AutoScaling", "GroupMaxSize", "AutoScalingGroupName", "${WebServerGroup}" ], [ ".", "GroupDesiredCapacity", ".", "." ], [ ".", "GroupInServiceInstances", ".", "." ], [ ".", "GroupMinSize", ".", ".", { "color": "#1f77b4" } ] ], "view": "timeSeries", "stacked": false, "region": "${AWS::Region}", "stat": "Average", "period": 1, "title": "ASG number of instances", "yAxis": { "left": { "min": 0 } } } } ] } Outputs: URL: Description: The URL of the website Value: !Join - '' - - http:// - !GetAtt 'ApplicationLoadBalancer.DNSName'