Bỏ qua

20.Wordpress Ec2 2

1-Click Deployment
Description: Animals4Life base VPC Template + Public Instance
Parameters:
  LatestAmiId:
    Description: AMI for EC2 (default is latest AmaLinux2023)
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.16.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: a4l-vpc1
  IPv6CidrBlock:
    Type: AWS::EC2::VPCCidrBlock
    Properties:
      VpcId: !Ref VPC
      AmazonProvidedIpv6CidrBlock: true
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: A4L-vpc1-igw
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  RouteTableWeb:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: A4L-vpc1-rt-web
  RouteTableWebDefaultIPv4:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTableWeb
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  RouteTableWebDefaultIPv6:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTableWeb
      DestinationIpv6CidrBlock: '::/0'
      GatewayId: !Ref InternetGateway
  RouteTableAssociationWebA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetWEBA
      RouteTableId: !Ref RouteTableWeb
  RouteTableAssociationWebB:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetWEBB
      RouteTableId: !Ref RouteTableWeb
  RouteTableAssociationWebC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SubnetWEBC
      RouteTableId: !Ref RouteTableWeb
  SubnetReservedA:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 0
        - !GetAZs ''
      CidrBlock: 10.16.0.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 00::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-reserved-A
  SubnetReservedB:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 1
        - !GetAZs ''
      CidrBlock: 10.16.64.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 04::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-reserved-B
  SubnetReservedC:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 2
        - !GetAZs ''
      CidrBlock: 10.16.128.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 08::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-reserved-C
  SubnetDBA:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 0
        - !GetAZs ''
      CidrBlock: 10.16.16.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 01::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-db-A
  SubnetDBB:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 1
        - !GetAZs ''
      CidrBlock: 10.16.80.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 05::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-db-B
  SubnetDBC:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 2
        - !GetAZs ''
      CidrBlock: 10.16.144.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 09::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-db-C
  SubnetAPPA:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 0
        - !GetAZs ''
      CidrBlock: 10.16.32.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 02::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-app-A
  SubnetAPPB:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 1
        - !GetAZs ''
      CidrBlock: 10.16.96.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 06::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-app-B
  SubnetAPPC:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 2
        - !GetAZs ''
      CidrBlock: 10.16.160.0/20
      AssignIpv6AddressOnCreation: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 0A::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-app-C
  SubnetWEBA:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 0
        - !GetAZs ''
      CidrBlock: 10.16.48.0/20
      MapPublicIpOnLaunch: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 03::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-web-A
  SubnetWEBB:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 1
        - !GetAZs ''
      CidrBlock: 10.16.112.0/20
      MapPublicIpOnLaunch: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 07::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-web-B
  SubnetWEBC:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select
        - 2
        - !GetAZs ''
      CidrBlock: 10.16.176.0/20
      MapPublicIpOnLaunch: true
      Ipv6CidrBlock: !Sub
        - ${VpcPart}${SubnetPart}
        - SubnetPart: 0B::/64
          VpcPart: !Select
            - 0
            - !Split
              - 00::/56
              - !Select
                - 0
                - !GetAtt VPC.Ipv6CidrBlocks
      Tags:
        - Key: Name
          Value: sn-web-C
  IPv6WorkaroundSubnetWEBA:
    Type: Custom::SubnetModify
    Properties:
      ServiceToken: !GetAtt IPv6WorkaroundLambda.Arn
      SubnetId: !Ref SubnetWEBA
  IPv6WorkaroundSubnetWEBB:
    Type: Custom::SubnetModify
    Properties:
      ServiceToken: !GetAtt IPv6WorkaroundLambda.Arn
      SubnetId: !Ref SubnetWEBB
  IPv6WorkaroundSubnetWEBC:
    Type: Custom::SubnetModify
    Properties:
      ServiceToken: !GetAtt IPv6WorkaroundLambda.Arn
      SubnetId: !Ref SubnetWEBC
  IPv6WorkaroundRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: !Sub ipv6-fix-logs-${AWS::StackName}
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
        - PolicyName: !Sub ipv6-fix-modify-${AWS::StackName}
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ec2:ModifySubnetAttribute
                Resource: '*'
  IPv6WorkaroundLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.lambda_handler
      Code:
        #import cfnresponse below required to send respose back to CFN
        ZipFile: !Sub |
          import cfnresponse
          import boto3

          def lambda_handler(event, context):
            if event['RequestType'] is 'Delete':
              cfnresponse.send(event, context, cfnresponse.SUCCESS)
              return

            responseValue = event['ResourceProperties']['SubnetId']
            ec2 = boto3.client('ec2', region_name='${AWS::Region}')
            ec2.modify_subnet_attribute(AssignIpv6AddressOnCreation={
                            'Value': True
                            },
                            SubnetId=responseValue)
            responseData = {}
            responseData['SubnetId'] = responseValue
            cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
      Runtime: python3.9
      Role: !GetAtt IPv6WorkaroundRole.Arn
      Timeout: 30
  PublicEC2:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: !Ref LatestAmiId
      IamInstanceProfile: !Ref SessionManagerInstanceProfile
      SubnetId: !Ref SubnetWEBA
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
      Tags:
        - Key: Name
          Value: A4L-PublicEC2
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC
      GroupDescription: Enable SSH access via port 22 IPv4 & v6
      SecurityGroupIngress:
        - Description: Allow SSH IPv4 IN
          IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 0.0.0.0/0
        - Description: Allow HTTP IPv4 IN
          IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0
        - Description: Allow SSH IPv6 IN
          IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIpv6: '::/0'
  SessionManagerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ssm:DescribeAssociation
                  - ssm:GetDeployablePatchSnapshotForInstance
                  - ssm:GetDocument
                  - ssm:DescribeDocument
                  - ssm:GetManifest
                  - ssm:GetParameter
                  - ssm:GetParameters
                  - ssm:ListAssociations
                  - ssm:ListInstanceAssociations
                  - ssm:PutInventory
                  - ssm:PutComplianceItems
                  - ssm:PutConfigurePackageResult
                  - ssm:UpdateAssociationStatus
                  - ssm:UpdateInstanceAssociationStatus
                  - ssm:UpdateInstanceInformation
                Resource: '*'
              - Effect: Allow
                Action:
                  - ssmmessages:CreateControlChannel
                  - ssmmessages:CreateDataChannel
                  - ssmmessages:OpenControlChannel
                  - ssmmessages:OpenDataChannel
                Resource: '*'
              - Effect: Allow
                Action:
                  - ec2messages:AcknowledgeMessage
                  - ec2messages:DeleteMessage
                  - ec2messages:FailMessage
                  - ec2messages:GetEndpoint
                  - ec2messages:GetMessages
                  - ec2messages:SendReply
                Resource: '*'
  SessionManagerInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref SessionManagerRole
