Serverless Static Wordpress is a Community Terraform Module from TechToSpeech that needs nothing more than a registered domain name with its DNS pointed at AWS.
It creates a complete infrastructure framework that allows you to launch a temporary, transient Wordpress container. You then log in and customize it like any Wordpress site, and finally publish it as a static site fronted by a global CloudFront CDN and S3 Origin. When you’re done you shut down the Wordpress container and it costs you almost nothing.
The emphasis is on extremely minimal configuration as the majority of everything you’d need is pre-installed and pre-configured in line with industry best practices and highly efficient running costs.
- A domain name either hosted with AWS, or with its DNS delegated to a Route53 hosted zone.
- A VPC configured with at least one public subnet in your desired deployment region.
Terraform best practice is to configure providers at the top-level module and pass them downwards through implicit
inheritance or explicit passing. Whilst the module and child-modules reference required_providers
, it is also necessary
for you to provide a regional alias for operations that must be executed in us-east-1 (CloudFront, ACM, and WAF).
As such you should include the following in your provider configuration:
terraform {
required_version = "> 0.15.1"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
configuration_aliases = [aws.ue1]
}
}
}
provider "aws" {
alias = "ue1"
region = "us-east-1"
}
The ue1
alias is essential for this module to work correctly.
locals {
aws_account_id = "998877676554"
aws_region = "eu-west-1"
site_name = "peterdotcloud"
profile = "peterdotcloud"
site_domain = "peter.cloud"
}
data "aws_caller_identity" "current" {}
module "peterdotcloud_website" {
source = "TechToSpeech/serverless-static-wordpress/aws"
version = "0.1.0"
main_vpc_id = "vpc-e121c09b"
subnet_ids = ["subnet-04b97235","subnet-08fb235","subnet-04b97734"]
aws_account_id = data.aws_caller_identity.current.account_id
# site_name will be used to prepend resource names - use no spaces or special characters
site_name = local.site_name
site_domain = local.site_domain
wordpress_subdomain = "wordpress"
hosted_zone_id = "Z00437553UWAVIRHANGCN"
s3_region = local.aws_region
# Send ECS and RDS events to Slack
slack_webhook = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"
ecs_cpu = 1024
ecs_memory = 2048
cloudfront_aliases = ["www.peter.cloud", "peter.cloud"]
waf_enabled = true
# Provides the toggle to launch Wordpress container
launch = 0
## Passing in Provider block to module is essential
providers = {
aws.ue1 = aws.ue1
}
}
Do not to set launch
to 1 initially as the module uses a Codebuild pipeline to take a vanilla version
of the Wordpress docker container and rebake it to include all of the pre-requisites required to publish the Wordpress
site to S3.
The step to push the required Wordpress container from Dockerhub to your own ECR repository can be tied into your module instantiation using our helper module as follows:
Note this requires Docker to be running on your Terraform environment with either a named AWS profile or credentials otherwise available.
module "docker_pullpush" {
source = "TechToSpeech/ecr-mirror/aws"
version = "0.0.6"
aws_account_id = data.aws_caller_identity.current.account_id
aws_region = local.aws_region
docker_source = "wordpress:php7.4-apache"
aws_profile = "peterdotcloud"
ecr_repo_name = module.peterdotcloud_website.wordpress_ecr_repository
ecr_repo_tag = "base"
depends_on = [module.peterdotcloud_website]
}
The CodeBuild pipeline takes a couple of minutes to run and pushes back a 'latest' tagged version of the container, which is what will be used for the Wordpress container. This build either needs to be triggered manually from the CodeBuild console, or you can use this snippet to trigger the build as part of your Terraform flow:
resource "null_resource" "trigger_build" {
triggers = {
codebuild_etag = module.peterdotcloud_website.codebuild_package_etag
}
provisioner "local-exec" {
command = "aws codebuild start-build --project-name ${module.peterdotcloud_website.codebuild_project_name} --profile ${local.profile} --region ${local.aws_region}"
}
depends_on = [
module.peterdotcloud_website, module.docker_pullpush
]
}
Whilst this might feel convoluted (and you might ask: why not just provide a public customized Docker image?), it was felt important that users should 'own' their own version of the Wordpress container, built transparently from the official Wordpress docker image with full provenance.
Finally, if you wish to fully automate the creation and update of the domain's nameservers if it's registered in Route53 within the same account, you can add these additional snippets to include this in your flow.
resource "aws_route53_zone" "apex" {
name = "peter.cloud"
}
resource "null_resource" "update_nameservers" {
triggers = {
nameservers = aws_route53_zone.apex.id
}
provisioner "local-exec" {
command = "aws route53domains update-domain-nameservers --region us-east-1 --domain-name ${local.site_domain} --nameservers Name=${aws_route53_zone.apex.name_servers.0}Name=${aws_route53_zone.apex.name_servers.1} Name=${aws_route53_zone.apex.name_servers.2} Name=${aws_route53_zone.apex.name_servers.3} --profile peterdotcloud"
}
depends_on = [aws_route53_zone.apex]
}
See examples for full set-up example.
Name | Description | Type | Default | Required |
---|---|---|---|---|
aws_account_id | The AWS account ID into which resources will be launched. | number |
n/a | yes |
cloudfront_aliases | The domain and sub-domain aliases to use for the cloudfront distribution. | list(any) |
[] |
no |
cloudfront_class | The price class for the distribution. One of: PriceClass_All, PriceClass_200, PriceClass_100 | string |
"PriceClass_All" |
no |
ecs_cpu | The CPU limit password to the Wordpress container definition. | number |
256 |
no |
ecs_memory | The memory limit password to the Wordpress container definition. | number |
512 |
no |
hosted_zone_id | The Route53 HostedZone ID to use to create records in. | string |
n/a | yes |
launch | The number of tasks to launch of the Wordpress container. Used as a toggle to start/stop your Wordpress management session. | number |
"0" |
no |
main_vpc_id | The VPC ID into which to launch resources. | string |
n/a | yes |
s3_region | The regional endpoint to use for the creation of the S3 bucket for published static wordpress site. | string |
n/a | yes |
site_domain | The site domain name to configure (without any subdomains such as 'www') | string |
n/a | yes |
site_name | The unique name for this instance of the module. Required to deploy multiple wordpress instances to the same AWS account (if desired). | string |
n/a | yes |
site_prefix | The subdomain prefix of the website domain. E.g. www | string |
"www" |
no |
slack_webhook | The Slack webhook URL where ECS Cluster EventBridge notifications will be sent. | string |
"" |
no |
snapshot_identifier | To create the RDS cluster from a previous snapshot in the same region, specify it by name. | string |
null |
no |
subnet_ids | A list of subnet IDs within the specified VPC where resources will be launched. | list(any) |
n/a | yes |
waf_acl_rules | List of WAF rules to apply. Can be customized to apply others created outside of module. | list(any) |
[ |
no |
waf_enabled | Flag to enable default WAF configuration in front of CloudFront. | bool |
n/a | yes |
wordpress_admin_email | The email address of the default wordpress admin user. | string |
"admin@example.com" |
no |
wordpress_admin_password | The password of the default wordpress admin user. | string |
"techtospeech.com" |
no |
wordpress_admin_user | The username of the default wordpress admin user. | string |
"supervisor" |
no |
wordpress_subdomain | The subdomain used for the Wordpress container. | string |
"wordpress" |
no |
Name | Source | Version |
---|---|---|
cloudfront | ./modules/cloudfront | n/a |
codebuild | ./modules/codebuild | n/a |
lambda_slack | ./modules/lambda_slack | n/a |
waf | ./modules/waf | n/a |
Name | Description |
---|---|
cloudfront_ssl_arn | The ARN of the ACM certificate used by CloudFront. |
codebuild_package_etag | The etag of the codebuild package file. |
codebuild_project_name | The name of the created Wordpress codebuild project. |
wordpress_ecr_repository | The name of the ECR repository where wordpress image is stored. |
Name | Version |
---|---|
terraform | >= 0.15.1 |
aws | ~> 3.0 |
random | ~> 3.1.0 |