Site Overlay

WordPress on GCP Free Tier: A 3-Year Update

It’s been three years since I wrote extensively about my journey to implement an elastic WordPress hosting model on Google Cloud. The initial objective was about cost, but it’s evolved into an ongoing project that’s given me a good excuse to continuously sharpen my skills with WordPress and numerous GCP services.

Every few months I receive an email from a stranger on the internet letting me know that the project has been helpful to them, or to offer a suggestion for improvement. It’s good to hear that other people have found it to be useful, because Google still doesn’t suggest Cloud Run as an option to host WordPress on Google Cloud.

Since cost was the impetus, I’m due for a readout. The total actual costs for each of the sites that I operate in this hosting model for the 2.5 year period from January 2021 – June 2023 are: $9.38 ($0.31/month) $0.93 ($0.03/month) $2.49 ($0.08/month) $1.46 ($0.05/month)

Compared to a very conservative pricing estimate of $5 per month to host each website somewhere else, the cost of this model is on average 98% lower – close enough to the initial expectation to say that it’s been a successful pursuit.


This project has never remained static – I keep a backlog of improvements in my mind, and if something is urgent enough I’ll give it attention.

A few things that have been urgent enough to address over the last three years:

+ Converted the provisioning of most GCP services from shell/gcloud scripts to Terraform, with automation through a Cloud Build pipeline. This reduces the level of interaction required in the initial setup.
+ Converted the WordPress image baking pipeline from requiring core/theme/plugin zip files to be locally stored in the repo to downloading them directly from the internet. The packages are configured and version-locked through URL lists, and local zip files are still supported as a backup. This simplifies the update process, and externalizes dependencies.
+ Added the installation of the Cloud Ops agent to the MySQL VM. This was initially excluded to preserve resources, but having insight into the full set of utilization metrics from that instance is worth it.
+ Added an approval gate for the WordPress image baking pipeline. This requires manual approval in the Cloud Console before a new WordPress image is built and deployed to Cloud Run. It’s a good sanity check.


This round of long-overdue improvements includes:

+ Upgraded Terraform to version 1.5.7 (the latest stable version), as well as the Google providers.
+ Created separate Service Accounts and corresponding IAM policies for the Cloud Run service (WordPress frontend) and the MySQL VM (WordPress database) instead of using the default Compute Engine service account for both. This is a more secure approach and best practice.
+ Implemented Direct VPC egress in Cloud Run, eliminating the most annoying detail about the original solution architecture where requests from WordPress to the MySQL database were hairpinned out to the edge to a public IP address. This communication is now 100% private. The Architecture Diagram has been updated to reflect this.
+ Implemented newer Cloud Run service configurations: startup CPU boost and session affinity.
+ Adjusted the default Cloud Run resource allocations to 1 vCPU and 1 GB memory. Historical utilization and launch instances rates for all four of my sites validate this as sufficient. Your experience may be different.
+ Revised the ignore file filters for both the infrastructure and application pipelines so their respective builds are triggered only by relevant commits.
+ Centralized almost all variables into a terraform.tfvars file. These are used for Terraform, and are also loaded into shell environment variables for the initial setup that must be executed through scripts. This reduces duplication of variables and the manual effort required in the initial setup.
+ Upgraded the Cloud Build-GitHub repository integration to the 2nd generation. In theory, this improves the level of automation possible in establishing the integration, but the Terraform module for this isn’t fully functional, so it’s been implemented in gcloud commands for now. Using the 2nd generation integration comes with a “feature” of relying on a quota (Concurrent Build CPUs (Regional Public Pool) per region per build_origin) with a default value of 0. A multi-day interaction with support is necessary to have the quota increased before Cloud Build is usable.
+ Upgraded the OS of the MySQL VM to Debian 12. Debian 10 went end of life in September 2022.
+ Replaced MySQL with MariaDB, a drop-in replacement with less ties to Oracle that is widely considered to be more performant.
+ Reduced the WordPress image history in Artifact Repository from 4 to 2, in an attempt to remain within the free tier limitation. I’ve never had to roll back more than one revision, and the GitHub commit history can always be used to rebuild previous versions.
+ Changed the GCE snapshot schedule from a daily backup with a 3 day retention history to a weekly backup with a 1 week retention history. The free tier for snapshot storage appears to have been eliminated, so this change is a cost optimization. I’ve never had to restore MySQL from a backup image, but an RPO of up to a week is tolerable for my sites. Your RPO may be different.
+ Added a gcloud init step at the beginning of the install process, to ensure that gcloud is configured to the correct project and is authorized.
+ Added a clarification to the prerequisites that a billing account should already be attached to the GCP project.
+ Converted the master repository to a template, which seems to be an appropriate model.

Finally, many resource names have been changed, to be more descriptive and to proactively avoid collision when going through a migration from an older version of this framework in the same GCP project (which is my future intent).

These latest updates are merged into the master branch of the wordpress-on-gcp-free-tier template repo. Feedback is always welcome.

Step by step process documentation on how I rolled these improvements out to four existing WordPress sites from the master template (in just one day of effort) is here.