Choose your host
shipped 1.0.0An environment names a provider. The provider decides how files move, how a command runs, how cwp opens a shell and what a restore point is. Four ship.
cloudron | ssh | ftps / sftp | local | |
|---|---|---|---|---|
| Transport | the Cloudron CLI | rsync over ssh | rclone | the filesystem |
| Commands | cloudron exec | ssh | none: WordPress answers through an agent | ddev |
| Restore point | cloudron backup create | a dump and a tar into .cwp-backups/ | a dump and a zip into .cwp-backups/, written by the agent | none, refused |
| Transfer dry run | no | yes, file-level | yes, file-level | yes |
| Logs | the platform log stream | WordPress’s own debug.log | none | DDEV’s |
| Extra requirement | cloudron login | an ssh key, wp on PATH | rclone, and the password in ~/.netrc | none |
provider defaults to cloudron, so a cwp.yml that never mentions it keeps
working.
What each one needs
Cloudron needs cloudron_app, the app location, and package. The second
picks between the two known layouts: managed puts wp-content at
/app/data/wp-content, developer at /app/data/public/wp-content. cwp
derives the remote path from it rather than storing it, and
cwp doctor checks the derivation against the real
remote path.
ssh needs ssh:, whatever you would type after the word ssh, and
path:, the docroot on that host. Both are mandatory. cwp cannot derive a
docroot on a plain host: a plausible guess would send every later transfer
somewhere wrong. An ssh environment without a path is a
configuration error with a message.
ftps and sftp mean shared hosting: an account that moves files and runs
nothing. They need host:, user:, path: and url:. path: is the docroot
as that account sees it. url: has to be https, because cwp calls the agent
over it.
port: only where the host answers somewhere other than 21 and 22, and
host_key: pins the SFTP server’s fingerprint.
There is no password key, on purpose. Git tracks cwp.yml, and a
repository is not a place for one. The password comes from ~/.netrc, where
curl and ftp already look, or from CWP_<ENVIRONMENT>_PASSWORD for a run
that has no home directory.
environments:
live:
provider: sftp
host: www280.example.net
user: sitep
path: /public_html/site
url: https://example.com
machine www280.example.net login sitep password <secret>
Ask for a shell before choosing these. Several hosts that advertise SFTP
also give a real login shell on the same port, and one of them makes this an
ssh environment with more capability and no agent:
ssh -o BatchMode=yes user@host 'echo ok; command -v wp || echo no-wp'
local needs neither. It is a second WordPress on the same machine. It exists so that a project with no remote at all is still a cwp project.
Two things the seam is for, rather than around
The provider is not a compatibility layer that flattens hosts to their lowest common ability. Two differences are visible in the commands, and both are the point:
- Setting
backup: nonemakes an upward write refused, not silently skipped. A host that cannot take a restore point does not get a quieter guard ladder; it gets a refusal. The operator decides. cwp push --dry-runonsshgives a real file-level diff, because rsync has one andcloudron syncdoes not. Same command, sharper plan, and no branch anywhere in the operation that produces it.
The second is why the Cloudron dry run says, in as many words, that a file-level diff is not knowable rather than printing an empty one.
A host that runs no commands
The only thing that executes PHP on shared hosting is the web server. So cwp uploads one PHP file into the docroot, calls it over HTTPS, and removes it when the run ends, however the run ends. The file has a random name, a secret and an expiry good for one run; past its expiry it answers 404 and deletes itself on the first request.
On a slow account that is two transfers per command. cwp agent install live
leaves one in place for a working day instead, and cwp agent remove live takes
it away.
That buys back most of what a shell would do, and four things still differ:
cwp shell,cwp logsandcwp wprefuse. The first two have nothing to attach to; the third is a raw pass-through to a WP-CLI that is not there. Everything cwp wraps still works, because those go through the agent.--dry-runasks WordPress only when you let it. The agent is a write, and a dry run installs nothing. Pass--with-agentand the run installs the file, plans from what the site says, and removes it again; without the flag it refuses and names the flag (ADR-029).- The restore point takes minutes. cwp assembles one instead of asking a
host that has no such thing: the database through WordPress’s own
$wpdb, andwp-contentinto aZipArchive. A web request has a time limit, so it writes both in passes and leaves both in.cwp-backups/on the far side. A large enough site outruns it, and then the run says so rather than half-writing an archive. - A
mode: sourceenvironment cannot be read at all here. Reading it needs the agent, the agent is a write, and no flag opens a source environment.
WP-CLI works everywhere
Everything built on WP-CLI therefore works on every provider: the ability
transport, cwp content,
cwp plugins, the Bricks design system and
doctor’s remote checks. The docroot you configured is where cwp runs it: ssh
lands in your home directory, and wp needs to be where WordPress is.