Skip to content

GitHub Actions

.github/workflows-templates/deploy.yml builds the site on GitHub and syncs the result to the server over SSH. The server only receives files — it does not need Composer or Node.

JobWhat it does
composercomposer install --no-dev and an optimized autoloader — vendor, WordPress core, plugins and mu-plugins
nodenpm ci and npm run build in the theme — assets/dist
deployWaits for both, rsyncs everything to the server, clears the Twig cache and runs the optional post-deploy command

composer and node run in parallel. Their builds are cached: the Composer build on composer.json and composer.lock, the Node build on the theme’s package-lock.json, assets/src and build config, so an unchanged build is not rebuilt.

TriggerEnvironment
Push to mainproduction
Push to developstaging
Actions → Deploy → Run workflowChosen when starting the run

GitHub only runs workflows in .github/workflows/, so the template does nothing until it is moved there.

  1. Create the production and staging environments under Settings → Environments, and add the secrets and variables below.

  2. Make sure the server already has its .env and web/.htaccess, see Deployment.

  3. Set the repository variable DEPLOY_DRY_RUN to true and DEPLOY_ENABLED to true.

  4. Move the workflow into place and push:

    Terminal window
    git mv .github/workflows-templates/deploy.yml .github/workflows/deploy.yml
  5. Check the Rsync step of the run: it lists what would change on the server without changing it. When it looks right, remove DEPLOY_DRY_RUN.

To pause deploys, set DEPLOY_ENABLED to anything but true, or move the workflow back to .github/workflows-templates/.


Add these per environment, or as repository secrets when both environments share them.

SecretDescription
COMPOSER_AUTHContents of auth.json on a single line, used to install ACF Pro. Repository secret, the composer job runs outside an environment
SSH_PRIVATE_KEYPrivate key of a deploy user on the server
SSH_KNOWN_HOSTSOutput of ssh-keyscan -p <port> <host>
SSH_HOSTServer hostname or IP
SSH_USERSSH user
VariableDescription
DEPLOY_ENABLEDtrue to run the workflow. Repository variable, the build jobs run outside an environment
DEPLOY_PATHAbsolute path to the app root on the server (the folder containing web, not web itself)
SSH_PORTOptional, defaults to 22
DEPLOY_DRY_RUNOptional, true runs rsync --dry-run and skips the cache clear and post-deploy command
POST_DEPLOY_COMMANDOptional, run in DEPLOY_PATH after the sync, e.g. wp cache flush

The sync uses rsync --delete: files on the server that are not in the repository or the build are removed. The excludes in the Rsync step are left alone, which by default covers:

  • .env, auth.json, web/.htaccess, web/nginx.conf
  • web/app/uploads, web/app/languages
  • Cache folders and drop-ins (cache, timber-cache, object-cache.php, advanced-cache.php, …)
  • Database dumps and logs (*.sql*, *.log)

  • rsync available to the SSH user on the server
  • The PHP version in the workflow (php-version) matches the server