---
AWSTemplateFormatVersion: 2010-09-09

Description: Reference Architecture to host WordPress on AWS - Creates WordPress web Auto Scaling group

Metadata:

  Authors:
    Description: Darryl Osborne (darrylo@amazon.com)
  License:
    Description: 'Copyright 2018 Amazon.com, Inc. and its affiliates. All Rights Reserved.
                  SPDX-License-Identifier: MIT-0'

  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: Web Parameters
      Parameters:
        - PHPVersion
        - PHPIniOverride
        - EC2KeyName
        - WebInstanceType
        - WebAsgMax
        - WebAsgMin
        - WebSecurityGroup
        - NumberOfSubnets
        - Subnet
        - PublicAlbTargetGroupArn
        - PublicAlbHostname
        - SslCertificate
    - Label:
        default: WordPress Parameters
      Parameters:
        - WPVersion
        - WPTitle
        - WPDomainName
        - WPDirectory
        - WPAdminUsername
        - WPAdminPassword
        - WPAdminEmail
        - WPLocale
    - Label:
        default: Database Parameters
      Parameters:
        - DatabaseClusterEndpointAddress
        - DatabaseName
        - DatabaseMasterUsername
        - DatabaseMasterPassword
    - Label:
        default: File System Parameters
      Parameters:
        - ElasticFileSystem
    ParameterLabels:
      PHPIniOverride:
        default: AWS php.ini Overrides
      DatabaseClusterEndpointAddress:
        default: DB Cluster Endpoint Address
      DatabaseMasterUsername:
        default: DB Master Username  
      DatabaseMasterPassword:
        default: DB Master Password
      DatabaseName:
        default: DB Name
      ElasticFileSystem:
        default: EFS File System
      EC2KeyName:
        default: Existing Key Pair
      NumberOfSubnets:
        default: Number of subnets
      PHPVersion:
        default: PHP Version
      PublicAlbTargetGroupArn:
        default: Public Alb Target Group Arn
      PublicAlbHostname:
        default: Public Alb Hostname
      SslCertificate:
        default: ACM Cert attached to Public Alb
      Subnet:
        default: Subnets
      WebAsgMax:
        default: Web ASG Max
      WebAsgMin:
        default: Web ASG Min
      WebInstanceType:
        default: Web Instance Type
      WebSecurityGroup:
        default: Web Security Group
      WPAdminEmail:
        default: Admin Email
      WPAdminPassword:
        default: Admin Password
      WPAdminUsername:
        default: Admin Username
      WPDirectory:
        default: Site Directory
      WPDomainName:
        default: Site Domain
      WPLocale:
        default: Language Code
      WPTitle:
        default: Site Title
      WPVersion:
        default: WordPress Version

