Summary
This article documents deploying the WordPress content management system (CMS) in Google Cloud as a fast, friendly, cheap (possibly free!) platform to blog from.
This is probably relevant for you if:
- You’re looking to start a blog
- You’ve settled on WordPress, the top Open Source blogging engine
- You have some Linux command line skills
I’m not going to discuss choosing WordPress over some other content management platform. Spending too much time worrying about the content management engine is a trap; Get to producing your content and don’t worry about the platform you’re using to publish it. That’s something you can change later on, as most of the major CMS platforms have tools to migrate from the other major platforms.
Why: Motivation
I host WordPress on tiny virtual machines in Google Cloud for administrative performance, and entry-level price. I’ve been asked “how” enough times that I’d like to document it for others.
My Blogging History – Blogger
My writing for the web has been a hobby, not a profession. I got started publishing personal short and medium form content on the Blogger platform. Blogger still exists, and if it fits your purpose, you might want to bypass all of this and just use it. Again, you can always change your platform later. The content is the important thing.
Blogger to WordPress shared hosting
I eventually moved my personal writing and professional musings to shared WordPress hosting platforms. WordPress is probably the most popular Open Source content management system out there. With that footprint comes tons of support, active development, and a large ecosystem of enhancements (themes, plugins, customizations). WordPress hosting services were an easy way to get started using WordPress without thinking about the infrastructure. Over the years I used a variety of vendors including (I think) Bluehost, DreamHost, and iPage.
WordPress shared hosting to WordPress in Google Cloud
After a number of years, I grew frustrated at the slow performance during upgrades of WordPress plugins and themes. I would log in to WordPress, intending to copy some content in and move on, a 2 minute task, only to see the latest group of upgrades that needed my attention. Those upgrades require suspending the WordPress engine and could lock up 10-15 minutes of my time. I ran some tests and found that WordPress running in a small VM could do the same thing in less than 15 seconds. Despite the poor relative performance, shared hosting vendors were expensive relative to what you could pay for in a cloud VM. I had the expertise to do the minimal administrative tasks, so I bit the bullet and migrated my content to self-hosted WordPress within Google Cloud. I’ve been promising/threatening to document that process for years, and have finally gotten around to doing so.
Why blog – Self-documentation
In both professional and personal contexts, I’ve long advocated writing about things one cares about as part of the process of improving skills. When blogging about my profession, I started as a consumer of other people’s technical writing, searching out solutions to my problems in other people’s writing. The thing that pushed me towards doing my own writing was when no one had encountered the specifics of my situation, which forced me to synthesize a number of different articles and documentation to reach my solution. At first I wouldn’t document it, mistakenly thinking it was a one-off situation. Eventually, I’d find myself wasting time re-creating the solution. It took an embarrassing number of times before I finally started just writing and publishing the variations of solutions I needed. And it didn’t take long at all before I was Googling a problem and found my own article on how to solve it.
Why blog – Improve thinking
Writing has benefited me in a number of ways, not just documenting knowledge for my future self. Writing clarifies my thinking. Well, more accurately, it reveals to me when my thinking isn’t clear, and the process of getting the writing done forces me to concentrate on clarifying my thoughts. It organizes my thinking. Writing this article, for example, forced me to separate out the process of deploying WordPress for the first time from the process of migrating to it, migrating instead of upgrading, and using it as a podcast publishing platform. I thought of, and tabled other projects, such as using WordPress as a Knowledge Management CMS.
I don’t think I’ve ever gotten a job or even improved a performance review because of my technical blogging. However, I’ve found that the process of organizing my thoughts and documenting solutions for repeatability has helped me professionally.
Why Google Cloud?
I happened to choose Google Cloud when I first started migrating my sites. I want to disclose that I now work for Google Cloud as a Customer Engineer, but that employment change happened years after I made my blogging platform decision. The main reasons I chose Google Cloud, at the time, was a slight price advantage and the fact that I was already using most of the Google consumer products (Gmail, Maps, Photos, YouTube, etc).
How to deploy WordPress in Google Cloud
The overall process of deploying WordPress to Google Cloud has four overall steps:
- Get Google Cloud prepped for the WordPress deployment
- Deploy WordPress into a small Google Cloud Engine virtual machine
- Configure the path people will use to reach the site
- Start publishing
Get Started with Google Cloud
If you have a Gmail account, you already have the basis for getting started with Google’s Cloud services. Here’s the Getting Started landing page. If you haven’t tried it before from that Gmail account, you’ll get $300 in credits for the first 90 days that you’re using it. That’ll make your WordPress virtual machine essentially free during that time for most use cases.
-
Log in to the Google Cloud Console You’ll need a (free) Google account, which many people already have for Gmail. If you don’t have that, your first step will be to get it. You’ll get a click-through Terms of Service statement.
-
Create a Project for the WordPress instance. Use a meaningful name for your project, such as a the name of the blog. A project is just an administrative construct within which you’ll be deploying your cloud resources. Later on, you might want to report on or do budget alerts for the blog. And if you want to publish multiple different blogs, you generally want different projects so you can report on and control them separately. Don’t overthink the permissions discussed in the official documentation; If you’re running a business, you might need to have multiple people with access to the project and different levels of permissions, but as a single hobbyist, project level permissions in the official documentation don’t really matter.
-
Set up payment for your Google Cloud account, (most likely a credit card). Again, you’ll have $300 of free credits to use for the first 90 days, and after that we’ll be using the free tier of services, but you’ll need a payment method for any non-free services.
This discussion is focused on those who want the minimal infrastructure for a self-hosted instance of WordPress on a virtual machine (VM). This involves only two real parts of GCP; Google Cloud Engine is the virtual machine service and getting the underlying static IP address for the site, part of cloud networking.
Deploy a curated version of WordPress
- For your first VM, deploy on an e2-micro in us-central1 to use in Google Cloud’s free tier. As of the time of this writing, the only machine qualifying for the free tier is a single e2-micro instance running in us-west1, us-central1, or us-east1. Any subsequent WordPress instances I create, I’ll use the N1→f1-micro for between $4-6/month.
- I rely on the crew at Bitnami to create curated packages to deploy WordPress. More specifically, I use the WordPress with NGINX and SSL Certified by Bitnami and Automattic [Link to Google Cloud Marketplace]
Confirm you’re deploying into the correct project
In the Google Cloud Console, I make sure I’m within the Google Cloud Project I created for this WordPress installation, then navigate to the WordPress with NGINX and SSL Certified by Bitnami and Automattic within Google Cloud Marketplace. You’ll see a fairly prominent “Launch” button. This Launches a configuration page, not the actual instance, so click-through.
On the configuration page, there are several things to change. I make sure there’s some metadata in the name, and that I’m using the cheapest deployment available, a combination of deployment zone and machine type.
- Deployment name
I add a name for the instance incorporating the name of my blog and the date I’m deploying the instance: blogname-YYYY-MM-DD. That way, I know exactly when I deployed the VM and this instance of WordPress at a glance.
- Zone
For the free tier, you currently need to be in us-west1, us-central1, or us-east1. The latter two are the cheaper regions if you’re outside of the-free tier.
- Machine Type
The free tier currently covers a single e2-micro machine
Series – E2
Machine type – e2-micro
You can see the estimated monthly cost to the right of the configurations. These prices are as of June 2022. For your first VM in the free tier, use an e2-micro. Subsequently, I use Series N1, f1-micro for between $4-6/month. If you ever have performance issues, you can just use a migration process to re-deploy to a large instance.
The process of creating the instance will proceed, and you’ll have an output which includes the current IP address of the instance and the initial, temporary username and password.
Instance configuration
There are a few things to tweak in the installation before we migrate our current blog content over to it. Apply any WordPress updates, install additional plugins, and make your ephemeral external IP address static. After that, point a domain name for the blog at the address, configure secure connections, and configure WordPress to use the domain name as the blog’s name rather than the IP address.
Change the Admin user and password
You can see from the last figure, that there was a user/password generated from the deployment. Add your own account and make it an admin. Choose a strong password that you won’t forget or that you store in a password service (I use LastPass or Google Password Manager in Chrome/Android).
After you’ve logged out and in successfully as the new admin user, remove the user created by the deployment process.
Apply WordPress Updates
- Go to the updates page on your WordPress Dashboard http://<instance-ip-address>/wp-admin/update-core.php Normally, you’d want to back up your WordPress instance before making major upgrades, but this instance is empty. If there’s any problems, just delete the VM and start over.
- Upgrade WordPress version if there’s one available (for example, I’m upgrading WordPress 5.9.3 to 6.0)
- Upgrade the plugins
- Upgrade the themes
Basic Plugins
There are a few plugins I like to use which aren’t part of Bitnami’s initial installation, so I install them at this time:
- Broken Link Checker – Lets me see and correct broken links in my site
- Image Source Control Lite – Makes sure I’m crediting all the images I use
- ImageInject – Search and use free images
Chose a Basic Theme
At this point, I like the clean, classic look of the official WordPress “Twenty Fifteen” theme. I’ve never been one to spend much time customizing this kind of thing. There’s plenty of time to do that later. Any time you spend here is just delaying your writing.
Convert your VM’s dynamic/ephemeral IP address into one that’s statically assigned to your site
Your WordPress site was deployed on a VM with an external (internet-facing) IP address that Google Cloud calls “ephemeral.” That is, it might change, at any given reboot of the VM. What we want is a “static” IP address, one which is assigned to the VM as long as we want it to be.
Here’s a link to the official GCP documentation on promoting your ephemeral IP address static.
- Go to the External IP Addresses page at the Google Cloud Console.
- Make sure you’re in the correct Project for your WordPress instance
- On your VM’s current ephemeral IP address row (it should have the name of the VM in the “in use by” column), click “Reserve”
- Give a meaningful name for the newly static IP address. I generally use the VM name with “-static” at the end.
Make a DNS entry for your static IP address
If you’ve already registered for your site’s domain name, follow your registrar’s instructions on providing an “A” record for your site’s domain name that points at the static IP address that you just promoted.
Example using Google Domains
I happen to use Google Domains as my registry for convenience. I registered the vjourneyman.com for $12/year. Here’s instructions on how to buy a domain name using Google Domains. But use whatever domain registrar you’re comfortable with.
After I own the domain, I navigate to the DNS section.
Then I created an “A” entry for both vjourneyman.com and all the secondary domain names with an entry for “*.vjourneyman.com”, and an explicit secondary domain record in case someone uses www.vjourneyman.com
It might take a few minutes for the new entry to propagate out to the world. You can check using a public DNS service like DNS Checker. This could theoretically take hours, but as long as you can locally resolve your domain name to the IP address, then you’re good to move on.
Configure WordPress to use Domains instead of IP Addresses
From the deployment process, WordPress has been hard-coded to use the machine’s IP address instead of a domain name. Now that we’ve reserved the IP address for the use of this machine and have registered the domain name and pointed it at the IP address, we can change WordPress to refer to itself through the links it shows by domain name instead of by IP address.
This is where we’ll need comfort with the Linux shell. You’ll need to launch an SSH connection to your VM (Google makes this easy from the console)
Here is the Bitnami documentation page for configuring the WordPress domain name. We’re deploying a self-contained image, so using Approach A to change the domain name.
sudo vi /opt/bitnami/wordpress/wp-config.php
Within the file, replace:
define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST'] . '/');
define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST'] . '/');
With:
define('WP_SITEURL', 'http://$DOMAIN/');
define('WP_HOME', 'http://$DOMAIN/');
Where “DOMAIN” is your site’s actual domain name.
Optional, but Best Practice: Enable Secure Connections to the site with https
Modern web browsers try to connect to every site using an encrypted connection (https). This is something we can support on our blog using Secure Sockets Layer (SSL) and the free third party certificate authority, “Lets Encrypt.”
Generate And Install A Let’s Encrypt SSL Certificate
This is where we’ll need comfort with the Linux shell again. Since we’re using a Bitnami VM, we can use Bitnami’s instructions creating and registering an SSL certificate. I’ve directly linked to “Approach A: Using system packages.”, but you can check for yourself which approach you should use depending on the build of the VM. You’ll need to launch an SSH connection to your VM (Google makes this easy from the console:
To make sure which approach you should be using:
test ! -f "/opt/bitnami/common/bin/openssl" && echo "Approach A: Using system packages." || echo "Approach B: Self-contained installation."
Again, I’m using Approach A.
-
Install the Lego client
cd /tmp curl -Ls https://api.github.com/repos/xenolf/lego/releases/latest | grep browser_download_url | grep linux_amd64 | cut -d '"' -f 4 | wget -i - tar xf lego*_linux_amd64.tar.gz sudo mkdir -p /opt/bitnami/letsencrypt sudo mv lego /opt/bitnami/letsencrypt/lego
-
Generate A Let’s Encrypt Certificate For Your Domain This step depends on DNS entries correctly pointing to your blog’s IP address.
-
Turn off Bitnami services
sudo /opt/bitnami/ctlscript.sh stop
-
Request a certificate for all the domains that someone might get your site by. I’ve included both the primary domain and www in this code. Assign values for your domain and email address!
EMAIL=”” DOMAIN=”” sudo /opt/bitnami/letsencrypt/lego --tls --email="$EMAIL" --domains="$DOMAIN" --domains="www.$DOMAIN" --path="/opt/bitnami/letsencrypt" run
- Configure The Web Server To Use The Let’s Encrypt Certificate
-
Link the certificates to where the web server can access them. We’re using NGINX for this installation, Approach A, so follow those instructions.
sudo mv /opt/bitnami/nginx/conf/bitnami/certs/server.crt /opt/bitnami/nginx/conf/bitnami/certs/server.crt.old sudo mv /opt/bitnami/nginx/conf/bitnami/certs/server.key /opt/bitnami/nginx/conf/bitnami/certs/server.key.old sudo mv /opt/bitnami/nginx/conf/bitnami/certs/server.csr /opt/bitnami/nginx/conf/bitnami/certs/server.csr.old sudo ln -sf /opt/bitnami/letsencrypt/certificates/$DOMAIN.key /opt/bitnami/nginx/conf/bitnami/certs/server.key sudo ln -sf /opt/bitnami/letsencrypt/certificates/$DOMAIN.crt /opt/bitnami/nginx/conf/bitnami/certs/server.crt sudo chown root:root /opt/bitnami/nginx/conf/bitnami/certs/server* sudo chmod 600 /opt/bitnami/nginx/conf/bitnami/certs/server*
-
Restart Bitnami services
sudo /opt/bitnami/ctlscript.sh start
- Test the configuration
- Can you go to your blog using https in the URL?
- Do you see the padlock by the domain name in the browser window, indicating that the connection is secure?
Assuming that everything went well, you now have secure https access to your site set up!
- Set up automatic renewals of the certificate
Create a script to automatically renew the certificate:
sudo mkdir -p /opt/bitnami/letsencrypt/scripts
sudo nano /opt/bitnami/letsencrypt/scripts/renew-certificate.sh
The contents of the script should be:
#!/bin/bash
sudo /opt/bitnami/ctlscript.sh stop nginx
sudo /opt/bitnami/letsencrypt/lego --tls --email="EMAIL" --domains="DOMAIN" --path="/opt/bitnami/letsencrypt" renew --days 90
sudo /opt/bitnami/ctlscript.sh start nginx
Make sure you put your email address and domain name in for the placeholders!
Make it executable:
sudo chmod +x /opt/bitnami/letsencrypt/scripts/renew-certificate.sh
Open the crontab editor:
sudo crontab -e
Add the following entry to periodically run the renewal:
0 0 1 * * /opt/bitnami/letsencrypt/scripts/renew-certificate.sh 2> /dev/null
Now renewals should be automated!
Get Publishing
- Write
- Edit
- Publish
- Repeat
In general, I do my writing outside of WordPress, using Google Docs. I write plain text using Markdown, and copy/paste the content into a [ordPress Markdown Block. Here’s instructions on Enabling Markdown blocks in WordPress . I add any images I might have captured to the post, then schedule publishing.
Set Up Backups
I use the UpdraftPlus WordPress Plugin for backups, namely because it can, with my authorization, place the backup files inside my Google Drive. And it does so for free. You might think that if I’m writing my posts in Google Docs, there’s no reason to backup. You’d be wrong. While it’s technically possible to re-create your posts, it’s incredibly painful, especially as you write more. Just set up backups to a personal Drive.
Optional but Best Practice: Set up Budget Alerts for the Project
I mentioned before that a Google Cloud Project is a really good abstraction to report on, especially to create cost warnings. For our purposes, we’re planning on running this WordPress blog in the free tier, so any spending over $5 (for example) would warrant a warning. So let’s set that up.
Here’s the subsection on Google Cloud’s official documentation on Budgets which deals with actually creating a budget (bypassing a lot of the enterprise/business concern about permissions and roles).
- Create the budget Go to Billing → Budgets on the Google Cloud console. There’s a “Create Budget” button along the top.
- Set the scope of the budget
- Name the budget something meaningful. I use the name of the blog and the budget. “vJourneyman $10”
- We’re looking for an alert every month, so time range is “Monthly”
- We want to alert only the project that houses WordPress, so select that project from the Project dropdown.
- Then select “NEXT”
- Set the details on the Budget Amount
- The default should be to “Specified Amount”.
- We’re going to have a $10 budget and have an alert emailed when half of it is used.
- Select “NEXT”
- Set the actions
- The defaults should work here. We’re being alerted when 50%, 90%, and 100% of our budget is consumed.
- The way we’re being alerted is emails sent to the billing admins and users.
- Select “FINISH”
Congratulations, your budget setup is all done!
Conclusion
I hope this article has been helpful in getting you closer to launching your blog. Hopefully you’ll agree with me that WordPress in Google Cloud is both faster and cheaper! If you have any feedback, such as problems following a specific step, I’d love to hear it.
Most importantly, get writing sooner rather than later. If you have problems getting this setup up and running, don’t let that stop you from writing. Write in a Google Doc so you can copy/paste into your blog later. Get writing!