By the end of this blog post (or wp-cloud-run YouTube video playlist), you’ll have a fully secure (DDoS proof), performant and scalable WordPress instance running on Cloud Run, backed by a Cloud SQL database and three GCS (Google Cloud Storage) buckets, for SQL backups, WordPress backups, and media storage.

wp-cloud-run project architectural diagram

But before that, a bit of history and what triggered me to create this project.

From cloud to on-premise and back to cloud

For years, I’ve run this now 18-year-old blog on AWS. I created the entire setup using various Ansible roles and playbooks, which I also open-sourced as part of the containerized-wordpress-project.

Then 3+ years ago, I moved it to GKE (Google Kubernetes Engine) as part of the wp-k8s project. However, I wasn’t satisfied with the cost of hosting a private blog on GKE, and at the same time I was migrating from Google Photos to Synology Photos as part of my private cloud setup. Which inspired me to extend the scope, get few RPI’s and create a privately hosted Kubernetes cluster.

As part of this setup, for past 3 years I’ve successfully managed all my public and private workloads, including this blog and atuf.app – Amsterdam Toilet & Urinal Finder.

Apart from a couple of minor hiccups, the setup performed exceptionally well, as I designed it with resilience in mind. Even in case something went terribly wrong or I wanted to upgrade the cluster to latest version of K8s by nuking all existing resources and stating from scratch. I’ve been able to do this and restore everything to its previous state by using the wp-k8s (for streamlined WordPress deployment on K8s) and rpi-microk8s-bootstrap (for automated Raspberry Pi cluster setup) open-source projects that emerged from this work.

Earlier this year, I created a disaster recovery (DR) failover (or in case I decide to migrate it to Google Cloud) for atuf.app. Resulting in App architecture with reliability in mind: From Kubernetes to Serverless with GCP Cloud Build & Cloud Run blog post and YouTube video. Please note I left this blog (WordPress) out of the scope of that work.

Then, this summer, I faced my biggest outage yet. Of course, it happened while I was on vacation! You can read more about it on Twitter/X or LinkedIn.

TL;DR: While my entire private setup was non-recoverable until I returned home to power on the downed host, I salvaged my vacation by moving all public workloads to Google Cloud.

Moving atuf.app was straightforward since I had already set up a Cloud Build and Cloud Run deployment for it. However, migrating this blog, an existing WordPress site with data from Kubernetes to Cloud Run (Knative) was much more complicated. It shouldn’t have been, and that’s the journey, along with the lessons learned, that I want to share.

Birth of wp-cloud-run project

While there are a few decent guides online for setting up WordPress on Cloud Run, all of them only cover how to set up basic “hello world” sites. They don’t address real-life scenarios with sites that include data. Or migrating from a stateful setup with data stored on NFS (as it was in my case) to a completely stateless architecture with storing some data in GCS buckets.

Cloud Run charges you for the traffic your site receives, the number and duration of requests made, and the resources (i.e CPU and memory) used by your container instances. This makes it cost-effective, especially for sites with irregular traffic patterns. However, a DDoS attack, as I experienced, can cause costs to spiral.

None of the Cloud Run setup-related resources I found addressed how to avoid these unexpected expenses. My daily costs reached €6.15, with €4.51 attributed to Cloud Run and the rest to Cloud SQL and GCS. For high-traffic sites, this could potentially escalate to thousands. I’ll share the lessons learned that helped me reduce these costs to around €0.51 per day (€0.09 for Cloud Run).

Maximum daily cost for wp-cloud-run during the DDoS attack without rate limiting and security hardening.
Approximate and minimum wp-cloud-run daily costs after rate-limiting and security hardening

This inspired me to design an optimal WordPress setup on Cloud Run (wp-cloud-run). It prioritizes security while minimizing costs without compromising performance, whether for a personal blog, company site, web store, or anything in between.

Project Deliverables:

Appendix: wp-cloud-run runbook