Outputs:
  a4lvpc1:
    Description: Animals4Life VPC1_ID
    Value: !Ref VPC
    Export:
      Name: a4l-vpc1
  a4lvpc1subnetweba:
    Description: Animals4Life VPC1 SubnetWEBA
    Value: !Ref SubnetWEBA
    Export:
      Name: a4l-vpc1-subnet-weba
  a4lvpc1subnetwebb:
    Description: Animals4Life VPC1 SubnetWEBB
    Value: !Ref SubnetWEBB
    Export:
      Name: a4l-vpc1-subnet-webb
  a4lvpc1subnetwebc:
    Description: Animals4Life VPC1 SubnetWEBC
    Value: !Ref SubnetWEBC
    Export:
      Name: a4l-vpc1-subnet-webc
  a4lvpc1subnetappa:
    Description: Animals4Life VPC1 SubnetAPPA
    Value: !Ref SubnetAPPA
    Export:
      Name: a4l-vpc1-subnet-appa
  a4lvpc1subnetappb:
    Description: Animals4Life VPC1 SubnetAPPB
    Value: !Ref SubnetAPPB
    Export:
      Name: a4l-vpc1-subnet-appb
  a4lvpc1subnetappc:
    Description: Animals4Life VPC1 SubnetAPPC
    Value: !Ref SubnetAPPC
    Export:
      Name: a4l-vpc1-subnet-appc
  a4lvpc1subnetdba:
    Description: Animals4Life VPC1 SubnetDBA
    Value: !Ref SubnetDBA
    Export:
      Name: a4l-vpc1-subnet-dba
  a4lvpc1subnetdbb:
    Description: Animals4Life VPC1 SubnetDBB
    Value: !Ref SubnetDBB
    Export:
      Name: a4l-vpc1-subnet-dbb
  a4lvpc1subnetdbc:
    Description: Animals4Life VPC1 SubnetDBC
    Value: !Ref SubnetDBC
    Export:
      Name: a4l-vpc1-subnet-dbc
  a4lvpc1subnetreserveda:
    Description: Animals4Life VPC1 SubnetReservedA
    Value: !Ref SubnetReservedA
    Export:
      Name: a4l-vpc1-subnet-reserveda
  a4lvpc1subnetreservedb:
    Description: Animals4Life VPC1 SubnetReservedB
    Value: !Ref SubnetReservedB
    Export:
      Name: a4l-vpc1-subnet-reservedb
  a4lvpc1subnetreservedc:
    Description: Animals4Life VPC1 SubnetReservedC
    Value: !Ref SubnetReservedC
    Export:
      Name: a4l-vpc1-subnet-reservedc

https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?templateURL=https://learn-cantrill-labs.s3.amazonaws.com/awscoursedemos/0006-aws-associate-ec2-wordpress-on-ec2/A4L_VPC_PUBLICINSTANCE_AL2023.yaml&stackName=WORDPRESS

Lesson Commands
# DBName=database name for wordpress
# DBUser=mariadb user for wordpress
# DBPassword=password for the mariadb user for wordpress
# DBRootPassword = root password for mariadb

# STEP 1 - Configure Authentication Variables which are used below
DBName='a4lwordpress'
DBUser='a4lwordpress'
DBPassword='4n1m4l$4L1f3'
DBRootPassword='4n1m4l$4L1f3'

