Skip to content
EntryWick documentation

For whoever runs EntryWick on their organization's own server.

The entrywick command (self-hosted, week 21)

The tool that installs a self-hosted EntryWick on a server and keeps it running: install, update, backup, restore, doctor, and compose for everything else. A reference of what each command does and refuses; step by step: requirements.md, install.md, update.md, backup.md. PRICING_ENTITLEMENTS §5, ADR-019, ADR-020.

Who opens it: whoever runs EntryWick on their organization's own server.

What they came to do: install, update, back up or check an instance — and know what a command will and will not do before running it during an event season.

What must be true when they leave: the instance runs a release EntryWick signed for their license's channel, a failed update has put the previous release back, and nothing they ran stopped check-in at a live event without them saying --force.

What the server needs

Docker Engine 24+ with the Compose v2 plugin (2.24+), php8.3-cli (Ubuntu 24.04's own package — the tool uses no extension beyond it), ports 80 and 443 free, and the size for the events it runs:

Attendees per event vCPU Memory
up to 2,000 2 4 GB
up to 10,000 4 8 GB

At least 20 GB free disk (40 GB recommended); amd64 only. Run it as root. Everything else — DNS, ports, outbound access: requirements.md. entrywick.phar is published with every release, next to its SHA-256 and a Sigstore bundle; install it as /usr/local/bin/entrywick (install.md, step 6). It works in /opt/entrywick unless --dir= or EW_DIR says otherwise.

Commands

Command Does Refuses
entrywick install Checks the server, asks for the domain, the organization, its address and timezone, the Owner's name and email, and the license key (not echoed); writes .env (mode 600: random database passwords, a new APP_KEY, EW_HOSTING=self_hosted); verifies the release's signature, pulls it by digest and takes the stack files out of that image; starts MySQL and Redis; has the app check the license key; migrates and seeds; starts everything; asks the app whether it takes the organization's answers (ew:instance:organization --check: its reserved addresses and existing accounts) and asks again for any it refuses, then for the Owner's password (not echoed, twice), and creates the organization the key names with its Owner; says hello to the license server; checks health and the certificate. Every answer can be an option instead (entrywick help install); secrets come from a prompt or a file, never an argument. Answers are kept in .entrywick/install.json for a second run; an option given then replaces the kept answer, and an answer the app refused is never kept. --version=X.Y.Z installs that release instead of the tool's own; entrywick --version alone prints the tool's version. A server below the requirements (unless --skip-requirements), without Docker, or with 80/443 taken; a release not signed for the key's channel; a key the app does not accept (exit 7) — after .env is written and MySQL and Redis are started, but before any table or organization is created.
entrywick update Reads the license through the app (ew:license:check --heartbeat --json), takes the newest release on its channel (or --to=X.Y.Z), verifies its signature, backs up, pulls, swaps the stack files and version, up, migrates, re-seeds platform rows, rebuilds live counters, caches, restarts Horizon, and checks health. --check only says whether a release is waiting. A license that does not allow updates — expired, missing, unverifiable or revoked (exit 3); a live event without --force (exit 4); a tag not signed for the channel (exit 5); a beta on the stable channel; an older version.
entrywick backup ew:backup in the app, then copies that dump out and checks its checksum, archives the storage volume's files and copies .env, into backups/<time>/ with a manifest of checksums. Keeps 5 (--keep=N). --list lists them. Safe during an event. A backup disk other than local.
entrywick restore <backup> Checks every checksum, stops the workers, unpacks the files, loads the dump (ew:restore), migrates to the running release, re-seeds, restarts everything and checks health. Puts the backup's APP_KEY into .env when it differs (the restored encrypted columns need it). Without the backup's name typed (or --force); a live event without --force; a backup made by a newer release; a file that does not match its checksum — all before touching anything.
entrywick doctor Containers up and healthy, app:healthz (and backup ages), /up, Horizon, the certificate's days left, free disk, the license's condition, the newest local backup. Changes nothing. — (exit 0 all well, 1 warnings, 2 failures)
entrywick compose … docker compose with this install's files, like staging's bin/ew: entrywick compose logs -f horizon.

When an update fails

Any failure after the pull rolls back on its own: the previous stack files and .env.version, the previous image, and — only when the failed release's migrations changed the database — the database from the backup taken at the start of the update. Migrations only go forward, so an older release cannot run on a newer schema; the backup is the way back, and whatever was written between that backup and the rollback is lost. That is why an update refuses to run during a live event unless told --force. Files stored meanwhile are kept.

It then exits 10 ("rolled back to …"). If the rollback itself does not come back healthy it exits 11, keeps .entrywick/update.json, and names the backup to restore. An update cut short — a closed SSH window — is finished with entrywick update --rollback; until then update refuses and doctor reports it.

Releases and signatures

A release is a git tag: vX.Y.Z is stable, vX.Y.Z-beta.N is beta. The release workflow pushes the image as X.Y.Z and once per channel it is on — stable-X.Y.Z and beta-X.Y.Z for a stable release (the beta channel gets every release), beta-X.Y.Z-beta.N for a beta — and signs it once per channel with Sigstore keyless signing, annotated channel and version.

Before it pulls anything, entrywick runs cosign verify from Sigstore's own image, pinned by digest, and requires a certificate issued by GitHub Actions (https://token.actions.githubusercontent.com) to .github/workflows/release.yml in entrywickapp-coder/entrywick, run for a version tag, with the channel and version annotations of the license and target. It then pulls and runs the signed digest: .env.version holds EW_VERSION=X.Y.Z and EW_IMAGE_DIGEST=@sha256:…, and the Compose overlay runs image:version@digest, so a tag moved afterwards changes nothing. The Compose files, Caddy and backup configuration come out of that same image — the files the cloud runs, for that version.

Exit codes

Code Meaning
0 Done (doctor: all well)
1 Failed, see the message (doctor: warnings)
2 Wrong usage, or the server does not meet the requirements (doctor: failures)
3 The license does not allow updates
4 An event is live; nothing was done
5 Not signed for the license's channel; nothing was pulled
6 The update stopped before anything changed
7 The app did not accept the license key
10 The update failed and was rolled back
11 The update failed and the rollback did not come back healthy