Updates & versioning
One-command server updates, and how desktop versions follow.
Updating a self-hosted Proliferate is one command on the server. The server image bakes in the compiled Web app, so pulling a new image updates the Web app and the API atomically, in the same step; there is no separate Web deployment to coordinate. Connected desktop apps follow the update automatically too; you never coordinate a separate desktop rollout.
Update the server
Run ./update.sh from your deploy directory (the extracted
proliferate-deploy bundle you deployed from). Under the hood it runs the
sequence:
Pull
Pull the server image at the tag configured in .env.static
(PROLIFERATE_SERVER_IMAGE_TAG).
Migrate
Run database migrations in a one-shot container before the new server starts.
Restart
Restart the stack (docker compose up -d).
The script also re-checks that generated secrets exist, refreshes the runtime
binaries on the host under /opt/proliferate/bin when the cloud sandboxes
add-on's runtime-binary variables
are set, and health-checks the stack before it exits, so a completed run
means the new version is actually serving.
Model gateway operators: update.sh also pulls, restarts, and
health-waits on litellm/litellm-db automatically whenever
AGENT_GATEWAY_ENABLED=true — the same one command covers the gateway, no
separate profile command needed. See
Model gateway. Installs without the
gateway can ignore this.
To confirm the version after an update:
Version pinning: a release tag vs stable
The server image is ghcr.io/proliferate-ai/proliferate-server, published
with per-release version tags and a stable tag. You choose which one you
track with PROLIFERATE_SERVER_IMAGE_TAG in .env.static:
- Pin a release tag (for example
0.3.0) for change-controlled environments.update.shthen only moves you when you edit the tag, so an update is an explicit, reviewable change. - Track
stableto pick up releases whenever you runupdate.sh, with no file edits.
Releases are published on GitHub as server-vX.Y.Z, and the deploy bundle
(proliferate-deploy.tar.gz) is attached to each release. The support
intent is N releases back: staying a few releases behind is fine, and
update.sh is the one operator motion that catches everything up.
How desktops stay in lockstep
The server you run is the version root for the whole fleet:
GET /metaon your server reportsserverVersion,desktopVersion,runtimeVersion, andminDesktopVersion. Each server release is stamped with the desktop and runtime versions it shipped with.- Connected desktop apps check
GET /desktop/updater/latest.jsonon your server, which responds with a 302 redirect to the official CDN update manifest for the version your server pins. When the manifest for that exact version is not published (a server built ahead of a desktop release, or a release that predates versioned manifests), the server redirects to the latest stable manifest instead, so update checks always land on a valid manifest. Your server carries only a version number; it never builds or serves desktop binaries. - The desktop app verifies every update against the signing key baked into the official build, no matter which endpoint served the manifest. A server can choose which version desktops run, but it can never ship a modified build.
minDesktopVersionis the compatibility floor: desktops older than it are told to update before they can keep working against your server.
The net effect: when you run update.sh, your users' apps converge on the
matching desktop version on their own.
Data retention & backups
There is no built-in backup command yet; back up these two things on whatever schedule your organization requires.
1. The database. Everything about your orgs, users, sessions, and
invitations lives in the db service's named volume (Postgres). If you
enabled the model gateway, its
litellm-db volume holds LiteLLM's own keys and spend records separately.
Back up either with pg_dump against the running container, or a volume
snapshot:
Taking a backup before running ./update.sh is cheap insurance, since
migrations move the schema forward and are not designed to move backward.
2. Host-side config and key material, which the database backup above does not cover:
| Path | Why it matters |
|---|---|
.env.generated | The JWT signing secret and the credential-encryption key. Losing this file without a backup means every session is invalidated and stored credentials become unrecoverable — restoring the database alone is not enough. |
.env.static / .env.local | Your configuration. Reconstructible by hand from this doc, but faster to restore from a copy. |
GITHUB_APP_PRIVATE_KEY_HOST_PATH (default /opt/proliferate/secrets/github-app) | The GitHub App's private key, if you configured cloud sandboxes. Re-downloadable from GitHub if lost, but faster to back up. |
Caddy's caddy_data / caddy_config volumes | Issued TLS certificates. Not critical — Caddy reissues them automatically on next boot if lost — but backing them up avoids a brief re-issuance window. |
Restore verification. After restoring the database volume and
.env.generated onto a fresh host running the same server version, boot the
stack and confirm GET /health and GET /meta respond, then sign in as an
existing user — a successful sign-in confirms the JWT/encryption keys and the
user data are consistent with each other. Do not restore .env.generated
from one backup and the database from a different one; they must be a
matched pair, or existing sessions and encrypted credentials will not decrypt.
- Data is kept until you delete it. The server does not yet ship automated retention windows for session data; scheduled purging is on the roadmap. If you have a hard retention requirement today, get in touch.
- Telemetry is separate from retention and is covered in Telemetry & privacy.