Parameters:

  DatabaseClusterEndpointAddress:
    Description: The RDS cluster endpoint address.
    Type: String
  DatabaseMasterUsername:
    AllowedPattern: ^([a-zA-Z0-9]*)$
    Description: The Amazon RDS master username.
    ConstraintDescription: Must contain only alphanumeric characters and be at least 8 characters.
    MaxLength: 16
    MinLength: 1
    Type: String
  DatabaseMasterPassword:
    AllowedPattern: ^([a-z0-9A-Z`~!#$%^&*()_+,\\-])*$
    ConstraintDescription: Must be letters (upper or lower), numbers, and these special characters '_'`~!#$%^&*()_+,-
    Description: The Amazon RDS master password.
    MaxLength: 41
    MinLength: 8
    NoEcho: true
    Type: String
  DatabaseName:
    AllowedPattern: ^([a-zA-Z0-9]*)$
    Description: The Amazon RDS master database name.
    Type: String
  ElasticFileSystem:
    AllowedPattern: ^(fs-)([a-z0-9]{17})$
    Description: The Amazon EFS file system id.
    Type: String
  EC2KeyName:
    AllowedPattern: ^([a-zA-Z0-9 @.`~!#$%^&*()_+,\\-])*$
    ConstraintDescription: Must be letters (upper or lower), numbers, and special characters.
    Description: Name of an EC2 KeyPair. Your bastion & Web instances will launch with this KeyPair.
    Type: AWS::EC2::KeyPair::KeyName
  NumberOfSubnets:
    AllowedValues:
    - 2
    - 3
    - 4
    - 5
    - 6
    Default: 3
    Description: Number of subnets. This must match your selections in the list of subnets below.
    Type: String 
  PHPIniOverride:
    Description: Full Amazon S3 https path to a php.ini override file (e.g. https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/20-aws.ini)
    Type: String
  PHPVersion:
    AllowedValues:
    - 8.0
    - 7.4
    Default: 8.0
    Description: The version of PHP to install.
    Type: String 
  PublicAlbTargetGroupArn:
    Description: The public application load balancer target group arn.
    Type: String
  PublicAlbHostname:
    Description: The hostname of the public ALB http form (e.g. http://abdc-12345-xyz.<region>.elb.amazonaws.com)
    Type: String
  SslCertificate:
    AllowedValues:
      - True
      - False
    Default: False
    Description: Is there an ACM SSL Certificate attached to the Public Alb?
    Type:
      String
  Subnet:
    Description: Select existing subnets. The number selected must match the number of subnets above. Subnets selected must be in separate AZs.
    Type: List<AWS::EC2::Subnet::Id>
  WebAsgMax:
    AllowedPattern: ^((?!0$)[1-2]?[0-9]|30)$
    ConstraintDescription: Must be a number between 1 and 30.
    Default: 4
    Description: Specifies the maximum number of EC2 instances in the Web Autoscaling Group.
    Type: String
  WebAsgMin:
    AllowedPattern: ^([0-0]?[0-9]|10)$
    ConstraintDescription: Must be a number between 0 and 10.
    Default: 2
    Description: Specifies the minimum number of EC2 instances in the Web Autoscaling Group.
    Type: String
  WebInstanceType:
    AllowedValues:
    - t3.nano
    - t3.micro
    - t3.small
    - t3.medium
    - t3.large
    ConstraintDescription: Must be a valid Amazon EC2 instance type.
    Default: t3.large
    Description: The Amazon EC2 instance type for your web instances.
    Type: String
  WebSecurityGroup:
    Description: Select the web security group.
    Type: AWS::EC2::SecurityGroup::Id
  WPAdminEmail:
    AllowedPattern: ^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$
    Description: The WordPress admin email address.
    Type: String
  WPAdminPassword:
    AllowedPattern: ^([a-zA-Z0-9`~!#$%^&*()_+,\\-])*$
    ConstraintDescription: Must be letters (upper or lower), numbers, and these special characters '_'`~!#$%^&*()_+,-   
    Description: The WordPress admin password.
    Type: String
    NoEcho: true
  WPAdminUsername:
    AllowedPattern: ^([a-zA-Z0-9])([a-zA-Z0-9_-])*([a-zA-Z0-9])$
    Description: The WordPress admin username.
    Type: String
  WPDirectory:
    AllowedPattern: ^([a-zA-Z0-9])([a-zA-Z0-9_-])*([a-zA-Z0-9])$
    Description: The WordPress site directory.
    Type: String
  WPDomainName:
    AllowedPattern: ^$|(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$
    Description: '[ Optional ] The main domain name of the WordPress site (e.g. example.com). Leave empty to use the ALB DNS name for the WordPress site.'
    Type: String
  WPLocale:
    Description: The main language of the WordPress site, as per https://codex.WordPress.org/Installing_WordPress_in_Your_Language. The default is 'en_GB'.
    Type: String
    Default: en_GB
  WPTitle:
    AllowedPattern: ^([a-zA-Z0-9])([a-zA-Z0-9 _-]*)([a-zA-Z0-9])$
    Description: The WordPress website title.
    Type: String
  WPVersion:
    AllowedValues:
      - latest
      - nightly
      - 6.0.3
      - 5.9.5
      - 4.9.22
    Default: latest
    Description: The WordPress version (make sure this version is compatible with the PHP version selected above).
    Type: String

Conditions:

  NoSslCertificate:
    !Equals [ False, !Ref SslCertificate ]
  NumberOfSubnets1:
    !Equals [ 1, !Ref NumberOfSubnets ]
  NumberOfSubnets2:
    !Equals [ 2, !Ref NumberOfSubnets ]
  NumberOfSubnets3:
    !Equals [ 3, !Ref NumberOfSubnets ]
  NumberOfSubnets4:
    !Equals [ 4, !Ref NumberOfSubnets ]
  NumberOfSubnets5:
    !Equals [ 5, !Ref NumberOfSubnets ]
  NumberOfSubnets6:
    !Equals [ 6, !Ref NumberOfSubnets ]
  PHP80:
    !Equals [ 8.0, !Ref PHPVersion ]
  PHP81:
    !Equals [ 8.1, !Ref PHPVersion ]
  PHP74:
    !Equals [ 7.4, !Ref PHPVersion ]
  Subnet0: !Or
    - !Condition NumberOfSubnets1
    - !Condition NumberOfSubnets2
    - !Condition NumberOfSubnets3
    - !Condition NumberOfSubnets4
    - !Condition NumberOfSubnets5
    - !Condition NumberOfSubnets6
  Subnet1: !Or
    - !Condition NumberOfSubnets2
    - !Condition NumberOfSubnets3
    - !Condition NumberOfSubnets4
    - !Condition NumberOfSubnets5
    - !Condition NumberOfSubnets6
  Subnet2: !Or
    - !Condition NumberOfSubnets3
    - !Condition NumberOfSubnets4
    - !Condition NumberOfSubnets5
    - !Condition NumberOfSubnets6
  Subnet3: !Or
    - !Condition NumberOfSubnets4
    - !Condition NumberOfSubnets5
    - !Condition NumberOfSubnets6
  Subnet4: !Or
    - !Condition NumberOfSubnets5
    - !Condition NumberOfSubnets6
  Subnet5: !Condition NumberOfSubnets6
  NoWPDomainName:
    !Equals [ '', !Ref WPDomainName ]

Mappings:

  RegionMap:
    ap-northeast-1:
      AMI: ami-0de5311b2a443fb89
    ap-northeast-2:
      AMI: ami-09cf633fe86e51bf0
    ap-south-1:
      AMI: ami-0e6329e222e662a52
    ap-southeast-1:
      AMI: ami-094bbd9e922dc515d
    ap-southeast-2:
      AMI: ami-0e3db330b156044b4
    ca-central-1:
      AMI: ami-088d4832275406edf
    eu-central-1:
      AMI: ami-070b208e993b59cea
    eu-west-1:
      AMI: ami-0ee415e1b8b71305f
    eu-west-2:
      AMI: ami-0648ea225c13e0729
    sa-east-1:
      AMI: ami-0122c4b16734197ac
    us-east-1:
      AMI: ami-0761052211f889859
    us-east-2:
      AMI: ami-045c61808fbcd75c9
    us-west-1:
      AMI: ami-017c001a88dd93847
    us-west-2:
      AMI: ami-0cc3c41e55d91e9af

Resources:

  WebInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
      - !Ref WebInstanceRole
  WebInstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: /
      Policies:
      - PolicyName: logs
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
            - logs:DescribeLogStreams
            Resource:
            - arn:aws:logs:*:*:*
  WebAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      Cooldown: 60
      HealthCheckGracePeriod: 120
      HealthCheckType: ELB
      LaunchConfigurationName:
        !If
          [ PHP80,
          !Ref WebLaunchConfiguration80,
          !If
            [ PHP81,
            !Ref WebLaunchConfiguration81,
            !Ref WebLaunchConfiguration74
            ]          
          ]
      MaxSize: !Ref WebAsgMax
      MinSize: !Ref WebAsgMin
      Tags:
        - Key: Name
          Value: !Join [ '', [ 'Web ASG / ', !Ref 'AWS::StackName' ] ]
          PropagateAtLaunch: true
      TargetGroupARNs:
        - !Ref PublicAlbTargetGroupArn
      VPCZoneIdentifier:
        !If
          [ NumberOfSubnets1,
          [ !Select [ 0, !Ref Subnet ] ],
          !If
            [ NumberOfSubnets2,
            [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ] ],
            !If
              [ NumberOfSubnets3,
              [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ] ],
              !If
                [ NumberOfSubnets4,
                [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ], !Select [ 3, !Ref Subnet ] ],
                !If
                  [ NumberOfSubnets5,
                  [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ], !Select [ 3, !Ref Subnet ], !Select [ 4, !Ref Subnet ] ],
                  [ !Select [ 0, !Ref Subnet ], !Select [ 1, !Ref Subnet ], !Select [ 2, !Ref Subnet ], !Select [ 3, !Ref Subnet ], !Select [ 4, !Ref Subnet ], !Select [ 5, !Ref Subnet ] ]
                  ]
                ]
              ]
            ]
          ]
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
  WebLaunchConfiguration80:
    Condition: PHP80
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          deploy_webserver:
            - install_webserver
            - build_cacheclient
            - build_wordpress
            - build_opcache
            - download_aws_ini
            - install_aws_ini
            - install_cacheclient
            - install_wordpress
            - install_opcache
            - start_webserver
        install_webserver:  
          files:
            /tmp/create_site_conf.sh:
              content:
                !Sub |
                  #!/bin/bash
                    touch /etc/httpd/conf.d/${WPDirectory}.conf
                    echo 'ServerName 127.0.0.1:80' >> /etc/httpd/conf.d/${WPDirectory}.conf
                    echo 'DocumentRoot /var/www/wordpress/${WPDirectory}' >> /etc/httpd/conf.d/${WPDirectory}.conf
                    echo '<Directory /var/www/wordpress/${WPDirectory}>' >> /etc/httpd/conf.d/${WPDirectory}.conf
                    echo '  Options Indexes FollowSymLinks' >> /etc/httpd/conf.d/${WPDirectory}.conf
                    echo '  AllowOverride All' >> /etc/httpd/conf.d/${WPDirectory}.conf
                    echo '  Require all granted' >> /etc/httpd/conf.d/${WPDirectory}.conf
                    echo '</Directory>' >> /etc/httpd/conf.d/${WPDirectory}.conf                
              mode: 000500
              owner: root
              group: root
          commands:
            create_site_conf:
              command: ./create_site_conf.sh
              cwd: /tmp
              ignoreErrors: false
        build_cacheclient:
          files:
            /tmp/install_cacheclient.sh:
              content:
                !Sub |
                  #!/bin/bash
                  pecl install igbinary
                  pecl channel-update pecl.php.net                  
                  cd /tmp
                  wget -P /tmp/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/AmazonElastiCacheClusterClient-PHP80-64bit-libmemcached-1.0.19-openssl1.1.tar.gz
                  tar -xf '/tmp/AmazonElastiCacheClusterClient-PHP80-64bit-libmemcached-1.0.19-openssl1.1.tar.gz'
                  cp '/tmp/amazon-elasticache-cluster-client.so' /usr/lib64/php/modules/
                  if [ ! -f /etc/php.d/50-memcached.ini ]; then
                      touch /etc/php.d/50-memcached.ini
                  fi
                  echo 'extension=igbinary.so;' >> /etc/php.d/50-memcached.ini
                  echo 'extension=/usr/lib64/php/modules/amazon-elasticache-cluster-client.so;' >> /etc/php.d/50-memcached.ini
              mode: 000500
              owner: root
              group: root
        build_opcache:
          files:
            /tmp/install_opcache.sh:
              content:
                !Sub |
                  #!/bin/bash
                  # create hidden opcache directory locally & change owner to apache                    
                  mkdir -p /var/www/.opcache
                  # enable opcache in /etc/php.d/opcache.ini
                  touch /etc/php.d/opcache.ini
                  echo 'opcache.file_cache=/var/www/.opcache/' >> /etc/php.d/opcache.ini
                  echo 'opcache.memory_consumption=512' >> /etc/php.d/opcache.ini
                  # download opcache-instance.php to verify opcache status
                  if [ ! -f /var/www/wordpress/${WPDirectory}/opcache-instanceid.php ]; then
                      wget -P /var/www/wordpress/${WPDirectory}/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/opcache-instanceid.php
                  fi
              mode: 000500
              owner: root
              group: root
        build_wordpress:
          files:
            /tmp/install_wordpress.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -xe\n",
                    "\n",
                    "# install wp-cli\n",
                    "if [ ! -f /bin/wp/wp-cli.phar ]; then\n",
                    "   curl -o /bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar\n",
                    "   chmod +x /bin/wp\n",
                    "fi\n",
                    "\n",
                    "   cd /var/www/wordpress/", !Ref WPDirectory, "\n",
                    "   # install wordpress if not installed\n",
                    "   # use public alb host name if wp domain name was empty\n",
                    "       wp core download --version='", !Ref WPVersion, "' --locale='", !Ref WPLocale, "' --allow-root\n",  
                    "       wp config create --dbname='", !Ref DatabaseName, "' --dbuser='", !Ref DatabaseMasterUsername, "' --dbpass='", !Ref DatabaseMasterPassword, "' --dbhost='", !Ref DatabaseClusterEndpointAddress, "' --dbprefix=wp_ --allow-root\n",
                    "       wp core install --url=", !If [ NoWPDomainName, !Ref PublicAlbHostname, !Join [ "", [ "'http://www.", !Ref WPDomainName, "'" ] ] ], " --title='", !Ref WPTitle, "' --admin_user='", !Ref WPAdminUsername, "' --admin_password='", !Ref WPAdminPassword, "' --admin_email='", !Ref WPAdminEmail, "' --skip-email --allow-root\n",
                    "       wp plugin install w3-total-cache --allow-root\n",
                    "       sed -i \"/$table_prefix = 'wp_';/ a \\define('WP_HOME', 'http://' . \\$_SERVER['HTTP_HOST']); \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n",
                    "       sed -i \"/$table_prefix = 'wp_';/ a \\define('WP_SITEURL', 'http://' . \\$_SERVER['HTTP_HOST']); \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n",
                    "       # enable HTTPS in wp-config.php if ACM Public SSL Certificate parameter was not empty\n",
                            !If [ NoSslCertificate, !Join [ '', [ "       sed -i \"/$table_prefix = 'wp_';/ a \\# No ACM Public SSL Certificate \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n" ] ] , !Join [ '', [ "       sed -i \"/$table_prefix = 'wp_';/ a \\$_SERVER['HTTPS'] = 'on';\" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n" ] ] ],
                    "\n",
                    "       # set permissions of wordpress site directories\n", 
                    "       chown -R apache:apache /var/www/wordpress/", !Ref WPDirectory, "\n",
                    "       chmod u+wrx /var/www/wordpress/", !Ref WPDirectory, "/wp-content/*\n",
                    "       if [ ! -f /var/www/wordpress/", !Ref WPDirectory, "/opcache-instanceid.php ]; then\n",
                    "         wget -P /var/www/wordpress/", !Ref WPDirectory, "/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/opcache-instanceid.php\n",
                    "       fi\n",
                  ]
                ]
              mode: 000500
              owner: root
              group: root
        download_aws_ini: 
          files:
            /tmp/download_aws_ini.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -x\n",
                    "\n",
                    "wget -P /etc/php.d/ ", !Ref PHPIniOverride, "\n"
                  ]
                ]
              mode: 000500
              owner: root
              group: root
        install_aws_ini:
          commands:
            install_aws_ini:
              command: ./download_aws_ini.sh
              cwd: /tmp
              ignoreErrors: true
        install_cacheclient:
          commands:
            install_cacheclient:
              command: ./install_cacheclient.sh
              cwd: /tmp
              ignoreErrors: true
        install_opcache:
          commands:
            install_opcache:
              command: ./install_opcache.sh
              cwd: /tmp
              ignoreErrors: true
        install_wordpress:
          commands:
            install_wordpress:
              command: ./install_wordpress.sh
              cwd: /tmp
              ignoreErrors: true
        start_webserver:
          services:
            sysvinit:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      IamInstanceProfile: !Ref WebInstanceProfile
      ImageId: !FindInMap [ RegionMap, !Ref 'AWS::Region', AMI ]
      InstanceMonitoring: true
      InstanceType: !Ref WebInstanceType
      KeyName: !Ref EC2KeyName
      SecurityGroups:
      - !Ref WebSecurityGroup
      UserData:
        "Fn::Base64":
          !Sub |
            #!/bin/bash
            yum update -y
            mkdir -p /var/www/wordpress/${WPDirectory}
            mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${ElasticFileSystem}.efs.${AWS::Region}.amazonaws.com:/ /var/www/wordpress/${WPDirectory}
            /opt/aws/bin/cfn-init --configsets deploy_webserver --verbose --stack ${AWS::StackName} --resource WebLaunchConfiguration80 --region ${AWS::Region}
            /opt/aws/bin/cfn-signal --success true --stack ${AWS::StackName} --resource WebAutoScalingGroup --region ${AWS::Region}
  WebLaunchConfiguration81:
    Condition: PHP81
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          deploy_webserver:
            - install_webserver
            - build_cacheclient
            - build_wordpress
            - build_opcache
            - download_aws_ini
            - install_aws_ini
            - install_cacheclient
            - install_wordpress
            - install_opcache
            - start_webserver
        install_webserver:
          files:
            /tmp/create_site_conf.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -xe\n",
                    "if [ ! -f /etc/httpd/conf.d/", !Ref WPDirectory, ".conf ]; then\n",                    
                    "   touch /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo 'ServerName 127.0.0.1:80' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo 'DocumentRoot /var/www/wordpress/", !Ref WPDirectory, "' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '<Directory /var/www/wordpress/", !Ref WPDirectory, ">' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '  Options Indexes FollowSymLinks' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '  AllowOverride All' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '  Require all granted' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '</Directory>' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "fi\n"
                  ]
                ]
              mode: 000500
              owner: root
              group: root
          commands:
            create_site_conf:
              command: ./create_site_conf.sh
              cwd: /tmp
              ignoreErrors: false
        build_cacheclient:
          files:
            /tmp/install_cacheclient.sh:
              content:
                !Sub |
                  #!/bin/bash -xe
                  pecl install igbinary
                  wget -P /tmp/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/AmazonElastiCacheClusterClient-1.0.0-php81-64bit.tgz
                  tar -xf '/tmp/AmazonElastiCacheClusterClient-1.0.0-php81-64bit.tgz'
                  cp '/tmp/amazon-elasticache-cluster-client.so' /usr/lib64/php/modules/
                  if [ ! -f /etc/php.d/50-memcached.ini ]; then
                      touch /etc/php.d/50-memcached.ini
                  fi
                  echo 'extension=igbinary.so;' >> /etc/php.d/50-memcached.ini
                  echo 'extension=/usr/lib64/php/modules/amazon-elasticache-cluster-client.so;' >> /etc/php.d/50-memcached.ini
                  ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1
                  ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1   
              mode: 000500
              owner: root
              group: root
        build_opcache:
          files:
            /tmp/install_opcache.sh:
              content:
                !Sub |
                  #!/bin/bash -xe
                  # create hidden opcache directory locally & change owner to apache
                  if [ ! -d /var/www/.opcache ]; then                    
                      mkdir -p /var/www/.opcache
                  fi
                  # enable opcache in /etc/php.d/opcache.ini
                  sed -i 's/;opcache.file_cache=.*/opcache.file_cache=\/var\/www\/.opcache/' /etc/php.d/10-opcache.ini
                  sed -i 's/opcache.memory_consumption=.*/opcache.memory_consumption=512/' /etc/php.d/10-opcache.ini
                  # download opcache-instance.php to verify opcache status
                  if [ ! -f /var/www/wordpress/${WPDirectory}/opcache-instanceid.php ]; then
                      wget -P /var/www/wordpress/${WPDirectory}/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/opcache-instanceid.php
                  fi
              mode: 000500
              owner: root
              group: root
        build_wordpress:
          files:
            /tmp/install_wordpress.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -xe\n",
                    "\n",
                    "# install wp-cli\n",
                    "if [ ! -f /bin/wp/wp-cli.phar ]; then\n",
                    "   curl -o /bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar\n",
                    "   chmod +x /bin/wp\n",
                    "fi\n",
                    "\n",
                    "   cd /var/www/wordpress/", !Ref WPDirectory, "\n",
                    "   # install wordpress if not installed\n",
                    "   # use public alb host name if wp domain name was empty\n",
                    "       wp core download --version='", !Ref WPVersion, "' --locale='", !Ref WPLocale, "' --allow-root\n",  
                    "       wp config create --dbname='", !Ref DatabaseName, "' --dbuser='", !Ref DatabaseMasterUsername, "' --dbpass='", !Ref DatabaseMasterPassword, "' --dbhost='", !Ref DatabaseClusterEndpointAddress, "' --dbprefix=wp_ --allow-root\n",
                    "       wp core install --url=", !If [ NoWPDomainName, !Ref PublicAlbHostname, !Join [ "", [ "'http://www.", !Ref WPDomainName, "'" ] ] ], " --title='", !Ref WPTitle, "' --admin_user='", !Ref WPAdminUsername, "' --admin_password='", !Ref WPAdminPassword, "' --admin_email='", !Ref WPAdminEmail, "' --skip-email --allow-root\n",
                    "       wp plugin install w3-total-cache --allow-root\n",
                    "       sed -i \"/$table_prefix = 'wp_';/ a \\define('WP_HOME', 'http://' . \\$_SERVER['HTTP_HOST']); \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n",
                    "       sed -i \"/$table_prefix = 'wp_';/ a \\define('WP_SITEURL', 'http://' . \\$_SERVER['HTTP_HOST']); \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n",
                    "       # enable HTTPS in wp-config.php if ACM Public SSL Certificate parameter was not empty\n",
                            !If [ NoSslCertificate, !Join [ '', [ "       sed -i \"/$table_prefix = 'wp_';/ a \\# No ACM Public SSL Certificate \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n" ] ] , !Join [ '', [ "       sed -i \"/$table_prefix = 'wp_';/ a \\$_SERVER['HTTPS'] = 'on';\" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n" ] ] ],
                    "\n",
                    "       # set permissions of wordpress site directories\n", 
                    "       chown -R apache:apache /var/www/wordpress/", !Ref WPDirectory, "\n",
                    "       chmod u+wrx /var/www/wordpress/", !Ref WPDirectory, "/wp-content/*\n",
                    "       if [ ! -f /var/www/wordpress/", !Ref WPDirectory, "/opcache-instanceid.php ]; then\n",
                    "         wget -P /var/www/wordpress/", !Ref WPDirectory, "/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/opcache-instanceid.php\n",
                    "       fi\n",
                  ]
                ]
              mode: 000500
              owner: root
              group: root
        download_aws_ini: 
          files:
            /tmp/download_aws_ini.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -x\n",
                    "\n",
                    "wget -P /etc/php.d/ ", !Ref PHPIniOverride, "\n"
                  ]
                ]
              mode: 000500
              owner: root
              group: root
        install_aws_ini:
          commands:
            install_aws_ini:
              command: ./download_aws_ini.sh
              cwd: /tmp
              ignoreErrors: true
        install_cacheclient:
          commands:
            install_cacheclient:
              command: ./install_cacheclient.sh
              cwd: /tmp
              ignoreErrors: false
        install_wordpress:
          commands:
            install_wordpress:
              command: ./install_wordpress.sh
              cwd: /tmp
              ignoreErrors: false          
        install_opcache:
          commands:
            install_opcache:
              command: ./install_opcache.sh
              cwd: /tmp
              ignoreErrors: false
        start_webserver:
          services:
            sysvinit:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      IamInstanceProfile: !Ref WebInstanceProfile
      ImageId: !FindInMap [ RegionMap, !Ref 'AWS::Region', AMI ]
      InstanceMonitoring: true
      InstanceType: !Ref WebInstanceType
      KeyName: !Ref EC2KeyName
      SecurityGroups:
      - !Ref WebSecurityGroup
      UserData:
        "Fn::Base64":
          !Sub |
            #!/bin/bash
            yum update -y
            mkdir -p /var/www/wordpress/${WPDirectory}
            mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${ElasticFileSystem}.efs.${AWS::Region}.amazonaws.com:/ /var/www/wordpress/${WPDirectory}
            /opt/aws/bin/cfn-init --configsets deploy_webserver --verbose --stack ${AWS::StackName} --resource WebLaunchConfiguration81 --region ${AWS::Region}
            /opt/aws/bin/cfn-signal --success true --stack ${AWS::StackName} --resource WebAutoScalingGroup --region ${AWS::Region}
  WebLaunchConfiguration74:
    Condition: PHP74
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          deploy_webserver:
            - install_webserver
            - build_cacheclient
            - build_wordpress
            - build_opcache
            - download_aws_ini
            - install_aws_ini
            - install_cacheclient
            - install_wordpress
            - install_opcache
            - start_webserver
        install_webserver:
          files:
            /tmp/create_site_conf.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -xe\n",
                    "if [ ! -f /etc/httpd/conf.d/", !Ref WPDirectory, ".conf ]; then\n",                    
                    "   touch /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo 'ServerName 127.0.0.1:80' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo 'DocumentRoot /var/www/wordpress/", !Ref WPDirectory, "' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '<Directory /var/www/wordpress/", !Ref WPDirectory, ">' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '  Options Indexes FollowSymLinks' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '  AllowOverride All' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '  Require all granted' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "   echo '</Directory>' >> /etc/httpd/conf.d/", !Ref WPDirectory, ".conf\n",
                    "fi\n"
                  ]
                ]
              mode: 000500
              owner: root
              group: root
          commands:
            create_site_conf:
              command: ./create_site_conf.sh
              cwd: /tmp
              ignoreErrors: false
        build_cacheclient:
          packages:
            yum:
              gcc-c++: []  
          files:
            /tmp/install_cacheclient.sh:
              content:
                !Sub |
                  #!/bin/bash -xe
                  ln -s /usr/bin/pecl7 /usr/bin/pecl #just so pecl is available easily
                  pecl7 install igbinary
                  wget -P /tmp/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/AmazonElastiCacheClusterClient-2.0.1-PHP74-64bit.tar.gz
                  tar -xf '/tmp/AmazonElastiCacheClusterClient-2.0.1-PHP74-64bit.tar.gz'
                  cp '/tmp/artifact/amazon-elasticache-cluster-client.so' /usr/lib64/php/modules/
                  if [ ! -f /etc/php.d/50-memcached.ini ]; then
                      touch /etc/php.d/50-memcached.ini
                  fi
                  echo 'extension=igbinary.so;' >> /etc/php-7.0.d/50-memcached.ini
                  echo 'extension=/usr/lib64/php/modules/amazon-elasticache-cluster-client.so;' >> /etc/php.d/50-memcached.ini
                  pecl install igbinary
                  cd /tmp
                  wget -P /tmp/ https://www.openssl.org/source/openssl-1.1.1c.tar.gz
                  tar xvf openssl-1.1.1c.tar.gz
                  cd openssl-1.1.1c
                  ./config
                  make
                  make install
                  ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1
                  ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1   
              mode: 000500
              owner: root
              group: root
        build_opcache:
          files:
            /tmp/install_opcache.sh:
              content:
                !Sub |
                  #!/bin/bash -xe
                  # create hidden opcache directory locally & change owner to apache
                  if [ ! -d /var/www/.opcache ]; then                    
                      mkdir -p /var/www/.opcache
                  fi
                  # enable opcache in /etc/php.d/10-opcache.ini
                  sed -i 's/;opcache.file_cache=.*/opcache.file_cache=\/var\/www\/.opcache/' /etc/php.d/10-opcache.ini
                  sed -i 's/opcache.memory_consumption=.*/opcache.memory_consumption=512/' /etc/php.d/10-opcache.ini
                  # download opcache-instance.php to verify opcache status
                  if [ ! -f /var/www/wordpress/${WPDirectory}/opcache-instanceid.php ]; then
                      wget -P /var/www/wordpress/${WPDirectory}/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/opcache-instanceid.php
                  fi
              mode: 000500
              owner: root
              group: root
        build_wordpress:
          files:
            /tmp/install_wordpress.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -xe\n",
                    "\n",
                    "# install wp-cli\n",
                    "if [ ! -f /bin/wp/wp-cli.phar ]; then\n",
                    "   curl -o /bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar\n",
                    "   chmod +x /bin/wp\n",
                    "fi\n",
                    "\n",
                    "   cd /var/www/wordpress/", !Ref WPDirectory, "\n",
                    "   # install wordpress if not installed\n",
                    "   # use public alb host name if wp domain name was empty\n",
                    "       wp core download --version='", !Ref WPVersion, "' --locale='", !Ref WPLocale, "' --allow-root\n",  
                    "       wp config create --dbname='", !Ref DatabaseName, "' --dbuser='", !Ref DatabaseMasterUsername, "' --dbpass='", !Ref DatabaseMasterPassword, "' --dbhost='", !Ref DatabaseClusterEndpointAddress, "' --dbprefix=wp_ --allow-root\n",
                    "       wp core install --url=", !If [ NoWPDomainName, !Ref PublicAlbHostname, !Join [ "", [ "'http://www.", !Ref WPDomainName, "'" ] ] ], " --title='", !Ref WPTitle, "' --admin_user='", !Ref WPAdminUsername, "' --admin_password='", !Ref WPAdminPassword, "' --admin_email='", !Ref WPAdminEmail, "' --skip-email --allow-root\n",
                    "       wp plugin install w3-total-cache\n",
                    "       sed -i \"/$table_prefix = 'wp_';/ a \\define('WP_HOME', 'http://' . \\$_SERVER['HTTP_HOST']); \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n",
                    "       sed -i \"/$table_prefix = 'wp_';/ a \\define('WP_SITEURL', 'http://' . \\$_SERVER['HTTP_HOST']); \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n",
                    "       # enable HTTPS in wp-config.php if ACM Public SSL Certificate parameter was not empty\n",
                            !If [ NoSslCertificate, !Join [ '', [ "       sed -i \"/$table_prefix = 'wp_';/ a \\# No ACM Public SSL Certificate \" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n" ] ] , !Join [ '', [ "       sed -i \"/$table_prefix = 'wp_';/ a \\$_SERVER['HTTPS'] = 'on';\" /var/www/wordpress/", !Ref WPDirectory, "/wp-config.php\n" ] ] ],
                    "\n",
                    "       # set permissions of wordpress site directories\n", 
                    "       chown -R apache:apache /var/www/wordpress/", !Ref WPDirectory, "\n",
                    "       chmod u+wrx /var/www/wordpress/", !Ref WPDirectory, "/wp-content/*\n",
                    "       if [ ! -f /var/www/wordpress/", !Ref WPDirectory, "/opcache-instanceid.php ]; then\n",
                    "         wget -P /var/www/wordpress/", !Ref WPDirectory, "/ https://s3.amazonaws.com/aws-refarch/wordpress/latest/bits/opcache-instanceid.php\n",
                    "       fi\n",
                  ]
                ]
              mode: 000500
              owner: root
              group: root
        download_aws_ini: 
          files:
            /tmp/download_aws_ini.sh:
              content:
                !Join [
                  "",[
                    "#!/bin/bash -x\n",
                    "\n",
                    "wget -P /etc/php.d/ ", !Ref PHPIniOverride, "\n"
                  ]
                ]
              mode: 000500
              owner: root
              group: root
        install_aws_ini:
          commands:
            install_aws_ini:
              command: ./download_aws_ini.sh
              cwd: /tmp
              ignoreErrors: true
        install_wordpress:
          commands:
            install_wordpress:
              command: ./install_wordpress.sh
              cwd: /tmp
              ignoreErrors: false          
        install_cacheclient:
          commands:
            install_cacheclient:
              command: ./install_cacheclient.sh
              cwd: /tmp
              ignoreErrors: false
        install_opcache:
          commands:
            install_opcache:
              command: ./install_opcache.sh
              cwd: /tmp
              ignoreErrors: false
        start_webserver:
          services:
            sysvinit:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      IamInstanceProfile: !Ref WebInstanceProfile
      ImageId: !FindInMap [ RegionMap, !Ref 'AWS::Region', AMI ]
      InstanceMonitoring: true
      InstanceType: !Ref WebInstanceType
      KeyName: !Ref EC2KeyName
      SecurityGroups:
      - !Ref WebSecurityGroup
      UserData:
        "Fn::Base64":
          !Sub |
            yum update -y
            amazon-linux-extras enable python3.8 mariadb10.5 php7.4
            yum clean metadata
            yum install php
            yum -y install php-cli php-pdo php-devel php-mysqlnd php-pear php-opcache
            yum install -y awslogs
            yum install -y python38
            yum install -y gcc perl-core pcre-devel zlib-devel
            yum install -y gcc-c++
            yum install -y php-opcache.x86_64
            yum install -y mariadb 
            mkdir -p /var/www/wordpress/${WPDirectory}
            mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${ElasticFileSystem}.efs.${AWS::Region}.amazonaws.com:/ /var/www/wordpress
            /opt/aws/bin/cfn-init --configsets deploy_webserver --verbose --stack ${AWS::StackName} --resource WebLaunchConfiguration74 --region ${AWS::Region}
            /opt/aws/bin/cfn-signal --exit-code $? --stack ${AWS::StackName} --resource WebAutoScalingGroup --region ${AWS::Region}


Outputs:

  Opcachestatus:
    Value: !Join [ '', [ !Ref PublicAlbHostname, '/opcache-instanceid.php' ] ]
