This is the setup that deploys this site. Every push to master runs a GitHub Actions job that connects to the server over SSH and resets the theme folder to the new commit. There’s no build step and no FTP, and a deploy takes about 20 seconds.
1. Create a dedicated deploy key
Use a key that exists only for deployments, without a passphrase, so you can revoke it without touching your personal key.
ssh-keygen -t ed25519 -f ~/.ssh/theme_deploy -N "" -C "github-actions-deploy"
2. Authorise the key on the server
ssh USER@HOST "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys" < ~/.ssh/theme_deploy.pub
ssh -i ~/.ssh/theme_deploy -o IdentitiesOnly=yes USER@HOST "echo ok"
If the second command prints ok, the key works on its own. If it fails, check /var/log/auth.log on the server: it names the exact reason.
3. Clone the theme on the server
cd /var/www/html/wp-content/themes
git clone https://github.com/YOUR_USER/YOUR_THEME.git your-theme
For a private repository, add a read-only deploy key to the repository settings and clone over SSH instead.
4. Add the GitHub secrets
In the repository, open Settings → Secrets and variables → Actions and add:
VPS_HOST: the server’s IP or hostnameVPS_USER: the SSH userVPS_SSH_KEY: the full contents of~/.ssh/theme_deploy, including the BEGIN and END linesVPS_THEME_PATH: the absolute path of the theme folder
5. Write the workflow
Create .github/workflows/deploy.yml:
name: Deploy theme
on:
push:
branches: [master]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy over SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
set -e
cd "${{ secrets.VPS_THEME_PATH }}"
git fetch origin master
git reset --hard origin/master
chown -R www-data:www-data .
find . -type f -exec chmod 644 {} ;
find . -type d -exec chmod 755 {} ;
git reset --hard makes the server match the repository exactly, so a deploy can never leave half-edited files behind. Never edit theme files directly on the server: the next deploy overwrites them.
6. Test and troubleshoot
Push a commit and open the Actions tab. Common failures:
unable to authenticate, attempted methods [none publickey]: the server doesn’t accept the key. Repeat step 2 and check that the secret contains the private key, not the.pubfile.Permission deniedonchown: the SSH user isn’t root. Run those lines withsudoand allow them in sudoers, or drop them if the user already owns the folder.- The change doesn’t appear: the theme’s stylesheet is cached. Bump the version in
style.cssso WordPress requests the new file.