Zero-Downtime WordPress Migration to Google Cloud: An Engineering Playbook
Every production WordPress migration is an exercise in risk mitigation—one missed dependency, and you might trigger a customer-facing outage or break SEO. Here’s a hardened, engineer-tested approach for shifting WordPress from legacy hosting to Google Cloud with negligible downtime and predictable performance.
Context: Why Google Cloud for WordPress?
Scalability, regional failover, VPC-level security, and direct integration with Cloud SQL, Filestore, and global HTTP(S) load balancing. These aren’t checkboxes; for heavy-traffic or latency-sensitive workloads, GCP’s primitives are essential.
Note: If you rely heavily on .htaccess rewrites or bespoke PHP modules, some manual tuning will be unavoidable post-migration.
Pre-Migration Checklist
- Full Application & DB Snapshot
Usewp cli db export
and a recursive filesystem tar (tar czf wpfiles.tar.gz /var/www/html
)—plugins like UpdraftPlus won’t handle untracked files in custom directories. - Compatibility Audit
Assess PHP (e.g., 8.1 vs 7.4), MySQL vs MariaDB differences (opcache config, authentication plugins), required modules, and crontab jobs. Document external integrations—some IPs or hostnames may need allow-list updates. - Network & DNS Planning
Drop TTL on A/AAAA and CNAME records to 300 seconds at least a day ahead. Note TTL expiry propagation is not immediate; measure your current authoritative DNS response for certainty. - SSL Inventory
Identify custom certificate requirements—is Let’s Encrypt sufficient? Consider multi-domain SAN certs if you serve aliases.
Step 1: Provision GCP Compute Resources
Size matters. For baseline production:
Use Case | vCPUs | RAM | Storage (min) | Notes |
---|---|---|---|---|
Small/Dev | 1 | 2GB | 20GB SSD | No autoscaling |
Modest Prod | 2 | 4GB | 50GB SSD | e2-medium |
High Load | 4+ | 8GB+ | 100GB SSD/NVMe | Consider L7 LB/ILB |
Setup:
gcloud compute instances create wp-prod-1 \
--machine-type=e2-medium \
--image-family=ubuntu-2204-lts \
--boot-disk-size=50GB \
--tags=http-server,https-server \
--zone=us-central1-a
Firewall rule for 80/443 is required (gcloud compute firewall-rules create
).
Known issue: Some pre-built images skip mod_rewrite for Apache; check /etc/apache2/mods-enabled/
.
Step 2: Hardened LAMP Install & WordPress Setup
Deploy required services. Avoid Debian/Ubuntu tasksel
"LAMP" package; it includes extraneous modules.
Minimal stack:
sudo apt update
sudo apt install apache2 libapache2-mod-php8.1 php8.1 php8.1-mysql php8.1-gd php8.1-curl php8.1-xml mariadb-server unzip -y
sudo phpenmod mbstring
Test PHP with a minimal phpinfo()
before proceeding.
Database note: For HA or autoscaling, use Cloud SQL (MySQL 8.0). If local, secure MariaDB (mysql_secure_installation
), create application DB/users:
CREATE DATABASE wpdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'%' IDENTIFIED BY 'S3curePwd!';
GRANT ALL PRIVILEGES ON wpdb.* TO 'wpuser'@'%';
FLUSH PRIVILEGES;
Filesystem prep:
cd /var/www
sudo wget https://wordpress.org/latest.zip
sudo unzip latest.zip
sudo chown -R www-data:www-data wordpress
sudo chmod -R 755 wordpress
VHost template (Apache, /etc/apache2/sites-available/000-default.conf
):
<VirtualHost *:80>
DocumentRoot /var/www/wordpress
<Directory /var/www/wordpress>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Gotcha: AllowOverride All
is required for permalinks. Reload Apache: sudo systemctl reload apache2
.
Step 3: Dump, Move, and Restore the Database
Export source site database (example assumes source host is accessible):
mysqldump -u wpuser -p'oldPWd' wpdb > dump.sql
Transfer to GCP (from local workstation):
gcloud compute scp dump.sql wp-prod-1:/tmp/
Restore on the target (MySQL 8.0, MariaDB 10.6+):
mysql -u wpuser -p'S3curePwd!' wpdb < /tmp/dump.sql
Watch for: Collation mismatches and plugin warnings. If encountering ERROR 1273 (HY000)
, check MySQL version compatibility.
Step 4: Migrate wp-content
and Custom Files
Only the wp-content
directory (themes, plugins, uploads) typically needs to move—core and vendor files should use stock versions to reduce attack surface.
scp -rp /local/path/wp-content wp-prod-1:/var/www/wordpress/
sudo chown -R www-data:www-data /var/www/wordpress/wp-content
For large media libraries, rsync --ignore-existing
can save time and bandwidth.
Step 5: Update wp-config.php
and Adjust URLs
Edit DB credentials, table prefix (if customized), and salting keys. Example:
define('DB_NAME', 'wpdb');
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'S3curePwd!');
define('DB_HOST', '127.0.0.1');
If the temporary server name/IP differs, WordPress hard-codes URLs in serialized arrays. Instead of manual SQL edits:
- Use Search Replace DB.
- Or WP CLI:
wp search-replace 'http://oldsite.com' 'https://newsite.com' --all-tables
Non-obvious tip: Be aware of serialized data—direct SQL replaces may corrupt arrays and objects.
Step 6: Validation Before DNS Cutover
Open /etc/hosts
on your workstation; map your domain to the new IP:
203.0.113.42 yoursite.com www.yoursite.com
Test:
- Admin login works.
- Permalinks resolve to correct URLs.
- Known plugins (e.g., caching, SEO) are functional.
Use browser dev tools for failed requests; look for 404s or mixed-content warnings.
Step 7: DNS Switch and Final Cutover
Update domain A/AAAA records. With prior low TTL, cutover happens quickly—but some global resolvers cache for up to a few hours regardless.
Monitor real traffic source IPs (awk
from access logs) to confirm when traffic ceases on the old host.
Step 8: SSL and Security Hardening
Install Certbot and enable HTTP/2:
sudo apt install python3-certbot-apache -y
sudo certbot --apache -d yoursite.com -d www.yoursite.com
Force HTTPS by editing your Apache config, or use Certbot-provided auto-redirect.
Afterthought: Once stable, back up the VM image (gcloud compute images create
), configure GCP firewall rules (block all except 80/443+management), and set up Cloud Monitoring alerts.
Extras: Scaling, Backups, and Automation
- Backups:
Script regular DB dumps to Cloud Storage via cron. - Scaling:
Migrate DB to Cloud SQL, use Cloud CDN for static assets via Load Balancer. - Automation:
Infrastructure-as-Code approach via Terraform or Deployment Manager—repeatable, auditable migrations.
Post-Migration: What Breaks and How to Fix
Not every plugin or custom script survives a migration unchanged. Needing to reconfigure rewrites or disabling OPcache temporarily isn’t uncommon. Regression test all critical flows.
Final note: If you discover character encoding issues, reimport your DB with explicit --default-character-set=utf8mb4
and check Apache’s default charset in /etc/apache2/conf-enabled/charset.conf
.
Summary:
WordPress-to-GCP migrations are a multi-dimensional challenge. Precise backups, staging on a temporary host, and methodical validation are the keys to an outage-free cutover. Avoid temptation for plugin-based, one-click automation on production workloads—engineer, don’t merely copy.