A tiny pure-bash CLI to manage containerized-wordpress releases across multiple WordPress projects on a single host.
It downloads versioned base tarballs from GitHub, applies them to per-project directories, and optionally rebuilds containers — all without needing git installed on the host.
You have several WordPress sites running on the same VPS, each in its own Docker Compose project. They all share the same hardened base image (WordPress + Nginx + PHP-FPM + cron + supervisor) and customize it through a strict override mechanism.
When you ship a new version of the base — fixing a bug, bumping PHP, hardening nginx — you want to roll it out to every site you maintain. Doing this by hand means cd-ing into each project, wget-ing a tarball, extracting it carefully into base/, bumping a version file, rebuilding, restarting. That's a script.
This is that script.
- Linux host (tested on Debian)
bash,curl,tar,sha256sum— all standarddocker composev5.1+ if you want--build(the project compose redefines thewpservice itinclude:s fromcompose.base.yml; v2.x errors withconflicts with imported resource). Install withapt-get install docker-compose-plugin.- Public internet access to
api.github.comandgithub.com
No git on the host. No Python. No jq.
Pick a tagged release:
VERSION=1.0.0
curl -fsSL "https://raw.githubusercontent.com/simonecerruti/wpbase-cli/v${VERSION}/wpbase" \
| sudo tee /usr/local/bin/wpbase > /dev/null
sudo chmod +x /usr/local/bin/wpbaseOr clone and copy:
git clone https://github.com/simonecerruti/wpbase-cli.git
sudo install -m 755 wpbase-cli/wpbase /usr/local/bin/wpbasewpbase reads from /etc/wpbase/:
sudo mkdir -p /etc/wpbase
# Point at the containerized-wordpress repo
echo "https://github.com/simonecerruti/containerized-wordpress" | sudo tee /etc/wpbase/repo
# List your projects (one absolute path per line)
sudo tee /etc/wpbase/projects.list <<'EOF'
/srv/projects/site-one
/srv/projects/site-two
/srv/projects/site-three
EOFLines starting with # are comments. Empty lines are ignored.
An optional /etc/wpbase/self-repo (single line: owner/repo or a URL) points wpbase self-update at its own repo; it defaults to SimoneCerruti/wpbase-cli.
Cache lives in /var/cache/wpbase/ and logs append to /var/log/wpbase.log (both auto-created). Override paths via WPBASE_CONF_DIR, WPBASE_CACHE_DIR, WPBASE_LOG_FILE, and the self-update repo via WPBASE_SELF_SLUG.
wpbase listOutput:
PROJECT VERSION STATUS
/srv/projects/site-one 1.0.0 clean
/srv/projects/site-two 1.0.0 modified
/srv/projects/site-three - not-initialized
Statuses: clean, modified (manual drift detected), missing-base, not-initialized.
wpbase versionsLists tags from containerized-wordpress GitHub releases, newest first.
wpbase install 1.0.0 /srv/projects/new-siteDownloads v1.0.0 and writes base/, .base-version, and a checksum into the project.
On a fresh project it also scaffolds the runnable project-root files from the release templates — docker-compose.yml (from compose.example.yml), .env (from .env.example), and .env.wordpress (from .env.wordpress.example) — only if they don't already exist. Existing files are never overwritten, and wpbase update leaves these project-root files alone entirely.
Then fill in the scaffolded files and keep the secrets out of git:
cd /srv/projects/new-site
$EDITOR .env .env.wordpress # set project name, domain, DB creds, etc.
printf '.env\n.env.wordpress\n' >> .gitignore
docker compose up -d --buildThen add the path to /etc/wpbase/projects.list.
# Dry-run-ish: confirm prompt, no rebuild
wpbase update /srv/projects/site-one --version 1.0.0
# Non-interactive, rebuild and restart
wpbase update /srv/projects/site-one --version 1.0.0 --yes --buildIf you omit --version, the latest GitHub release is used.
# Default: dry-run, shows what would change
wpbase update-all
# Apply with per-project confirmation, no rebuild
wpbase update-all --version 1.0.0
# Apply everywhere, rebuild and restart everything
wpbase update-all --version 1.0.0 --yes --buildupdate-all is dry-run by default. You need to explicitly pass --yes or --build for it to do anything.
wpbase diff /srv/projects/site-oneShows checksum drift and (if drifted) a diff -rq against the freshly fetched tarball.
wpbase verifyA read-only, offline mass drift check across all registered projects. Prints a table like wpbase list and exits non-zero (3) if any project is missing its base/, uninitialised, or drifted — handy in cron/CI.
wpbase uninstall /srv/projects/old-siteRemoves the wpbase-managed base/, base.old/ and .base-version, then untracks the path from projects.list. Prompts unless --yes, and keeps your docker-compose.yml, .env, .env.wordpress, and overrides/.
sudo wpbase self-update # latest release from its own repo
sudo wpbase self-update --version 1.2.0Downloads the wpbase script from its own repo, syntax-checks it, and replaces the installed copy in place (skips if already identical, unless --force). Needs write access to the install path — hence sudo.
| Flag | Meaning |
|---|---|
--version X.Y.Z |
Pin to a specific version (default: latest release) |
--yes / -y |
Skip confirmation prompts |
--build |
Run docker compose build && up -d after update (needs Compose v5.1+) |
--dry-run |
Show what would happen, do nothing |
--force |
Reinstall even if already at the target version |
--help / -h |
Show help and exit |
For each project, wpbase:
- Downloads
https://github.com/<repo>/archive/refs/tags/v<version>.tar.gzinto/var/cache/wpbase/<version>/ - Extracts a subset (
configs/,scripts/,overrides/,Dockerfile.base,compose.base.yml,VERSION) into<project>/.base-staging-XXXXXX/ - Atomically swaps the staging dir into
<project>/base/ - Writes
<project>/.base-versionand<project>/base/.checksum - Optionally runs
docker compose build --no-cache wp && docker compose up -d
Drift detection compares the stored checksum against a fresh hash of base/ on every operation. Drift is warned about, never blocking.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
User error (bad args, missing config, etc.) |
2 |
Network or IO error |
3 |
Drift or partial failure (update-all failures, or verify found drift) |
- GitHub anonymous API rate limit (60 req/hour). Heavy use can hit it.
- No locking. Don't run two
wpbaseinstances simultaneously on the same host. - No automatic rollback. If
--buildfails after a base update, you fix forward. - Linux only. Won't work on macOS without GNU coreutils.
containerized-wordpress— the actual Docker base this CLI manages- Per-project repos — one per WordPress site, each pinned to a specific base version
See CLAUDE.md in this repo for design rationale and contribution guidelines.
MIT