TMA CloudTMA Cloud
GuidesOperations

Updating

Update a Docker install to a new version with update.sh.

Update a Docker install to a new version with update.sh.

When a new version is published, Settings → Updates in the web and desktop apps shows it to the administrator, with a link to its release notes and to this page.

Run an Update

setup.sh puts update.sh in the install directory. Run it there:

cd tma-cloud
./update.sh

Without a local copy, for example on an install made before update.sh existed:

curl -fsSL https://raw.githubusercontent.com/TMA-Cloud/TMA/main/update.sh | bash

The containers that change are recreated, so the app is unavailable for a short time.

What It Does

  1. Downloads and checks the new files. compose.yml, .env.example, setup.sh, rotate.sh, db-backup-restore.sh, and update.sh are downloaded over HTTPS only. Each script must start with #!/usr/bin/env bash and pass bash -n, and the new compose.yml must load with your .env and compose.override.yml. If any check fails, nothing is changed.
  2. Updates itself. When update.sh changed, the new copy replaces the old one and runs the rest of the update.
  3. Backs up the database. pg_dump writes backups/pre-update-<time>.dump before the new version runs its migrations. The dump is checked with pg_restore --list. If the backup fails, nothing is changed.
  4. Replaces the files. The old versions are copied to .update/backup-<time>/. See Files You Edited.
  5. Updates .env. Renamed settings get their new name, and new settings are added. See New Settings.
  6. Pulls the new images and restarts. The running app image is first tagged tma-cloud/tma:pre-update-<time>, then docker compose pull and docker compose up -d --wait run. The script ends when the containers are healthy and prints the version that is now running.

Each file is written to a temporary name in the same directory and renamed into place, so an interrupted update leaves the old file or the new one, never half of one. Scripts are saved with mode 0700, .env, compose.yml, and .env.example with 0600.

Files You Edited

setup.sh and update.sh record the SHA-256 hash of each file they install in .tma-manifest. On the next update:

Current fileResult
Same as the new versionLeft as is
Same as the recorded hashReplaced; the old file goes to .update/backup-<time>/
Different from both (you edited it)Kept; the new version is saved as <name>.new with a warning
No recorded hash (install from before update.sh)Replaced; the old file goes to .update/backup-<time>/

To replace edited files as well, run TMA_FORCE=1 ./update.sh. The edited copies are backed up first.

Put local changes to the stack in compose.override.yml instead of compose.yml. Docker Compose merges it automatically, and updates never touch it:

services:
  app:
    image: ghcr.io/tma-cloud/tma:<tag>
  worker:
    image: ghcr.io/tma-cloud/tma:<tag>

New Settings

Settings that were renamed keep their values under the new name: NODE_ENV becomes APP_ENV, and AUDIT_WORKER_CONCURRENCY becomes WORKER_CONCURRENCY. If .env already sets the new name, the old line is left alone and listed as unused. A copy of .env from before the change is saved in .update/backup-<time>/.

Settings that the new .env.example has and .env lacks are added at the end of .env under # Added by update.sh on <time>, with the comment lines above each one. No other line is changed, so passwords and keys stay as they are. The script lists the renamed and added settings; review their values.

Settings in .env that the new version no longer reads are listed as safe to remove. They are not removed.

A copy of the current .env.example is kept in the install directory for its comments.

Options

VariableEffect
TMA_DIRInstall directory (default: the current directory)
TMA_REFGit branch or tag to download the files from (default: main)
TMA_NO_START=1Update the files only: no database backup, pull, or restart
TMA_SKIP_DB_BACKUP=1Skip the database backup
TMA_NO_PULL=1Use the image already on the machine, for example one built from source
TMA_FORCE=1Replace files you edited too

Example: TMA_REF=v<tag> ./update.sh

Kept Backups

  • The last 3 database dumps in backups/
  • The last 5 file backups in .update/
  • One previous app image, tma-cloud/tma:pre-update-<time>

Roll Back

Migrations only move forward, so going back to the previous image also needs the database from before the update.

  1. Stop the app and the worker:

    docker compose stop app worker
  2. Restore the dump with the backup script. It asks you to type the database name. Because the app and the worker are already stopped, it leaves them stopped:

    ./db-backup-restore.sh restore backups/pre-update-<time>.dump

    The dump goes into a scratch database first, so a failed restore leaves the current database as it was. See Database Restore.

  3. Set the previous image for app and worker in compose.override.yml:

    services:
      app:
        image: tma-cloud/tma:pre-update-<time>
      worker:
        image: tma-cloud/tma:pre-update-<time>
  4. Copy the files you need back from .update/backup-<time>/, then start the stack:

    docker compose up -d

Files uploaded after the backup are left in the bucket without a database row. Find them with Orphan Review.

If an Update Fails

  • A download or check fails: Nothing was changed. Run it again later.
  • The database backup fails: Nothing was changed. Check that the postgres container is running.
  • The pull fails: The files were updated, but the running containers were not changed. Run ./update.sh again.
  • The containers do not become healthy: The script prints the paths of the database dump, the file backup, and the previous image. Check docker compose logs app, then fix the cause or roll back.
  • "Another update is running": Remove .update.lock if no update is running.

update.sh does not run while rotate.sh is running, and the other way round, because both rewrite .env.

Last updated on

On this page