GitHub Action to deploy the wp-content directory of a WordPress site to a remote server using SSH and rsync. This is ideal for deploying themes, plugins, and other customizations directly from GitHub.
-
Generate SSH Key on your local machine:
Run the following command in your terminal (on your local development machine):
ssh-keygen -t rsa -b 4096 -C "deploy@yourdomain.com"When prompted, press Enter to use the default path. This generates two files:
~/.ssh/id_rsa(private key — never share this)~/.ssh/id_rsa.pub(public key)
-
Copy Public Key to the Remote Server:
Use the following command to append your public key to the server's authorized keys:
ssh-copy-id -i ~/.ssh/id_rsa.pub your-user@your-server-ipReplace
your-userandyour-server-ipwith your actual SSH username and IP address of the server. -
Add the following secrets in your GitHub repository:
Go to Settings > Secrets and Variables > Actions and add:
Secret Name Description DEPLOY_HOSTThe IP address or hostname of your server DEPLOY_KEYThe private SSH key (contents of id_rsa)SLACK_WEBHOOK(Optional) Slack webhook for notifications
Your GitHub repository should look like this:
wp-content/
├── plugins/
│ ├── my-plugin/
│ └── another-plugin/
├── themes/
│ └── my-theme/
├── mu-plugins/
├── uploads/ ← excluded from deploy
├── vendor/ ← excluded from deploy
├── composer.json
├── .distignore ← used for custom exclusions
└── .github/
└── workflows/
└── deploy.yml
| Input | Required | Default | Description |
|---|---|---|---|
ssh_host |
Yes | – | The IP/host of the server |
ssh_user |
Yes | – | The SSH username to connect as |
ssh_key |
Yes | – | The private key content (from id_rsa) |
deploy_path |
Yes | – | Full path to the wp-content folder on the server |
site_url |
No | ${{ github.event.repository.name }} |
Used for Slack notification message |
slack_webhook |
No | – | Slack webhook URL |
slack_message |
No | – | Custom Slack message. Auto-generated if not set. |
None explicitly, but it provides:
- Slack notification with status
- Cache flush via WP-CLI if available
The .distignore file allows you to explicitly define which files and folders should be excluded from deployment via rsync. This is useful to prevent unnecessary or sensitive files (like dev tools, cache, logs, or personal editor configs) from being pushed to your production server.
Even without .distignore, this action already excludes many common development and system folders by default, such as:
.git/.github/node_modules/vendor/uploads/,cache/,backups/, etc.
The .distignore file gives you fine control to customize or expand those exclusions as needed.
# Git
/.git
/.github
# Node/npm
node_modules/
yarn.lock
npm-debug.log
# PHP/Composer
/vendor/
composer.lock
# Media / Cache
uploads/
upgrade/
backups/
cache/
# WordPress drop-ins
advanced-cache.php
object-cache.php
db.php
# Editor/OS junk
.idea/
.vscode/
.DS_Store
Thumbs.db
# Misc
*.log
*.sql
*.tar.gz
*.zip
*.bak
*.sh
- name: Deploy site
uses: sultann/wordpress-site-deploy@v1
with:
ssh_host: ${{ secrets.DEPLOY_HOST }}
ssh_user: deploy
ssh_key: ${{ secrets.DEPLOY_KEY }}
deploy_path: /var/www/example.com/wp-content
slack_webhook: ${{ secrets.SLACK_WEBHOOK }}name: Build & Deploy – My WordPress Site
on:
push:
branches:
- master
jobs:
deploy:
name: Deploy to Server
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
tools: composer
- name: Install Composer Dependencies
run: composer install --no-dev --optimize-autoloader
- name: Deploy using WordPress Site Deploy
uses: sultann/wordpress-site-deploy@v1
with:
ssh_host: ${{ secrets.DEPLOY_HOST }}
ssh_user: deploy
ssh_key: ${{ secrets.DEPLOY_KEY }}
deploy_path: /var/www/example.com/wp-content
slack_webhook: ${{ secrets.SLACK_WEBHOOK }}Everything tracked by Git, except:
- Files/folders matched in
.distignore - Common dev junk and build artifacts (see sample above)
If a file is removed from Git and not excluded, it will be deleted from the server.
When the deploy finishes:
- A Slack message is sent if
slack_webhookis set - Auto-includes the
site_urland commit hash - You can override the message with
slack_message
Run this locally to simulate the deploy:
rsync -avzn --delete --exclude-from=.distignore ./ user@server:/var/www/example.com/wp-contentMIT © Sultan Nasir Uddin