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' NginxSubnetId: Description: 'Subnet ID for a public subnet in which to start the server..' Type: 'AWS::EC2::Subnet::Id' Amzn2LatestAmiId: Description: 'AMI ID for most recent Ubuntu image' Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' 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: t3.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. Resources: NginxServer: Type: AWS::EC2::Instance Properties: InstanceType: !Ref 'InstanceType' ImageId: !Ref Amzn2LatestAmiId KeyName: !Ref SshKeyName BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeType: "gp3" DeleteOnTermination: true VolumeSize: !Ref RootDiskSize SubnetId: !Ref NginxSubnetId SecurityGroupIds: - !GetAtt NginxServerSecurityGroup.GroupId IamInstanceProfile: !Ref NginxInstanceProfile UserData: # # Helper for searching out right incantation. Paste result in script below # for pkg in steam steamcmd; do # for arch in "" ":i386"; do # echo echo ${pkg}${arch} ${pkg}/question select '"I AGREE"' \| debconf-set-selections # echo echo ${pkg}${arch} ${pkg}/license select '"Ok"' \| debconf-set-selections # done # done Fn::Base64: | #!/bin/bash # Run system updates yum update -y # 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; 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 # Create phpinfo file for testing cat >/usr/share/nginx/html/phpinfo.php <<"EOT" <?php phpinfo(); phpinfo(INFO_MODULES); ?> 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 collectd cat >/opt/aws/amazon-cloudwatch-agent/bin/config.json <<"EOT" {"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":"/fis-workshop/asg-access-log","log_stream_name":"{instance_id}"},{"file_path":"/var/log/nginx/error.log","log_group_name":"/fis-workshop/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}}}} EOT 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 Tags: - Key: Name Value: fis-server NginxMetricsFilterRequestTime: Type: AWS::Logs::MetricFilter Properties: FilterPattern: "{$.request_time >= 0}" # Fix this to be a ref LogGroupName: /fis-workshop/asg-access-log MetricTransformations: - MetricValue: "$.request_time" MetricNamespace: "fisworkshop" MetricName: "duration" DefaultValue: 0 NginxMetricsFilter2xx: Type: AWS::Logs::MetricFilter Properties: FilterPattern: "{$.status = 2*}" # Fix this to be a ref LogGroupName: /fis-workshop/asg-access-log MetricTransformations: - MetricValue: "1" MetricNamespace: "fisworkshop" MetricName: "2xx" DefaultValue: 0 NginxMetricsFilter5xx: Type: AWS::Logs::MetricFilter Properties: FilterPattern: "{$.status = 5*}" # Fix this to be a ref LogGroupName: /fis-workshop/asg-access-log MetricTransformations: - MetricValue: "1" MetricNamespace: "fisworkshop" MetricName: "5xx" DefaultValue: 0 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'