Skip to content

Choose your host

shipped 1.0.0

An 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.

cloudronsshftps / sftplocal
Transportthe Cloudron CLIrsync over sshrclonethe filesystem
Commandscloudron execsshnone: WordPress answers through an agentddev
Restore pointcloudron backup createa dump and a tar into .cwp-backups/a dump and a zip into .cwp-backups/, written by the agentnone, refused
Transfer dry runnoyes, file-levelyes, file-levelyes
Logsthe platform log streamWordPress’s own debug.lognoneDDEV’s
Extra requirementcloudron loginan ssh key, wp on PATHrclone, and the password in ~/.netrcnone

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: none makes 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-run on ssh gives a real file-level diff, because rsync has one and cloudron sync does 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 logs and cwp wp refuse. 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-run asks WordPress only when you let it. The agent is a write, and a dry run installs nothing. Pass --with-agent and 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, and wp-content into a ZipArchive. 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: source environment 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.