Compose: Upgrading from the legacy zulip/docker-zulip image
Zulip Server 11.x and earlier shipped as zulip/docker-zulip on
Docker Hub. The 12.x series moved to ghcr.io/zulip/zulip-server,
with a number of breaking configuration changes along the way. This
page covers the one-time work needed to migrate; once you’re on the
new image, future upgrades follow the standard
Compose: Upgrading flow.
If you’ve already migrated, you don’t need this page.
Plan and back up
Back up first. This is a major upgrade and the volume layout changes (see below); a backup is the simplest way to make rolling back tractable. See backing up Zulip data.
docker compose exec zulip /sbin/entrypoint.sh app:backup docker compose run --rm -v zulip:/data -v $(pwd):/backup zulip \ tar czf /backup/backup.tar.gz -C /data .
Snapshot your current configuration. The checkout in the next section will overwrite your edited
docker-compose.yml. Save a reference copy first so you can translate settings from it:cp docker-compose.yml ../docker-compose.yml.legacy-backup
What changed
Image
zulip/docker-zulip on Docker Hub is replaced by
ghcr.io/zulip/zulip-server on GitHub Container Registry. The Docker
Hub image will receive no further updates after the Zulip Server 11.x
series is end-of-life.
Configuration layout
Local configurations are expected to live in
compose.override.yaml, which you copy from the trackedcompose.override.yaml.exampletemplate. The shippedcompose.yamlis no longer expected to be edited.Secrets are no longer environment variables in two places in
compose.yaml; they have moved to use Docker secrets. See Compose: Secrets management.
Setting renames and removals
DB_HOSTandDB_HOST_PORThave been replaced bySETTING_REMOTE_POSTGRES_HOSTandSETTING_REMOTE_POSTGRES_PORT, respectively, to align with standard Zulip settings.DB_USERandDB_NAMEhave been replaced withCONFIG_postgresql__database_userandCONFIG_postgresql__database_name, respectively.REMOTE_POSTGRES_SSLMODEhas been removed; the standard spellingSETTING_REMOTE_POSTGRES_SSLMODEis used instead.DISABLE_HTTPSandSSL_CERTIFICATE_GENERATIONhave been replaced with the singleCERTIFICATESsetting; the default is now HTTP-only, since most Docker deployments are behind an existing proxy. See Compose: Configuring TLS.SPECIAL_SETTING_DETECTION_MODEhas been removed; its behavior was confusing and at odds with its name.NGINX_PROXY_BUFFERINGhas been removed; setting it could only break things.NGINX_WORKERShas been replaced with the genericCONFIG_application_server__nginx_worker_processes.PROXY_ALLOW_ADDRESSESandPROXY_ALLOW_RANGEShave been replaced with the genericCONFIG_http_proxy__allow_addressesandCONFIG_http_proxy__allow_ranges.QUEUE_WORKERS_MULTIPROCESShas been replaced with the genericCONFIG_application_server__queue_workers_multiprocess.
Volume layout
Contents of the named zulip Docker volume have been reorganized:
certificates are stored in certs/ subdirectories (self-signed,
certbot, and manual), and LINK_SETTINGS_TO_DATA contents are
stored in etc-zulip/ rather than settings/etc-zulip/. Files are
moved to these new locations automatically on first startup with the
new image.
Migrate to the 12.x layout
Discard local edits to the tracked compose file.
git checkoutrefuses to overwrite a file with uncommitted modifications, and you already have your reference copy saved from the previous section. Either reset:git checkout -- docker-compose.yml
or stash:
git stash push -m "legacy compose customizations" docker-compose.yml
Fetch and check out the first 12.x release tag, on a local branch so subsequent upgrades follow the same pattern:
git fetch --tags git checkout -B release 12.0-0
The compose configuration file is now
compose.yaml(notdocker-compose.yml).Move your secrets into a
.envfile. See Store secrets in a .env file for the full mapping; copy eachZULIP__*value out of your olddocker-compose.yml.legacy-backupand into.env.Build your override file from the example, then translate settings:
cp compose.override.yaml.example compose.override.yaml
Edit it to translate your previous local settings, applying the renames in the section above. The skeleton looks like:
secrets: zulip__postgres_password: environment: "ZULIP__POSTGRES_PASSWORD" zulip__memcached_password: environment: "ZULIP__MEMCACHED_PASSWORD" zulip__rabbitmq_password: environment: "ZULIP__RABBITMQ_PASSWORD" zulip__redis_password: environment: "ZULIP__REDIS_PASSWORD" zulip__secret_key: environment: "ZULIP__SECRET_KEY" zulip__email_password: environment: "ZULIP__EMAIL_PASSWORD" services: zulip: environment: # Include all settings starting with SETTING_ from your old # docker-compose.yml, plus any of the renamed settings above.
Set
CERTIFICATESif needed. If you had not previously setDISABLE_HTTPS, or had setSSL_CERTIFICATE_GENERATION, you will need to setCERTIFICATES; see Compose: Configuring TLS.
Bring the new image up
docker compose pull
docker compose up -d
The first boot performs the volume reorganization described above,
along with any database migrations. Watch the logs with
docker compose logs -f zulip, looking for
=== End Initial Configuration Phase === to confirm a clean start.