The following appendix outlines all topics covered in detail in the YouTube video, which will demonstrate how to set up a fully scalable, secure, and high-performance WordPress site running on Cloud Run.

  • 1 – Create GCP Artifacts Registry repository to store wp-cloud-run container images
    • 1.1 – Create Artifact Registry to store Docker container images
    • 1.2 – Point out other configuration options like clean-up policies to delete (old) artifacts and enable vulnerability scanning 
    • 1.3 – How to configure Docker client to automatically authenticate with Google Artifact Registry, which will be explained in detail in next step
  • 2 – Using wp-cloud-run project for local WordPress development with Docker & Docker Compose
    • 2.1 – Introduction on what wp-cloud-run project consists of
    • 2.2 – Pre-requirements and requirements for running container-build-push.go
    • 2.3 – How to run & use container-build-push.go to build and push a wp-cloud-run (WordPress app) container image to Google Cloud Registry
    • 2.4 – How to use wp-cloud-run repository for local WordPress development
      • 2.4.1 – Overview of WordPress and MySQL setup in the docker-compose.yaml
      • 2.4.2 – Deploying WordPress and MySQL locally using docker-compose.yaml
      • 2.4.3 – Guide to developing WordPress on a locally deployed environment, making changes to container image, covering container attachments and more
  • 3 – Setup Cloud SQL instance and WordPress database backup
    • 3.1 – Create GCS (Google Cloud Storage) bucket for SQL backup
    • 3.2 – Create GCP Cloud SQL instance with MySQL engine
    • 3.3 – Create MySQL WordPress database and WordPress database user
    • 3.4 – Creating Cloud SQL & database backups and exporting them to GCS bucket created for SQL backups
  • 4 – Create wp-cloud-run: WordPress Cloud Run service
    • 4.1 – Setup WordPress Cloud Run service and configure container options for optimal resource allocation and scalability & connect to SQL database
    • 4.1.1 – Configure Direct VPC egress and send traffic to a VPC network for low latency with Cloud SQL WordPress database and connecting to using private IP
    • 4.1.2 – Deploy wp-cloud-run (WordPress) and configure it
  • 4.2 – Setup WP-Stateless plugin to store WordPress media on GCS (Google Cloud Storage) bucket
    • 4.2.1 – Create GCS bucket for WordPress media storage
    • 4.2.2 – Create “wp-stateless” service account with key and grant it “Storage Admin” access on bucket level
    • 4.2.3 – Configure WP-Stateless plugin
    • 4.2.4 – Demo image upload to GCS bucket
  • 4.3 – Perform full WordPress backup & restore using “All-in-One WP Migration and Backup” plugin to store backups on GCS (Google Cloud Storage) bucket
    • 4.3.1 – Create WordPress backup GCS bucket
    • 4.3.2 – Add Cloud Storage Bucket volume to Cloud Run service and mount it as part of volume mounts
    • 4.3.3 – Configure All-in-One WP Migration plugin to use GCS WordPress backup bucket
    • 4.3.4 – Perform WordPress backup to GCS WordPress bucket using All-in-One WP Migration plugin, and show how restore would be performed
  • 5 – Point domain name (on Cloudflare) to wp-cloud-run Cloud Run service with Cloud Run Domain Mappings
    • 5.1 – Add domain mapping using Cloud Run Domain Mappings
    • 5.2 – Add domain (update DNS) on Cloudflare to point to wp-cloud-run Cloud Run service
  • 6 – Setup Cloud Run uptime alerting
    • 6.1 – Create Uptime check for availability alerting
  • 7 – Explain costs associated with wp-cloud-run project
    • 7.1 – Explore costs for wp-cloud-run setup (Cloud Run, Cloud SQL, Cloud Storage)
    • 7.2 – Explore costs for wp-cloud-run (Cloud Run) and setup tags
    • 7.3 – Compare to costs of running same service on private Kubernete clusters at home (on-premise)
    • 7.4 – Create budget alerts
  • 8 – Performance, scalability and preventing unwanted costs with use of CDN, rate limiting & DDoS protection
    • 8.1 – Realizing I’m under a DDoS attack
  • 8.2 – Create rate limiting and add DDoS protection using Wordfence Security plugin
    • 8.2.1 – Configure Rate Limiting options and see it in action
    • 8.2.2 – Configure WordPress 2FA access
  • 8.3 – WordPress site performance improvements with Cloudflare (free plan): optimizing speed through cache rules, CDN configurations, and enhanced security settings.
    • 8.3.1 – Configure Cloud Run domain mapping to work with Cloudflare proxy DNS records
    • 8.3.2 – Cloudflare speed optimizations
    • 8.3.3 – Setting Cloudflare caching rules with Edge TTL (CDN)
    • 8.3.4 – Cloudflare caching configuration with Tiered caching and Cache reserve
    • 8.3.5 -Cloudflare site security settings
    • 8.3.6 – Configure “Super Page Cache” plugin to use Cloudflare CDN
    • 8.3.6 – Cloudflare CDN/Proxy setup verification
    • 8.3.7 – Site speed test

What’s next for wp-cloud-run?

Next step will be to create a Terraform repository just as it was created for atuf-deployment consisting of deployment with Cloud Build & Cloud Run. Which I’ll also create a blog post & create a Youtube video.

Happy hacking! If you found this project useful, consider supporting its continued open-source development by becoming a sponsor on GitHub. Your support would be greatly appreciated!