# STEP 2 - Install system software - including Web and DB
sudo dnf install wget php-mysqlnd httpd php-fpm php-mysqli mariadb105-server php-json php php-devel -y


# STEP 3 - Web and DB Servers Online - and set to startup

sudo systemctl enable httpd
sudo systemctl enable mariadb
sudo systemctl start httpd
sudo systemctl start mariadb


# STEP 4 - Set Mariadb Root Password
sudo mysqladmin -u root password $DBRootPassword


# STEP 5 - Install Wordpress
sudo wget http://wordpress.org/latest.tar.gz -P /var/www/html
cd /var/www/html
sudo tar -zxvf latest.tar.gz
sudo cp -rvf wordpress/* .
sudo rm -R wordpress
sudo rm latest.tar.gz


# STEP 6 - Configure Wordpress

sudo cp ./wp-config-sample.php ./wp-config.php
sudo sed -i "s/'database_name_here'/'$DBName'/g" wp-config.php
sudo sed -i "s/'username_here'/'$DBUser'/g" wp-config.php
sudo sed -i "s/'password_here'/'$DBPassword'/g" wp-config.php   
sudo chown apache:apache * -R


# STEP 7 Create Wordpress DB

echo "CREATE DATABASE $DBName;" >> /tmp/db.setup
echo "CREATE USER '$DBUser'@'localhost' IDENTIFIED BY '$DBPassword';" >> /tmp/db.setup
echo "GRANT ALL ON $DBName.* TO '$DBUser'@'localhost';" >> /tmp/db.setup
echo "FLUSH PRIVILEGES;" >> /tmp/db.setup
mysql -u root --password=$DBRootPassword < /tmp/db.setup
sudo rm /tmp/db.setup


# STEP 8 - Browse to http://your_instance_public_ipv4_ip

https://learn-cantrill-labs.s3.amazonaws.com/awscoursedemos/0006-aws-associate-ec2-wordpress-on-ec2/lesson_commands_AL2023.txt

Blog Images https://learn-cantrill-labs.s3.amazonaws.com/awscoursedemos/0006-aws-associate-ec2-wordpress-on-ec2/blogimages.zip

💻 Cài đặt WordPress thủ công trên EC2 – Phần 2 (Hoàn thiện & test)


1. Cấu hình WordPress (wp-config.php)

  1. Đổi tên file cấu hình mẫu:

    sudo cp wp-config-sample.php wp-config.php
    
  2. Tự động thay thế giá trị cấu hình bằng biến đã đặt:

    # Điền tên database
    sudo sed -i "s/database_name_here/$DB_NAME/" wp-config.php
    
    # Điền username database
    sudo sed -i "s/username_here/$DB_USER/" wp-config.php
    
    # Điền mật khẩu database
    sudo sed -i "s/password_here/$DB_PASSWORD/" wp-config.php
    
  3. Phân quyền file/folder cho web server:

    sudo chown -R apache:apache /var/www/html
    

2. Tạo Database, User và Phân quyền cho WordPress

  1. Tạo script SQL để tạo database/user:

    echo "CREATE DATABASE $DB_NAME;" > /tmp/dbsetup.sql
    echo "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';" >> /tmp/dbsetup.sql
    echo "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';" >> /tmp/dbsetup.sql
    echo "FLUSH PRIVILEGES;" >> /tmp/dbsetup.sql
    
  2. Chạy script SQL qua MariaDB:

    sudo mysql -u root -p"$DB_ROOT_PASSWORD" < /tmp/dbsetup.sql
    
  3. Xóa script chứa thông tin nhạy cảm:

    rm -f /tmp/dbsetup.sql
    

3. Kiểm tra cài đặt WordPress

  1. Lấy IP public của EC2 từ console.
  2. Mở trình duyệt, truy cập:
    http://<EC2-PUBLIC-IP>
    
  3. Hoàn tất wizard cài đặt:

    • Chọn ngôn ngữ: English (United States)
    • Blog title: “All the cats”
    • Username: admin
    • Password: (copy từ wizard, dùng để login)
    • Email: test@test.com
    • Nhấn Install WordPress
    • Đăng nhập với username/password vừa tạo
  4. Kiểm tra giao diện:

    • Vào “All the cats” → Visit site
    • Trang WordPress đã hoạt động!

4. Dọn dẹp tài nguyên AWS (Clean up)

  1. Xóa stack CloudFormation để gỡ toàn bộ hạ tầng demo:
    • AWS Console > CloudFormation > Chọn stack WordPress > Delete

5. Tổng kết & bài học kinh nghiệm

  • Bạn đã cài đặt WordPress thủ công trên một EC2 duy nhất (monolithic).
  • Quy trình này rất dễ lỗi, tốn thời gian, không lặp lại được nếu làm nhiều lần.
  • Thực tế, nên dùng automation (CloudFormation, Ansible, AMI, ...).
  • Các bài học tiếp theo sẽ hướng dẫn bạn tự động hóa cài đặt và triển khai WordPress trên AWS.