For WordPress developers · About 15 minutes for first-time setup
The ddev-pressable add-on connects a local DDEV WordPress environment to your Pressable site. Pull the live database and media down to your machine, and push a local copy up to a Pressable site. It runs over the SSH and WP-CLI access your site already has, so there are no API tokens to manage and nothing to install on the platform.
This guide starts from a completely fresh machine with nothing installed. If you already run DDEV day to day, skip ahead to Step 3.
Pushes overwrite the target database. ddev push pressable replaces the remote database with your local one. On a live site that destroys everything created since your local copy: orders, comments, form entries, new posts.
It is strongly recommended that you only ever push to a staging site. See Step 9.
What The Add-On Does (And Doesn’t)
| Direction | What Moves | Command |
|---|---|---|
| Pull, Pressable to local | Database + uploads/ media | ddev pull pressable |
| Push, local to Pressable | Database + uploads/ media | ddev push pressable |
During a pull, the add-on rewrites your site’s URLs so the local copy loads at *.ddev.site instead of your production domain, and it does so safely for serialized data.
The add-on moves the database and uploads, not your theme or plugin code. With this workflow, that code is meant to live in git. If you just want a working local site quickly, Step 7 shows how to copy it down with rsync.
See our guide detailing how to Deploy from GitHub.
What You Need Before You Start
- macOS, Linux, or Windows (WSL2), with permission to install software on your machine
- A Pressable site you administer, with SSH access enabled (on by default for site owners, collaborators require the SFTP/SSH permission)
Step 1 installs everything else.
A note on support. Pressable support can help with SSH access on your site: confirming your public key is attached, checking SSH is switched on, and finding your site’s SSH username. Everything past that point runs on your own machine. For DDEV itself, see the DDEV documentation. For the add-on, use the issue tracker at github.com/pressable/ddev-pressable or log a bug with Pressable support.
Step 1: Install The Local Toolchain
If your machine is new to local development, install these three tools first, in this order. DDEV needs Docker, and mkcert gives you trusted HTTPS on localhost.
1a. Docker
Install Docker Desktop (or another provider DDEV supports, such as OrbStack or Colima) and start it. Confirm it’s running:
docker info
1b. DDEV And mkcert
On macOS with Homebrew:
brew install ddev/ddev/ddev mkcert
On Linux and Windows, follow the DDEV installation docs for your platform, then install mkcert. Check the version afterward. You need v1.24.0 or newer:
ddev version
1c. Trust The Local Certificate Authority
mkcert -install
Don’t use sudo here. Run mkcert -install as yourself. It asks for your password only for the one step that adds the certificate authority to the system trust store. If you sudo the whole command, the CA lands in root’s home directory instead of yours, and DDEV (running as you) can’t read it.
Step 2: Create A WordPress DDEV Project
Make a project folder and configure it as a WordPress site. Swap my-site for whatever you like; it becomes your local URL, https://my-site.ddev.site.
mkdir -p ~/Sites/my-site
cd ~/Sites/my-site
ddev config --project-type=wordpress --project-name=my-site
Pressable runs nginx, so match it locally for parity:
ddev config --webserver-type=nginx-fpm
Start the project and download WordPress core so local WP-CLI has something to work with:
ddev start
ddev wp core download
DDEV writes a working wp-config.php (plus a managed wp-config-ddev.php) and spins up a database container, so WP-CLI can connect locally.
Port conflicts are fine. If ports 80 or 443 are already in use, DDEV picks alternates and prints the real URL, something like
https://my-site.ddev.site:33001. It has no effect on syncing.
Step 3: Install The Pressable Add-On
From inside the project folder:
ddev add-on get pressable/ddev-pressable
It drops two files into .ddev/:
providers/pressable.yaml, the pull and push logicconfig.pressable.yaml, the hook that rewrites URLs after a pull
Commit the .ddev directory so everyone on the project shares the same setup.
Step 4: Set Up SSH Access To Pressable
This is the step most people get stuck on. There are two parts: Pressable has to trust your key, and DDEV has to be able to use it.
4a. Make Sure You Have An SSH Key
If you don’t already have one:
ssh-keygen -t ed25519 -C "you@example.com"
4b. Add Your Public Key To Your Pressable Site
In the MyPressable control panel, open your site’s SFTP/SSH section and paste in your public key (~/.ssh/id_ed25519.pub or ~/.ssh/id_rsa.pub). Confirm that SSH access is enabled for that user, not just SFTP.
See our guide covering how to Connect to SSH on Pressable.
“Authenticated, but still permission denied.” A verbose SSH attempt can print
Server accepts keyand then still refuse the connection. That line does not mean your key is authorized for the site: the gateway acknowledges the key during the handshake and checks it against its own records afterward. Check that the public key is attached to this exact site, and that the SSH username you use belongs to that same site. Pasting a username from another site is an easy mistake.
4c. Tell The Add-On Which SSH User To Use
Every Pressable site has its own SFTP/SSH username. Find it in the SFTP/SSH section on the Overview page of the MyPressable control panel, then set it for this project:

