From e91c72ea2bb4bc040c240b13ef66fdbdd78ac759 Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Wed, 25 Mar 2020 13:00:30 +0800 Subject: [PATCH 1/8] Remove default parameters So other people will be prompted for their parameter overrides --- template.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/template.yaml b/template.yaml index 7b9af8c..d2f9f93 100644 --- a/template.yaml +++ b/template.yaml @@ -5,10 +5,8 @@ Transform: AWS::Serverless-2016-10-31 Parameters: VpcSecurityGroupIds: Type: 'List' - Default: 'sg-53af6735' VpcSubnetIds: Type: 'List' - Default: 'subnet-0dcd7a44,subnet-a8757ef0,subnet-b19c01d6' StageName: Type: String Default: 'Prod' From f1f410bb4526096fca60171c7b71d50f90d170d2 Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Wed, 25 Mar 2020 13:02:59 +0800 Subject: [PATCH 2/8] Refactor template Use Sub functions to make it easier to read --- template.yaml | 49 +++++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/template.yaml b/template.yaml index d2f9f93..88f993c 100644 --- a/template.yaml +++ b/template.yaml @@ -28,8 +28,8 @@ Resources: Tracing: Active Layers: # - arn:aws:lambda:us-west-2:887080169480:layer:php73:2 - - arn:aws:lambda:us-west-2:777160072469:layer:php73:11 - + - !Sub "arn:aws:lambda:${AWS::Region}:887080169480:layer:php73:3" + Environment: Variables: S3_UPLOADS_BUCKET: !Ref assetsS3 @@ -76,34 +76,24 @@ Resources: DistributionConfig: Origins: - Id: PhpServer - DomainName: !Join - - '' - - - !Ref restapi - - '.execute-api.' - - !Ref AWS::Region - - '.amazonaws.com' + DomainName: !Sub "${restapi}.execute-api.${AWS::Region}.amazonaws.com" CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 OriginProtocolPolicy: https-only - OriginPath: !Join ['', ['/', !Ref StageName]] - + OriginPath: !Sub "/${StageName}" + - Id: Assets - DomainName: !Join - - "" - - - !Ref assetsS3 - - ".s3-" - - !Ref AWS::Region - - ".amazonaws.com" + DomainName: !Sub "${assetsS3}.s3-${AWS::Region}.amazonaws.com" S3OriginConfig: - OriginAccessIdentity: !Join [ '', [ 'origin-access-identity/cloudfront/', !Ref cfOriginAccessIdentity ]] + OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${cfOriginAccessIdentity}" Enabled: 'true' IPV6Enabled: 'true' HttpVersion: 'http2' PriceClass: !Ref CloudFrontPriceClass - + CustomErrorResponses: - ErrorCode: 404 ErrorCachingMinTTL: 0 @@ -162,7 +152,7 @@ Resources: Forward: 'none' TargetOriginId: Assets ViewerProtocolPolicy: redirect-to-https - + - PathPattern: "*.jpeg" AllowedMethods: - GET @@ -247,7 +237,7 @@ Resources: assetsS3: Type: AWS::S3::Bucket - + assetsS3BucketPolicy: Type: AWS::S3::BucketPolicy Properties: @@ -257,14 +247,10 @@ Resources: - Sid: CloudFrontOrigin Effect: Allow Principal: - CanonicalUser: !GetAtt cfOriginAccessIdentity.S3CanonicalUserId + CanonicalUser: !Sub "${cfOriginAccessIdentity.S3CanonicalUserId}" Action: - s3:GetObject - Resource: !Join - - '' - - - 'arn:aws:s3:::' - - !Ref assetsS3 - - '/*' + Resource: !Sub "${assetsS3.Arn}/*" cfOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity @@ -274,18 +260,13 @@ Resources: Outputs: RestApiDomainName: - Value: !Join - - '' - - - !Ref restapi - - '.execute-api.' - - !Ref AWS::Region - - '.amazonaws.com' - + Value: !Sub "${restapi}.execute-api.${AWS::Region}.amazonaws.com" + CloudFrontDistributionId: Value: !Ref cloudfront CloudFrontDistributionDomainName: Value: !GetAtt cloudfront.DomainName - + AssetsBucketName: Value: !Ref assetsS3 From d37b194f8e7332d88f1e3d7838de97502ff70adc Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Wed, 25 Mar 2020 15:01:17 +0800 Subject: [PATCH 3/8] Ignore samconfig.toml --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 339eaae..d2ccf21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ src/php/wp-config.php serverless-output.yaml +samconfig.toml From 9256f56de50ae6a66015086f76953e95eb6c4b06 Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Wed, 25 Mar 2020 15:03:03 +0800 Subject: [PATCH 4/8] Update template.yaml - Add dbCluster - Add Security Groups - Remove VpcSecurityGroupIds parameter - Add VpcId and database parameters - Configure phpserver to work with database directly --- template.yaml | 86 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/template.yaml b/template.yaml index 88f993c..2b0d1c1 100644 --- a/template.yaml +++ b/template.yaml @@ -3,8 +3,9 @@ Description: WordPress on AWS Lambda! Transform: AWS::Serverless-2016-10-31 Parameters: - VpcSecurityGroupIds: - Type: 'List' + VpcId: + Description: The default VPC ID in the region you're deploying to. + Type: 'AWS::EC2::VPC::Id' VpcSubnetIds: Type: 'List' StageName: @@ -13,6 +14,29 @@ Parameters: CloudFrontPriceClass: Type: String Default: 'PriceClass_200' + DBName: + Default: wordpressdb + Description: The WordPress database name. + Type: String + MinLength: '1' + MaxLength: '64' + AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' + ConstraintDescription: must begin with a letter and contain only alphanumeric characters. + DBUser: + Default: admin + NoEcho: 'true' + Description: The WordPress database admin account username + Type: String + MinLength: '1' + MaxLength: '16' + AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' + ConstraintDescription: must begin with a letter and contain only alphanumeric characters. + DBPassword: + NoEcho: 'true' + Description: The WordPress database admin account password. The password validation regex varies for different wordpress versions. + Type: String + MinLength: '8' + MaxLength: '41' Resources: phpserver: @@ -33,6 +57,12 @@ Resources: Environment: Variables: S3_UPLOADS_BUCKET: !Ref assetsS3 + DATABASE_ENDPOINT: !GetAtt [dbCluster, Endpoint.Address] + DATABASE_NAME: !Ref DBName + DATABASE_USER: !Ref DBUser + # Comment out the line below or use KMS if you have requirements for security. + # Otherwise, security groups should be secure enough for networking. + DATABASE_PASS: !Ref DBPassword Policies: - VPCAccessPolicy: {} @@ -56,9 +86,25 @@ Resources: # Comment this out to run in public mode. VpcConfig: - SecurityGroupIds: !Ref VpcSecurityGroupIds + SecurityGroupIds: + - !GetAtt phpserverSecurityGroup.GroupId SubnetIds: !Ref VpcSubnetIds + phpserverSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: >- + Security group for lambda + VpcId: !Ref VpcId + + phpserverSecurityGroupIngress: + Type: AWS::EC2::SecurityGroupIngress + DependsOn: phpserverSecurityGroup + Properties: + GroupId: !Ref phpserverSecurityGroup + IpProtocol: '-1' + SourceSecurityGroupId: !Ref phpserverSecurityGroup + restapi: Type: AWS::Serverless::Api DeletionPolicy: "Retain" @@ -258,6 +304,34 @@ Resources: CloudFrontOriginAccessIdentityConfig: Comment: The Origin Access Identity to allow CloudFront to serve static files from the assets bucket (WordPress on Lambda) + dbSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Open database for access + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: '3306' + ToPort: '3306' + SourceSecurityGroupId: !GetAtt phpserverSecurityGroup.GroupId + VpcId: !Ref VpcId + + dbCluster: + Type: AWS::RDS::DBCluster + Properties: + DBClusterIdentifier: !Join ["-", [!Ref "AWS::StackName", !Select [0, !Split ["-", !Select [2, !Split ["/", !Ref "AWS::StackId"]]]]]] + DatabaseName: !Ref DBName + MasterUsername: !Ref DBUser + MasterUserPassword: !Ref DBPassword + Engine: aurora + EngineMode: serverless + ScalingConfiguration: + AutoPause: true + MaxCapacity: 16 + MinCapacity: 1 + SecondsUntilAutoPause: 300 + VpcSecurityGroupIds: + - !GetAtt dbSecurityGroup.GroupId + Outputs: RestApiDomainName: Value: !Sub "${restapi}.execute-api.${AWS::Region}.amazonaws.com" @@ -270,3 +344,9 @@ Outputs: AssetsBucketName: Value: !Ref assetsS3 + + DatabaseEndpoint: + Value: !GetAtt [dbCluster, Endpoint.Address] + + DatabaseName: + Value: !Ref DBName From e567817d8c427622d36fd909182d34a7d1b2ce32 Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Wed, 25 Mar 2020 15:03:33 +0800 Subject: [PATCH 5/8] Update wp-config-sample.php Use connection from dbCluster --- src/php/wp-config-sample.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/php/wp-config-sample.php b/src/php/wp-config-sample.php index 9b3d4c7..bfc4838 100644 --- a/src/php/wp-config-sample.php +++ b/src/php/wp-config-sample.php @@ -20,16 +20,16 @@ // ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ -define( 'DB_NAME', 'database_name_here' ); +define( 'DB_NAME', getenv('DATABASE_NAME') ); /** MySQL database username */ -define( 'DB_USER', 'username_here' ); +define( 'DB_USER', getenv('DATABASE_USER') ); /** MySQL database password */ -define( 'DB_PASSWORD', 'password_here' ); +define( 'DB_PASSWORD', getenv('DATABASE_PASS') ); /** MySQL hostname */ -define( 'DB_HOST', 'localhost' ); +define( 'DB_HOST', getenv('DATABASE_ENDPOINT') ); /** Database Charset to use in creating database tables. */ define( 'DB_CHARSET', 'utf8' ); @@ -37,9 +37,9 @@ /** The Database Collate type. Don't change this if in doubt. */ define( 'DB_COLLATE', '' ); -define('WP_SITEURL', 'https://[CLOUDFRONT DOMAIN NAME HERE]'); -define('WP_HOME', 'https://[CLOUDFRONT DOMAIN NAME HERE]'); -$_SERVER['HTTP_HOST'] = '[CLOUDFRONT DOMAIN NAME HERE]'; +define('WP_SITEURL', 'https://cloudfront_domain_name_here'); +define('WP_HOME', 'https://cloudfront_domain_name_here'); +$_SERVER['HTTP_HOST'] = 'cloudfront_domain_name_here'; define( 'S3_UPLOADS_BUCKET', getenv('S3_UPLOADS_BUCKET') . '/wp-content' ); define( 'S3_UPLOADS_USE_INSTANCE_PROFILE', true ); From 3404d7383a335ca1ec7203db7592c6ed928d6ccd Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Wed, 25 Mar 2020 15:14:48 +0800 Subject: [PATCH 6/8] Update README.md User friendly --- README.md | 83 ++++++++++++++++++++++++++++++++++++++++++++--- docs/success.png | Bin 0 -> 33026 bytes 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 docs/success.png diff --git a/README.md b/README.md index 719a9ef..e422d06 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,85 @@ Use at your own caution!!! -[Read more](https://keita.blog/?p=1796) +[Read the original article](https://keita.blog/?p=1796) -## How To Use +## Quick Start + +This creates a cloudfront domain, api gateway, lambda function, aurora (MySQL) serverless cluster and security groups in a previously provisioned VPC. + +### 0. Prerequisites + +1. AWS CLI ([download](https://aws.amazon.com/cli/)) +2. A recent version (^0.33.1) of the AWS SAM CLI with guided deployments ([download](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)) + +### 1. Use the guided SAM template to deploy the template once. +Run the following the deploy using your default AWS profile in ~/.aws/credentials: +```bash +sam deploy -g +``` +or use the following to deploy in a custom profile: +```bash +sam deploy -g --profile REPLACE_THIS_WITH_NAMED_PROFILE +``` +| Parameter | Description | +| ------------- | ------------- | +| Stack Name | Anything you want. Must be unique from what you already have in the region unless you want to update the stack. | +| AWS Region | Region you are deploying to. | +| VpcId | The VPC in the region you are deploying to. You can obtain this by going to https://console.aws.amazon.com/vpc/home?region=`AWS_REGION_HERE`#vpcs:sort=VpcId | +| VpcSubnetIds | A comma-delimited string of subnet IDs belonging to the VPC you specified earlier. You must specify at least 1 subnet ID. | +| StageName | (optional) Stage name of API gateway. | +| CloudFrontPriceClass | (optional) See [here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-distributionconfig.html#cfn-cloudfront-distribution-distributionconfig-priceclass) for a list of valid values. | +| DBName | (optional) The name of the database in the cluster to connect to | +| DBUser | (optional) Default: `admin`. The username of the database cluster | +| DBPassword | The password corresponding to DBUser. | +| Confirm changes before deploy | Y if you want to check changes, N otherwise. | +| Allow SAM CLI role creation | Y, to let SAM manage our deployment bucket. | +| Save arguments to samconfig.toml | Y, so you don't need to go through the steps here again later. | + +This will deploy the stack and required resources. Visiting the cloudfront domain won't work just yet. + +### 2. Set up `wp-config.php` + +Copy the modified wp-config-sample.php and replace all `cloudfront_domain_name_here` with the value of the `CloudFrontDistributionDomainName` (e.g. abcd.cloudfront.net) stack output you obtained from the previous step. + +Linux/Mac: +```bash +cp ./src/php/wp-config-sample.php ./src/php/wp-config.php +sed -i "s/cloudfront_domain_name_here/REPLACE_THIS_WITH_CLOUDFRONT_DOMAIN/g" ./src/php/wp-config.php +``` + +### 3. Redeploy ```bash -$ sam package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket "$DEPLOY_BUCKET" -$ sam deploy --template-file serverless-output.yaml --stack-name wordpress-on-lambda --capabilities CAPABILITY_IAM -$ aws s3 sync ./src/php s3://deploy-bucket-XXXXX/prod --exclude "*.php" --exclude "*.ini" +sam deploy ``` + +We need to redeploy the updated `wp-config.php` onto our lambda function as it contains our settings. There is a circular dependency between cloudfront and the autogenerated IAM permissions for the function so placing the cloudfront domain as an environment variable won't work. + +### 4. Deploy static assets + +Replace `REPLACE_THIS_WITH_ASSETS_BUCKET_NAME` with the value of `AssetsBucketName` from the stack outputs obtained from the previous step. + +```bash +aws s3 sync ./src/php s3://REPLACE_THIS_WITH_ASSETS_BUCKET_NAME --exclude "*.php" --exclude "*.ini" +``` + +or the following if you used a named profile in step 1: + +```bash +aws s3 sync ./src/php s3://REPLACE_THIS_WITH_ASSETS_BUCKET_NAME --exclude "*.php" --exclude "*.ini" --profile REPLACE_THIS_WITH_NAMED_PROFILE +``` + +### 5. Visit cloudfront domain + +You should see the following Wordpress 5.2.1 installation (everything under `./src/php`): + +![Wordpress Install](./docs/success.png) + +## Using a different Wordpress version + +Throw everything away under ./src/php *except* for: + +- `wp-config.php` or `wp-config-sample.php` +- `php.ini` +- `src/php/wp-content/S3-Uploads-2.1.0/*` diff --git a/docs/success.png b/docs/success.png new file mode 100644 index 0000000000000000000000000000000000000000..24db60629c38282f6a1805ce614f636058111535 GIT binary patch literal 33026 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 aE|iYFcrzgN<-98uk@RbbWWM Date: Thu, 26 Mar 2020 09:14:46 +0800 Subject: [PATCH 7/8] Update template.yaml - Add constraint for CloudFrontPriceClass - Remove NoEcho in DBUser to allow default value --- template.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/template.yaml b/template.yaml index 2b0d1c1..b165081 100644 --- a/template.yaml +++ b/template.yaml @@ -13,6 +13,10 @@ Parameters: Default: 'Prod' CloudFrontPriceClass: Type: String + AllowedValues: + - PriceClass_100 + - PriceClass_200 + - PriceClass_All Default: 'PriceClass_200' DBName: Default: wordpressdb @@ -24,7 +28,6 @@ Parameters: ConstraintDescription: must begin with a letter and contain only alphanumeric characters. DBUser: Default: admin - NoEcho: 'true' Description: The WordPress database admin account username Type: String MinLength: '1' From 94d87a832f1c7eee648f6d8e070d699b188e51ef Mon Sep 17 00:00:00 2001 From: Alex Ang Date: Mon, 30 Mar 2020 10:30:24 +0800 Subject: [PATCH 8/8] Update template.yaml Removing caching of 504's due to aurora serverless cold starts on cloudfront --- template.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/template.yaml b/template.yaml index b165081..2342e01 100644 --- a/template.yaml +++ b/template.yaml @@ -146,6 +146,8 @@ Resources: CustomErrorResponses: - ErrorCode: 404 ErrorCachingMinTTL: 0 + - ErrorCode: 504 + ErrorCachingMinTTL: 0 DefaultCacheBehavior: AllowedMethods: