In an effort to consolidate and save a little bit of money I’ve recently moved all my projects off DeployHQ and moved them to a free alternative: GitHub Actions.
I work almost exclusively on WordPress plugins and themes that use a combination of Composer and Node scripts, and I want to automatically run these scripts and deploy the built files to my server over SSH. In this post, I’ll share how I accomplished this with GitHub Actions in just a few lines of code.
In your GitHub repository, create a new file in the .github/workflows
folder called deploy.yml
with the following content:
name: Deploy
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: none
- name: Install Composer dependencies
run: composer install --no-dev
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install npm dependencies
run: npm install
- name: Build
run: npm run build
- name: Deploy to server via SSH
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SERVER_USERNAME: ${{ secrets.SSH_USER }}
SERVER_HOST: ${{ secrets.SSH_SERVER }}
DEPLOY_DIR: ${{ secrets.SSH_PATH }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts
rsync -avz --delete -e "ssh -o StrictHostKeyChecking=no" --exclude-from='.distignore' ./ $SERVER_USERNAME@$SERVER_HOST:$DEPLOY_DIR
If the .github/workflows
folder doesn’t already exist you can create it yourself by running this command in the root of your repository:
mkdir -p .github/workflows
This action takes a few different steps in order, whenever a new commit is pushed to main
:
- Check out the current repository
- Install PHP (you can replace
8.3
with your desired PHP version) - Install Composer dependencies (uses
--no-dev
which ensures no dev dependencies get installed) - Install npm
- Run the npm build script (replace
npm run build
with your own build script if necessary) - Use rsync to copy files to your remote server over SSH
To make this work, you need to set a few secrets in the repository settings.

Set the following secrets:
SSH_SERVER | the IP address of your server |
SSH_PATH | the path to upload the files to (.e.g ~/files/wp-content/plugins/my-plugin/ ) |
SSH_USER | the username you use to SSH into your server |
SSH_KEY | the private key you use to connect to your server |
rsync only supports keys in PEM format, which you can generate using this command:
ssh-keygen -m PEM -t rsa -b 4096
This generates a public/private key pair. The private key, which starts with -----BEGIN RSA PRIVATE KEY----
, needs to be set as the SSH_KEY
repository secret, and the public key needs to be added to the ~/.ssh/authorized_keys
file on your server in order to connect.
The last rsync step looks a little complicated, but is actually fairly straightforward. It creates a new ~/.ssh
folder (where your SSH keys are stored), copies the private key to this folder, gives it the correct permissions and connects to your server to get the known hosts.
It then copies the files over using rsync, while ignoring any files that are present in the .distignore
file in your repository root. This is super useful to prevent copying over files you don’t want or need. Here’s an example:
bin
node_modules
src
.*
composer.json
composer.lock
license.txt
README.md
package.json
package-lock.json
webpack.config.js
Add the .distignore
file to your own repository root and choose which files and folders to ignore— these will not be copied over when the action is run.
.*
means “any file or folder that starts with a .
“, so it automatically ignores all dotfiles such as .editorconfig
as well as hidden folders like .github
and .vscode
.
If you want to include specific dotfiles (for example .env
), you can add this on the line below: !.env
Hopefully this helps you deploy your own projects using GitHub Actions! If you want to learn more about actions and see what else is possible I encourage you to check out the official docs.
Leave a Reply