ddev config --web-environment-add="PRESSABLE_SSH_USER=<your-site-ssh-user>"
ddev restart
The host defaults to ssh.pressable.com. To override it, set PRESSABLE_SSH_HOST.
4d. Load Your Key Into DDEV’s SSH Agent
ddev auth ssh
DDEV runs the sync inside its own container, which can’t reach your system keychain, so your key has to be loaded into DDEV’s agent.
Run this in your own terminal. If your key has a passphrase,
ddev auth sshprompts for it, so it can’t run inside a script. The key stays loaded for later commands until you runddev poweroff.
Step 5: Test The Connection First
Before a long sync, check that SSH auth and remote WP-CLI both work. This check is read-only; it changes nothing:
ddev exec ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new \
"$PRESSABLE_SSH_USER@ssh.pressable.com" "wp option get siteurl"
If it prints your production URL, you’re ready to pull. If it says Permission denied, go back to Step 4b.
Step 6: Pull Your Site
Pull the database and media down:
ddev pull pressable
Common variations:
| Goal | Command |
|---|---|
| Database + media (default) | ddev pull pressable |
| Database only (skip large media) | ddev pull pressable --skip-files |
| Media only (leave local DB alone) | ddev pull pressable --skip-db |
| Download without importing | ddev pull pressable --skip-import |
Skip bulky logging tables to speed up a database pull:
ddev config --web-environment-add="PRESSABLE_DB_EXCLUDE_TABLES=wp_actionscheduler_logs,wp_actionscheduler_actions"
Or import only a chosen set of tables. This is advanced, and WordPress needs its core tables to run:
ddev config --web-environment-add="PRESSABLE_DB_TABLES=wp_options,wp_posts,wp_postmeta,wp_users,wp_usermeta"
PRESSABLE_DB_TABLES wins over the exclude list.
A note on timing. Databases are usually often less than 1 gigabyte and land in seconds. Media libraries can run to several gigabytes, so a first full pull can take a few minutes. Once the media is local,
--skip-filesmakes repeat database refreshes quick.
Step 7: Get Your Theme And Plugin Code Locally
The add-on syncs the database and uploads but not code, so a freshly pulled site won’t render until the theme and plugins are present. Two ways to handle it.
Option A: Git (Best For Real Work)
Clone your site’s code repository so wp-content is under version control. This is the workflow most users want long term.
Option B: Copy The Code With rsync (Fastest Way To A Working Site)
You already have SSH access, so pull the theme and plugin code straight off the site. Run these from the project root, and watch the trailing slashes:
# Themes
rsync -azL -e ssh \
<your-site-ssh-user>@ssh.pressable.com:htdocs/wp-content/themes/ \
wp-content/themes/
# Plugins
rsync -azL -e ssh \
<your-site-ssh-user>@ssh.pressable.com:htdocs/wp-content/plugins/ \
wp-content/plugins/
A few things that will save you a headache:
-Lfollows symlinks. Some plugins inwp-content/plugins/are platform-managed symlinks rather than real directories, Jetpack and Akismet among them. Without-L, rsync copies the link itself, which points nowhere on your machine, and it stops outright withcould not make way for new symlink ... cannot delete non-empty directoryif a local directory is already sitting in that spot. WordPress core ships its own copy of Akismet, so that collision is the one people hit first.-Lcopies the real files and avoids both problems.- Copy only
themes/andplugins/. Leave thewp-contentroot drop-ins alone (object-cache.php,advanced-cache.php). They point at caching services that exist on Pressable but not in DDEV, so copying them locally breaks the site. - Platform plugins won’t behave the same locally. Jetpack in particular arrives as real files with no connection to WordPress.com behind it. Deactivate it in your local install if it gets noisy:
ddev wp plugin deactivate jetpack. - You can grab media the same way if you ever need to (
...:htdocs/wp-content/uploads/ wp-content/uploads/), thoughddev pull pressablealready handles uploads.
Which plugins are symlinked changes over time, and some sites have WooCommerce handled as a symlink. So check your own site rather than trusting a list in a guide:
ssh <your-site-ssh-user>@ssh.pressable.com "ls -la htdocs/wp-content/plugins/ | grep '^l'"
Check your work:
ddev wp theme list
ddev wp plugin list
ddev launch # open the local site
Step 8: Check That URLs Were Rewritten
The post-pull hook rewrites siteurl and home to your local *.ddev.site address. DDEV also defines the WP_HOME and WP_SITEURL constants at runtime, so the front end shows the local URL right away.
Confirm the database itself was fully localized, because some plugins tuck absolute URLs into serialized or JSON option values. Compare what’s stored against what’s live:
# Raw value stored in the database
ddev wp db query "SELECT option_value FROM wp_options WHERE option_name='siteurl'"
# Scan for any remaining production references
ddev wp db query "SELECT option_name FROM wp_options WHERE option_value LIKE '%YOUR-PRODUCTION-DOMAIN%'"
If production URLs are still in there, finish the job with a serialized-safe search-replace. Reading the stored value directly keeps the runtime constants from masking it:
ddev wp search-replace 'https://YOUR-PRODUCTION-DOMAIN' 'https://my-site.ddev.site' \
--all-tables-with-prefix --skip-columns=guid
# JSON-encoded options store escaped slashes, so catch those too
ddev wp search-replace 'https:\/\/YOUR-PRODUCTION-DOMAIN' 'https:\/\/my-site.ddev.site' \
--all-tables-with-prefix --skip-columns=guid
Step 9: Push To Pressable
When you’ve made local changes, you can push the database and media back up.
Push to staging only. ddev push pressable overwrites the remote database. On a live site that wipes out everything created since your local copy: orders, comments, form entries, new posts.
The push waits for a confirmation prompt. Don’t skip it with -y. The file push is additive by default, so it never deletes remote media. After a push, the add-on runs wp cache flush on the remote so the object cache picks up the new data.
ddev push pressable # database + media to Pressable
ddev push pressable --skip-files # database only
Match Your Local Environment To Pressable
For the closest match, line up .ddev/config.yaml with your site’s settings from the MyPressable control panel:
| Setting | Recommendation |
|---|---|
| PHP | Set php_version to match your site |
| Web server | webserver_type: nginx-fpm |
| Database | Most MariaDB versions import Pressable dumps fine; use mariadb_version: "10.11" for exact parity |
| WordPress core | Managed separately via git; syncing only moves the database and uploads |
Apply changes with ddev restart.
Command Cheat Sheet
# One-time local setup
brew install ddev/ddev/ddev mkcert
mkcert -install # NOT with sudo
# New project
mkdir -p ~/Sites/my-site && cd ~/Sites/my-site
ddev config --project-type=wordpress --project-name=my-site --webserver-type=nginx-fpm
ddev start && ddev wp core download
# Add-on + SSH
ddev add-on get pressable/ddev-pressable
ddev config --web-environment-add="PRESSABLE_SSH_USER=<your-site-ssh-user>"
ddev restart
ddev auth ssh
# Sync
ddev pull pressable # DB + media down
ddev pull pressable --skip-files # DB only
ddev push pressable # DB + media to Pressable only
# Get code (if not using git)
rsync -azL --exclude='akismet' -e ssh \
<your-site-ssh-user>@ssh.pressable.com:htdocs/wp-content/themes/ wp-content/themes/
rsync -azL --exclude='akismet' -e ssh \
<your-site-ssh-user>@ssh.pressable.com:htdocs/wp-content/plugins/ wp-content/plugins/
ddev launch # open the local site
Summary
- Install Docker, DDEV, and mkcert (
mkcert -installwithoutsudo). - Create and start a WordPress DDEV project.
- Install the add-on:
ddev add-on get pressable/ddev-pressable. - Add your public SSH key to the site, set
PRESSABLE_SSH_USER, and runddev auth ssh. - Test the connection, then
ddev pull pressable. - Bring your theme and plugin code down via git or
rsyncso the site renders. - Push only to staging, and never skip the confirmation prompt.
The add-on is open source. File issues and pull requests at github.com/pressable/ddev-pressable.
Running into errors? See Troubleshooting Pressable DDEV Syncs.