Automate your WordPress site management with GitHub Actions. From backups to deployments, this guide simplifies workflow automation for developers.
Every WordPress developer has a version of the same bad night: a deploy goes sideways at 11pm, the backup you swore you took last week doesn’t exist, and you’re SSHed into a server trying to remember which folder had the good copy. Manual backups and manual deploys fail for the same reason. They depend on you remembering to do them.
GitHub Actions takes that human step out of the loop. You describe the work once in a YAML file, commit it to your repo, and GitHub runs it for you, either when you push code or on a schedule. In this guide we’ll wire up backups and deployments, walk through the workflow files, and be honest about the parts the examples gloss over.
Table of Contents
- Why Use GitHub Actions for WordPress?
- Prerequisites
- Setting Up GitHub Actions
- Automating WordPress Site Backups
- Automating WordPress Deployments
- Troubleshooting Common Issues
- Best Practices for GitHub Actions in WordPress
- Conclusion
Why Use GitHub Actions for WordPress?
A GitHub Actions workflow is a YAML file that lives in your repo and runs on GitHub’s servers. You pick what triggers it. A push to a branch, a pull request, or a cron schedule are the common ones. When the trigger fires, GitHub spins up a fresh virtual machine, runs your steps, and throws the machine away.
For a WordPress project, that buys you a few concrete things:
- Scheduled backups: Dump your files and database on a cron so you always have a recent recovery point, no reminder needed.
- Hands-off deploys: Push to
mainand let the workflow ship the change to your server. - Consistency across a team: The workflow is the same for everyone, so the deploy doesn’t depend on whose laptop it runs from.
- Fewer mistakes: The repetitive, easy-to-fumble steps run the same way every time.
Prerequisites
Before you write a line of YAML, get these in place:
- A GitHub repository: Your site’s code (theme, plugins, config) should be version-controlled on GitHub.
- Server access: SSH or SFTP into your WordPress host, whether that’s shared hosting, a VPS, or a dedicated box.
- Somewhere to store backups: An external target like Amazon S3, Dropbox, or Google Drive. Keep backups off the server they’re backing up.
- GitHub Secrets: Store every credential (database password, SSH private key, API tokens) in your repo under Settings > Secrets and variables > Actions. Never paste them into the workflow file. Secrets are encrypted and masked in logs; anything hardcoded in YAML is plain text in your repo history.
Setting Up GitHub Actions
Workflows live in the .github/workflows directory. Each YAML file describes the steps to run and the events that trigger them. Here’s a bare setup:
Example of the code
# File: .github/workflows/wordpress-automation.yml
name: WordPress Automation
on:
push:
branches:
- main # Trigger workflow on pushes to the main branch
schedule:
- cron: "0 2 * * *" # Run daily at 2 AM
jobs:
setup:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Install Required Tools
run: |
sudo apt update
sudo apt install -y zip unzip rsync
This is the foundation: it triggers on a push to main or on the daily schedule, then checks out your code and installs the tools the later jobs need. A couple of things worth knowing about that schedule. Scheduled workflows run in UTC, not your local time, so 0 2 * * * is 2 AM UTC. And GitHub disables scheduled runs on a repo after 60 days of no activity, so a rarely-touched backup repo can quietly stop firing. Push a commit or re-enable it in the Actions tab to wake it back up.
One note on the checkout step. The examples in this guide pin actions/checkout@v3, which still works, but the current major version is actions/checkout@v4. When you write your own workflows, use @v4 so you’re on the maintained release.
Automating WordPress Site Backups
Regular backups are the whole point. Here’s a job that compresses your files, dumps the database, and pushes both to an S3 bucket:
Example of the code
jobs:
backup:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Compress WordPress Files
run: |
zip -r wordpress-files.zip /var/www/html
- name: Upload to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 cp wordpress-files.zip s3://your-bucket-name/wordpress-backups/
- name: Backup Database
env:
DB_USER: ${{ secrets.DB_USER }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_HOST: ${{ secrets.DB_HOST }}
DB_NAME: ${{ secrets.DB_NAME }}
run: |
mysqldump -u $DB_USER -p$DB_PASSWORD -h $DB_HOST $DB_NAME > wordpress-db.sql
aws s3 cp wordpress-db.sql s3://your-bucket-name/wordpress-backups/
Read this one carefully before you copy it, because there’s a trap. The runner is a fresh, empty GitHub virtual machine. zip -r wordpress-files.zip /var/www/html zips the runner’s filesystem, not your live server, so that path is empty on GitHub’s box. The same goes for mysqldump pointing at a database it can’t reach.
To back up a real site you need the commands to run against your actual server. Two common ways: give mysqldump a DB_HOST that’s reachable from GitHub’s network, or SSH into the server from the workflow and run the dump and zip there, then copy the artifact out. A self-hosted runner that lives on your infrastructure is another option. Treat the snippet above as the shape of the job, not a drop-in.
Automating WordPress Deployments
Deploys are a cleaner fit for the runner, because you’re pushing from GitHub to your server over SSH. This job uses rsync to sync files up:
Example of the code
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Deploy WordPress Files
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SERVER_USER: ${{ secrets.SERVER_USER }}
SERVER_IP: ${{ secrets.SERVER_IP }}
run: |
echo "$SSH_PRIVATE_KEY" > ssh_key.pem
chmod 600 ssh_key.pem
rsync -avz -e "ssh -i ssh_key.pem" ./wordpress/ $SERVER_USER@$SERVER_IP:/var/www/html/
The private key, the server user, and the IP all come from Secrets, so nothing sensitive sits in the file. rsync only sends what changed, which keeps deploys fast. One gotcha: the first connection to a new host will fail on the host-key check unless you add the server to known_hosts first, usually with an ssh-keyscan step before the rsync.
Troubleshooting Common Issues
You’ll hit friction the first few runs. The usual suspects:
- Permission denied: The SSH key doesn’t have access on the target server, or the user can’t write to the destination path. Check both.
- File path errors: Double-check the paths for your files and database. Remember the runner’s filesystem is not your server’s.
- Failed S3 upload: Confirm the AWS credentials in Secrets are correct and the IAM policy actually allows writes to that bucket.
- Host key verification failed: Add an
ssh-keyscanstep to seedknown_hostsbefore you rsync.
Best Practices for GitHub Actions in WordPress
- Keep secrets in Secrets: Every key, password, and token goes in encrypted GitHub Secrets, never in the YAML.
- Watch the runs: Check the Actions tab regularly. A silently failing backup is worse than no backup, because you’ll trust it.
- Least privilege: Scope SSH keys and API credentials to only what the workflow needs. A deploy key shouldn’t be able to delete your whole bucket.
- Test your restores: A backup you’ve never restored is a guess. Pull one down and rebuild from it at least once.
Conclusion
GitHub Actions turns backups and deploys from things you remember to do into things that just happen. The workflows here are a starting point, not gospel. The backup job in particular needs to actually reach your server before it’s protecting anything, so wire that up and confirm it before you rely on it.
Get it running, watch a few runs land, then restore one backup to prove it works. Once you trust it, you get the best part of automation: you stop thinking about it, and go back to building the site.


