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.
| Job | What it does |
|---|---|
composer | composer install --no-dev and an optimized autoloader — vendor, WordPress core, plugins and mu-plugins |
node | npm ci and npm run build in the theme — assets/dist |
deploy | Waits 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.
| Trigger | Environment |
|---|---|
Push to main | production |
Push to develop | staging |
| Actions → Deploy → Run workflow | Chosen when starting the run |
GitHub only runs workflows in .github/workflows/, so the template does nothing until it is moved there.
-
Create the
productionandstagingenvironments under Settings → Environments, and add the secrets and variables below. -
Make sure the server already has its
.envandweb/.htaccess, see Deployment. -
Set the repository variable
DEPLOY_DRY_RUNtotrueandDEPLOY_ENABLEDtotrue. -
Move the workflow into place and push:
Terminal window git mv .github/workflows-templates/deploy.yml .github/workflows/deploy.yml -
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/.
Secrets
Section titled “Secrets”Add these per environment, or as repository secrets when both environments share them.
| Secret | Description |
|---|---|
COMPOSER_AUTH | Contents of auth.json on a single line, used to install ACF Pro. Repository secret, the composer job runs outside an environment |
SSH_PRIVATE_KEY | Private key of a deploy user on the server |
SSH_KNOWN_HOSTS | Output of ssh-keyscan -p <port> <host> |
SSH_HOST | Server hostname or IP |
SSH_USER | SSH user |
Variables
Section titled “Variables”| Variable | Description |
|---|---|
DEPLOY_ENABLED | true to run the workflow. Repository variable, the build jobs run outside an environment |
DEPLOY_PATH | Absolute path to the app root on the server (the folder containing web, not web itself) |
SSH_PORT | Optional, defaults to 22 |
DEPLOY_DRY_RUN | Optional, true runs rsync --dry-run and skips the cache clear and post-deploy command |
POST_DEPLOY_COMMAND | Optional, run in DEPLOY_PATH after the sync, e.g. wp cache flush |
What is synced
Section titled “What is synced”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.confweb/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)
Requirements
Section titled “Requirements”rsyncavailable to the SSH user on the server- The PHP version in the workflow (
php-version) matches the server

