| name | wp-wpengine |
| description | Optional: Use for WP Engine hosting workflows โ SSH-based git push, remote WP-CLI via SSH gateway, GitHub Actions CI/CD with safety-gated deploys to dev/staging/production, managing installs/domains/cache/backups via the wpe-labs Claude Code skills, and WP Engine API access. Requires SSH key setup and WPE_USERNAME/WPE_PASSWORD env vars for API operations. |
| license | GPL-2.0-or-later |
| optional | true |
WP Engine
When to use
- Deploy WordPress code to a WP Engine environment via
git push or GitHub Actions.
- Set up a branch-gated CI/CD pipeline:
develop โ dev, staging โ staging, main โ production.
- Run WP-CLI commands remotely on a WP Engine install (plugin updates, cache flush, DB ops, search-replace).
- Manage WP Engine installs, domains, cache, backups, or users through natural language.
- Generate monthly usage/bandwidth reports across WP Engine accounts.
- Manage LargeFS media offload configuration.
Prerequisites
- SSH key stored in 1Password (
Employee vault, item wpengine_ed25519).
Key type note: RSA 4096-bit is the historically proven key type for WP Engine git push.
Ed25519 is more modern and works on current WP Engine infrastructure, but if you're
setting up a new key, RSA 4096 is the safest choice: ssh-keygen -t rsa -b 4096 -f ~/.ssh/wpengine_rsa
- SSH key registered in the WP Engine portal โ both under Git Push and SSH Keys (two separate registrations, same key).
- WP Engine API credentials in 1Password (
Employee vault, item WP Engine API).
op CLI authenticated (op whoami works).
- SSH gateway access requires a Professional plan or higher.
- The
wpe-labs Claude Code skills installed (~/.claude/skills/wpe-labs:*) for natural language management.
Procedure
1) First-time SSH setup on a new machine
Pull the private key from 1Password and configure SSH:
op read "op://Employee/wpengine_ed25519/private key" > ~/.ssh/wpengine_ed25519
chmod 600 ~/.ssh/wpengine_ed25519
ssh-keyscan -t rsa git.wpengine.com >> ~/.ssh/known_hosts
ssh-keyscan -H <install>.ssh.wpengine.net >> ~/.ssh/known_hosts
Add to ~/.ssh/config (before any Host * block):
# WP Engine git push
Host git.wpengine.com
User git
IdentityFile ~/.ssh/wpengine_ed25519
IdentitiesOnly yes
# WP Engine SSH gateway (WP-CLI + file transfer)
Host *.ssh.wpengine.net
IdentityFile ~/.ssh/wpengine_ed25519
IdentitiesOnly yes
ControlMaster auto
ControlPath ~/.ssh/wpe-%r@%h:%p
ControlPersist 10m
StrictHostKeyChecking accept-new
StrictHostKeyChecking accept-new: automatically accepts and stores the host key on first connection, then rejects any change to that key (MITM protection). Safer than no; avoids having to manually ssh-keyscan each install hostname.
ControlMaster / ControlPersist: multiplexes SSH connections so subsequent commands over the same gateway reuse the existing connection. Cuts per-command latency from ~2 s to ~100 ms for repeated WP-CLI invocations.
Verify git push access:
ssh git@git.wpengine.com info
Verify SSH gateway access (replace <install> with the WP Engine install slug):
ssh <install>@<install>.ssh.wpengine.net wp --info
2A) Deploy via Official WP Engine GitHub Action (recommended)
The official WP Engine GitHub Action uses rsync over SSH โ faster, more flexible than git push, and built/maintained by WP Engine.
Repository: wpengine/github-action-wpe-site-deploy@v3
Required secret
The official action uses WPE_SSHG_KEY_PRIVATE (your SSH private key). The action handles known_hosts automatically โ no keyscan needed.
name: Deploy โ Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build assets
run: npm ci && npm run build
- name: Deploy to WP Engine
uses: wpengine/github-action-wpe-site-deploy@v3
with:
WPE_SSHG_KEY_PRIVATE: ${{ secrets.WPE_SSHG_KEY_PRIVATE }}
WPE_ENV: <install-name>
PHP_LINT: true
CACHE_CLEAR: true
FLAGS: -azvr --inplace --delete --exclude=.* --exclude-from=.deployignore
SCRIPT: "scripts/post-deploy.sh"
scripts/post-deploy.sh (committed to repo, runs on WP Engine after deploy):
#!/usr/bin/env bash
set -e
wp cache flush --skip-plugins --skip-themes
wp rewrite flush --skip-plugins --skip-themes
wp cron event run --due-now --skip-plugins --skip-themes
echo "โ
Post-deploy WP-CLI complete"
.deployignore (rsync exclude list, committed to repo root):
.git
node_modules
.env
.env.*
README.md
.github
package.json
package-lock.json
pnpm-lock.yaml
composer.json
composer.lock
*.test.*
tests/
Key options:
| Option | Description |
|---|
WPE_ENV | Install slug. Alias: PRD_ENV, STG_ENV, DEV_ENV for multi-env workflows |
SRC_PATH | Deploy subdirectory of repo (trailing slash = contents only) |
REMOTE_PATH | Destination on WP Engine (defaults to WP root) |
PHP_LINT | true to run PHP lint pre-deploy |
FLAGS | rsync flags. Default: -azvr --inplace --exclude=.* |
SCRIPT | Post-deploy bash script (relative to WP root on server) |
CACHE_CLEAR | true to clear page + CDN cache post-deploy (default: true) |
Multi-environment workflow:
on:
push:
branches: [develop, staging, main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: wpengine/github-action-wpe-site-deploy@v3
with:
WPE_SSHG_KEY_PRIVATE: ${{ secrets.WPE_SSHG_KEY_PRIVATE }}
DEV_ENV: ${{ github.ref == 'refs/heads/develop' && '<install>dev' || '' }}
STG_ENV: ${{ github.ref == 'refs/heads/staging' && '<install>stg' || '' }}
PRD_ENV: ${{ github.ref == 'refs/heads/main' && '<install>' || '' }}
CACHE_CLEAR: true
Secret name difference: The official action uses WPE_SSHG_KEY_PRIVATE. Our custom git-push workflows use WPE_SSH_KEY. Both are the same private key โ just stored under different secret names.
2B) Deploy via git push (alternative)
Always get the exact remote URL from the WP Engine portal โ it includes the environment prefix:
https://my.wpengine.com/installs/<ENV>/git_push
The URL format is: git@git.wpengine.com:<environment>/<install-name>.git
where <environment> is production, staging, or development.
git remote add wpengine-prod git@git.wpengine.com:<install-name>.git
git remote add wpengine-staging git@git.wpengine.com:<install-name>stg.git
git remote add wpengine-dev git@git.wpengine.com:<install-name>dev.git
Deploy:
git push wpengine-prod main
git push wpengine-staging staging:main
- WP Engine deploys the pushed branch automatically.
- Only WordPress files are pushed โ not
node_modules, build artifacts, or .git/.
- After push, allow 1โ2 min for propagation.
Verify the remote URL: git remote -v should show git@git.wpengine.com:production/<install>.git.
If it shows git@git.wpengine.com:<install>.git (no environment prefix), update it โ that is an older format that may no longer work.
3) WP-CLI via SSH gateway
WP Engine's SSH gateway host is {install}.ssh.wpengine.net with username {install}.
The WordPress root on the server is /home/wpe-user/sites/{install}.
Method A โ Direct SSH command (simplest)
ssh <install>@<install>.ssh.wpengine.net wp <command>
WP-CLI on WP Engine already knows the WordPress path, so --path is usually not required. If needed:
ssh <install>@<install>.ssh.wpengine.net wp plugin list --path=/home/wpe-user/sites/<install>
Always use --skip-plugins --skip-themes on production for safety:
ssh <install>@<install>.ssh.wpengine.net \
wp cache flush --skip-plugins --skip-themes
Method B โ WP-CLI --ssh flag
WP-CLI's native --ssh flag runs any command against a remote install without logging in first:
wp --ssh=<install>@<install>.ssh.wpengine.net:/home/wpe-user/sites/<install> plugin list
wp --ssh=<install>@<install>.ssh.wpengine.net cache flush
Method C โ wp-cli.yml aliases (best for repeated use)
Create or update wp-cli.yml in your local repo root:
@production:
ssh: <install>@<install>.ssh.wpengine.net
path: /home/wpe-user/sites/<install>
@staging:
ssh: <install>stg@<install>stg.ssh.wpengine.net
path: /home/wpe-user/sites/<install>stg
Then use the alias for any command:
wp @production plugin list --format=json
wp @staging cache flush
wp @production db export - > backup-$(date +%F).sql
wp @production search-replace 'old-domain.com' 'new-domain.com' --dry-run
Commit wp-cli.yml to the repo so all team members and CI pipelines share the same remote aliases.
Method D โ SCP / rsync for file transfer
The SSH gateway also accepts SCP and rsync (port 22). Use this to pull/push files without a full git push:
scp -P 22 <install>@<install>.ssh.wpengine.net:sites/<install>/wp-content/uploads/large-file.zip ./
scp -P 22 ./my-patch.php <install>@<install>.ssh.wpengine.net:sites/<install>/wp-content/plugins/my-plugin/
rsync -avz --progress \
-e "ssh -p 22" \
<install>@<install>.ssh.wpengine.net:sites/<install>/wp-content/uploads/ \
./local-uploads/
rsync -avz --dry-run \
-e "ssh -p 22" \
./my-theme/ \
<install>stg@<install>stg.ssh.wpengine.net:sites/<install>stg/wp-content/themes/my-theme/
WP Engine server path: WordPress root is sites/<install>/ relative to the SSH home, or /home/wpe-user/sites/<install> as an absolute path. wp-content/ lives inside that root.
Method E โ Multiple commands via heredoc
Run several commands in one SSH session without reconnecting:
ssh <install>@<install>.ssh.wpengine.net bash -s << 'EOF'
set -e
wp cache flush --skip-plugins --skip-themes
wp rewrite flush --skip-plugins --skip-themes
wp cron event run --due-now --skip-plugins --skip-themes
wp core version --skip-plugins --skip-themes
EOF
ssh -t <install>@<install>.ssh.wpengine.net wp shell
SSH gateway environment notes
- Restricted shell: The gateway provides a limited shell environment. WP-CLI, PHP, basic POSIX utilities (echo, cat, stat, du, find, grep) and rsync/SCP are available. Package installation (
apt, yum), sudo, and arbitrary service management are not available.
- PHP version: Matches the PHP version configured for that WP Engine install.
php --version to confirm.
- WordPress path:
~/sites/<install>/ (relative to SSH home) or /home/wpe-user/sites/<install> (absolute).
--path flag: If WP-CLI returns "not a WordPress installation", add --path=/home/wpe-user/sites/<install> explicitly.
- Legacy gateway:
ssh.wpengine.net (no subdomain) is the old generic gateway address. Current convention always uses <install>.ssh.wpengine.net.
4) Common remote WP-CLI operations
Always run --dry-run or a read-only check first. All examples use Method C aliases.
Inspect the environment
wp @production cli info
wp @production option get siteurl
wp @production option get home
wp @production core version
Plugin and theme management
wp @production plugin list --format=json
wp @production plugin update woocommerce
wp @production plugin update --all --dry-run
wp @production plugin update --all
wp @production plugin activate <slug>
wp @production plugin deactivate <slug> --skip-plugins --skip-themes
Cache flush (always safe post-deploy)
wp @production cache flush
wp @production rewrite flush
wp @production transient delete --all
Database operations
wp @production db export - > backup-$(date +%F-%H%M).sql
wp @production db size --tables --format=table
wp @production db query "SELECT option_name, option_value FROM wp_options WHERE autoload='yes' LIMIT 20"
Search and replace (migration / domain change)
wp @production search-replace 'http://old-domain.com' 'https://new-domain.com' \
--dry-run --report-changed-only
wp @production search-replace 'http://old-domain.com' 'https://new-domain.com' \
--precise --report-changed-only
wp @production cache flush && wp @production rewrite flush
See wp-wpcli-and-ops skill โ references/search-replace.md for full search-replace patterns.
User management
wp @production user list --role=administrator --format=table
wp @production user create tempagent temp@example.com --role=administrator --user_pass=<strong-pass>
wp @production user delete tempagent --reassign=1
Cron inspection and triggering
wp @production cron event list --format=table
wp @production cron event run --due-now
wp @production cron event run <hook-name>
5) Remote database access
WP Engine provides three methods to access the remote database. No IP allowlisting required.
Method A โ wp db query via SSH gateway (simplest, recommended)
No extra tools or credentials needed โ connects through the authenticated SSH tunnel:
ssh <install>@<install>.ssh.wpengine.net wp db query 'SELECT post_title FROM wp_posts LIMIT 10;'
ssh <install>@<install>.ssh.wpengine.net wp db export - > backup-$(date +%F).sql
wp @production db export - > backup-$(date +%F).sql
wp @production db query 'SELECT option_name, option_value FROM wp_options WHERE autoload="yes" LIMIT 20;'
Method B โ SSH tunnel + GUI tool (MySQL Workbench, Sequel Ace, TablePlus)
First retrieve the DB password from the server:
ssh <install>@<install>.ssh.wpengine.net \
wp config get DB_PASSWORD --skip-plugins --skip-themes
ssh <install>@<install>.ssh.wpengine.net \
"grep WPENGINE_SESSION_DB_PASSWORD ./sites/<install>/_wpeprivate/config.json"
Start an SSH tunnel with local port forwarding:
ssh -L 3307:127.0.0.1:3306 <install>@<install>.ssh.wpengine.net
Connect your GUI tool with:
| Field | Value |
|---|
| Connection method | TCP/IP over SSH (or plain TCP once tunnel is open) |
| SSH hostname | <install>.ssh.wpengine.net |
| SSH username | <install> |
| SSH key file | ~/.ssh/wpengine_ed25519 |
| MySQL host | 127.0.0.1 |
| MySQL port | 3306 (Workbench/Sequel Ace) or 3307 (other tools via tunnel) |
| Database username | <install> |
| Database password | from DB_PASSWORD / WPENGINE_SESSION_DB_PASSWORD |
| Database name | wp_<install> |
MySQL Workbench: Use Standard (TCP/IP) over SSH connection type โ it handles the tunnel internally, no separate ssh -L needed.
Sequel Ace: Use SSH connection type. If connection times out, increase timeout to 60s in Network settings.
TablePlus, DBeaver, DataGrip: Use TCP mode after opening the ssh -L 3307:... tunnel manually.
DB credentials location on server
ssh <install>@<install>.ssh.wpengine.net grep "DB_" sites/<install>/wp-config.php
ssh <install>@<install>.ssh.wpengine.net cat sites/<install>/_wpeprivate/config.json
DB name format: wp_<install> (e.g., wp_mysite). The session password in config.json as WPENGINE_SESSION_DB_PASSWORD may rotate โ prefer DB_PASSWORD from wp-config.php for persistent access.
6) Pull WP Engine environment to local Playground
Full DB + search-replace workflow for local development:
wp @development db export - > /tmp/wpe-dev-$(date +%F).sql
wp db import /tmp/wpe-dev-$(date +%F).sql
wp search-replace 'https://dev.yoursite.wpengine.com' 'http://localhost:9400' \
--precise --report-changed-only
wp cache flush && wp rewrite flush
wp option update upload_url_path 'https://dev.yoursite.wpengine.com/wp-content/uploads'
upload_url_path: A WordPress option (wp_options) that overrides the base URL
for all uploaded media. Setting it to the remote server's uploads path means your
local WordPress loads real images from production/staging without syncing any files.
Much faster than rsync for GBs of media. Reset it with wp option delete upload_url_path
before deploying.
Partial-sync alternative: If you've copied over some recent uploads locally (to
regenerate image sizes etc.) but want older months to fall back to production,
use BE Media from Production
instead. It filters image URLs by date range rather than redirecting everything.
upload_url_path is simpler and works well when you have no local uploads at all.
To also sync actual upload files (when you need local file access, not just URLs):
rsync -avz --dry-run \
-e "ssh -p 22" \
myinstall@myinstall.ssh.wpengine.net:sites/myinstall/wp-content/uploads/ \
./wp-content/uploads/
See wp-bootstrap skill โ scripts/pull-wpe-env.sh for the full automated version.
For full branch-gated deploys with safety guards, pre-deploy backups, smoke tests, and auto-rollback:
Read: references/github-actions-deploy.md
CI gate policy โ no --no-verify:
- All lint, typecheck, tests, and build checks must pass before any push reaches a deploy branch.
--no-verify is explicitly forbidden. Hooks exist to surface problems early โ bypass them and you own the breakage.
- The CI gate runs two parallel jobs (
php-gate + js-gate) for every push to a protected branch. Required status check.
- Every deploy workflow runs a
verify job as its first dependency โ deploys never start without it passing.
Read: references/ci-gate.md
Agent-runnable scripts:
| Script | Purpose | When to use |
|---|
scripts/ci-gate.sh | Run the full local CI gate (PHP + JS/TS) | Before any push to a deploy branch |
scripts/wpe-preflight.sh | Pre-deploy sanity checks (SSH, WP, HTTP) | Before triggering a deploy |
scripts/wpe-check.sh | SSH connectivity to all configured installs | After machine setup or debugging SSH |
Run CI gate locally:
bash {baseDir}/scripts/ci-gate.sh
Run pre-deploy preflight:
INSTALL=mysite bash {baseDir}/scripts/wpe-preflight.sh production
Check all SSH connections:
bash {baseDir}/scripts/wpe-check.sh
10) wpe-labs skills (natural language management)
Load API credentials, then use any /wpe-labs:* skill:
eval $(op run --env-file ~/.config/op-ssh/.env.1pass -- env | grep ^WPE | sed 's/^/export /')
| Skill | What it does | Risk |
|---|
/wpe-labs:account-usage | Bandwidth, visits, storage across accounts | ๐ข Read-only |
/wpe-labs:monthly-report | Client-ready monthly usage report | ๐ข Read-only |
/wpe-labs:backups | On-demand backups + progress monitoring | ๐ก Write |
/wpe-labs:cache | Purge object/page/CDN cache | ๐ก Write |
/wpe-labs:users | List, invite, update roles, remove users | ๐ก/๐ด |
/wpe-labs:domains | Manage domains, DNS, SSL | ๐ก/๐ด |
/wpe-labs:installs | List, create, copy WordPress installs | ๐ก/๐ด |
/wpe-labs:offload | LargeFS media offload config | ๐ก Write |
Example prompts:
/wpe-labs:account-usage which accounts are closest to their bandwidth limit?
/wpe-labs:cache purge all cache for uofdev production
/wpe-labs:backups back up uofdev production before deployment
/wpe-labs:installs copy uofdev production to staging
/wpe-labs:monthly-report last month
11) Re-installing wpe-labs skills
curl -fsSL https://raw.githubusercontent.com/wpengine/wpe-labs-platform-skills/main/install.sh | bash
Verification
| Check | Command |
|---|
| Git push SSH | ssh git@git.wpengine.com info โ hello <user> / R W <install> |
| SSH gateway | ssh <install>@<install>.ssh.wpengine.net wp --info |
| WP-CLI alias | wp @production core version |
| API credentials | `op run --env-file ~/.config/op-ssh/.env.1pass -- bash -c 'curl -s -u "$WPE_USERNAME:$WPE_PASSWORD" https://api.wpengineapi.com/v1/user |
Safety guardrails for remote operations
- Always
--dry-run first for any search-replace or destructive DB operation.
- Always export a DB backup before schema changes or large search-replaces.
- Use
--skip-plugins --skip-themes on production for cache flush, deactivations, and anything where a broken plugin might short-circuit the operation.
- Prefer staging for testing WP-CLI commands before running on production.
- ControlMaster is safe โ it reuses an existing authenticated session; no new credentials are stored.
- wpe-labs write operations (
backups, cache, installs, users, domains) should be confirmed before execution.
Failure modes
| Symptom | Fix |
|---|
Host key verification failed (git) | ssh-keyscan git.wpengine.com >> ~/.ssh/known_hosts |
Host key verification failed (gateway) | Run ssh-keyscan -H <install>.ssh.wpengine.net >> ~/.ssh/known_hosts for that specific install hostname. Or add StrictHostKeyChecking accept-new to the *.ssh.wpengine.net SSH config block โ it will auto-accept on first connect. |
Permission denied | Confirm key at ~/.ssh/wpengine_ed25519, chmod 600. Check the key is registered under SSH Keys in the WP Engine portal (separate from git push keys). |
git push rejected | Get the exact URL from the portal (https://my.wpengine.com/installs/<ENV>/git_push). URL format varies by account โ copy it verbatim. |
| SSH gateway hangs | Kill stale ControlMaster socket: ssh -O stop <install>@<install>.ssh.wpengine.net |
wp: command not found on gateway | WP Engine's WP-CLI path: try php /usr/local/bin/wp or contact WP Engine support |
| WP-CLI returns wrong site | Add --path=/home/wpe-user/sites/<install> explicitly |
401 Unauthorized (wpe-labs) | Regenerate API credentials at https://my.wpengine.com/api_access, update 1Password item |
storage shows zero (wpe-labs) | Ask to "refresh storage" (async recalculation, ~30โ60 s) |
References
- WP Engine SSH gateway docs:
https://wpengine.com/support/ssh-gateway/
- WP Engine git push portal:
https://my.wpengine.com/installs/<ENV>/git_push
- WP Engine SSH Keys portal:
https://my.wpengine.com/ssh_keys
- WP Engine API access:
https://my.wpengine.com/api_access
- WP-CLI
--ssh docs: https://make.wordpress.org/cli/handbook/guides/running-commands-remotely/
- wpe-labs skills source:
https://github.com/wpengine/wpe-labs-platform-skills
- SSH setup log (first machine): gist
602d6a16ddfea438c0611a8e5cc31d5e