Upgrade Temps
Temps includes a self-upgrade command that downloads the latest release from GitHub, verifies its checksum, and replaces the binary atomically. Database migrations run automatically on the next restart.
Check your current version
temps --version
Output:
v0.0.6 (abc1234) built 2026-03-04 12:34:56 UTC
Check for updates
See if a newer version is available without installing it:
temps upgrade --check
Or use the health check command, which includes an update check along with other system diagnostics:
temps doctor
If a newer version exists, you will see:
WARN Update: v1.1.0 available - run 'temps upgrade' to update
Back up before upgrading
Before any upgrade, create a backup of your data:
If you have S3 backup storage configured:
Trigger a manual backup from the dashboard (Settings > Backups > Run Backup) or via the API.
If you do not have S3 configured:
At minimum, back up the Temps data directory and database:
# Back up the data directory (contains encryption key, auth secret, GeoLite2 DB)
cp -r ~/.temps ~/.temps-backup-$(date +%Y%m%d)
# Back up the PostgreSQL database
docker exec temps-timescaledb pg_dumpall -U postgres | gzip > temps-db-backup-$(date +%Y%m%d).sql.gz
The ~/.temps/encryption_key file is critical — it encrypts managed service credentials. If this file is lost, you cannot decrypt stored passwords. Always include it in your backups.
Run the upgrade
Upgrade to the latest version
temps upgrade
If the binary is in a root-owned location (e.g. /usr/local/bin/temps):
sudo temps upgrade
The upgrade process:
- Detects your platform (Linux/macOS, x86_64/ARM64)
- Fetches the latest release from GitHub
- Compares versions — exits if already up to date
- Shows the upgrade plan (current version, target version, download size)
- Asks for confirmation
- Downloads the release tarball
- Verifies the SHA-256 checksum (if available)
- Replaces the binary atomically (write to temp file, then rename)
Options
# Upgrade to a specific version (ignores the channel)
temps upgrade --version v1.1.0
# Skip the confirmation prompt
temps upgrade --yes
# Track a release channel (stable is the default)
temps upgrade --channel beta
# Upgrade a binary at a different path
temps upgrade --path /opt/temps/bin/temps
| Flag | Default | Description |
|---|---|---|
--channel <stable|beta> | stable | Which release stream to track. See Release channels. |
--version <vX.Y.Z> | latest in channel | Pin a specific version. Bypasses channel filtering entirely. |
--path <path> | currently running binary | Path to the temps binary to replace. |
--yes, -y | off | Skip the confirmation prompt. |
--check | off | Preview the planned upgrade without installing. |
The old boolean --stable flag still works but is deprecated and hidden — it is an alias for --channel stable (which is the default anyway) and will be removed in a future release. Use --channel stable instead.
Other upgrade methods
temps upgrade is the recommended path because it verifies the checksum and swaps the binary atomically. These alternatives exist for installs that were set up with the deploy script or that prefer a one-shot command.
Upgrade script (deploy.sh installs)
If you installed Temps with deploy.sh, the upgrade script handles everything in one command — it backs up your encryption key, downloads the latest binary, upgrades Localup if tunnel mode is detected, and restarts the services:
curl -fsSL https://temps.sh/upgrade.sh | bash
To pin a specific version:
curl -fsSL https://temps.sh/upgrade.sh | bash -s vX.Y.Z
Re-run the installer
The installer downloads the latest binary for your platform and replaces the one at ~/.temps/bin/temps, preserving all configuration, data, and certificates. It accepts the same --channel flag as temps upgrade:
# Latest stable (default)
curl -fsSL https://temps.sh/install.sh | bash
# Latest beta
curl -fsSL https://temps.sh/install.sh | bash -s -- --channel beta
Then restart the service (see Restart Temps).
Manual download
Download a release tarball directly from GitHub, extract it, and replace the binary:
curl -LO https://github.com/gotempsh/temps/releases/latest/download/temps-linux-amd64.tar.gz
tar -xzf temps-linux-amd64.tar.gz
sudo mv temps /usr/local/bin/temps
sudo systemctl restart temps
To pin a version, swap latest/download for download/vX.Y.Z.
Release channels
temps upgrade tracks one of two release streams, selected with --channel:
| Channel | Selects | Notes |
|---|---|---|
stable (default) | Non-prerelease GitHub releases only | Tags without a - suffix, e.g. v1.2.0. |
beta | Both stable and prerelease releases | Includes tags like v1.2.0-beta.4 or v1.2.0-rc.1. |
Running temps upgrade with no flags always lands on stable.
Because GitHub returns releases newest-first and beta accepts both kinds, a beta host always upgrades to the freshest available version — including a newly shipped stable that supersedes the latest beta on the same line. The runtime decision is GitHub's prerelease flag on each release (draft releases are never selectable on either channel), not literal tag-string parsing.
Channel selection is CLI-only by design — there is no environment-variable fallback. You must pass --channel beta explicitly on each invocation to opt into prereleases. This prevents a long-lived shell or CI environment variable from silently switching a host onto beta.
Pinning a specific --version ignores the channel entirely and fetches that exact release directly.
The install.sh installer
The curl-pipe installer accepts the same --channel flag with matching semantics (default stable, accepts only stable or beta):
# Install the latest stable release (default)
curl -fsSL https://temps.sh/install.sh | bash
# Install the latest beta release
curl -fsSL https://temps.sh/install.sh | bash -s -- --channel beta
Stable resolves through GitHub's /releases/latest endpoint (which returns the newest non-prerelease); beta takes the newest tag from /releases?per_page=20. Passing an explicit version positional argument ignores the channel. One divergence from the Rust CLI: the bash installer does not filter draft releases — it trusts that the GitHub API only returns shipped releases, whereas the CLI explicitly skips drafts.
Restart Temps
The upgrade replaces the binary but does not restart the running process. You need to restart manually.
If running under systemd (typical server setup)
sudo systemctl restart temps
If you run the proxy as a separate process:
sudo systemctl restart temps-proxy
If running in a terminal
Stop the current process (Ctrl+C) and start it again:
temps serve
Database migrations
Migrations run automatically when temps serve starts. There is no separate migration command. When the server boots, it:
- Connects to PostgreSQL
- Runs all pending migrations (120-second timeout)
- Backfills any new TimescaleDB continuous aggregates
- Starts serving traffic
If migrations fail, the server will not start. Check the logs for the specific migration error.
Verify the upgrade
After restarting:
# Check the version
temps --version
# Confirm the service is healthy
curl -sf http://localhost:8081/health
# Run diagnostics
temps doctor
The doctor command checks:
- Data directory integrity
- Encryption key presence
- Database connectivity and version
- TimescaleDB extension
- Migration count
- Docker daemon availability
- External connectivity (GitHub API, Docker Hub, Let's Encrypt)
- Git providers and DNS providers
If everything passes, your upgrade is complete. Visit the dashboard to confirm it loads correctly.
Upgrade the database
TimescaleDB runs as a Docker container and is upgraded independently of Temps:
# Pull the latest image
docker pull timescale/timescaledb-ha:pg18
# Stop and remove the old container (data persists in the volume)
docker stop temps-timescaledb
docker rm temps-timescaledb
# Start with the new image
docker run -d \
--name temps-timescaledb \
--restart unless-stopped \
-e POSTGRES_USER=temps \
-e POSTGRES_PASSWORD="YOUR_DB_PASSWORD" \
-e POSTGRES_DB=temps \
-p 127.0.0.1:5432:5432 \
-v temps-db-data:/home/postgres/pgdata/data \
timescale/timescaledb-ha:pg18
# Restart Temps to reconnect
sudo systemctl restart temps
Your database password is stored in ~/.temps/.wizard-state/db_password if you used the deploy script.
Switch to Enterprise Edition
temps upgrade --tier ee switches a running install from the open-source binary (the default) to the Enterprise Edition (EE) binary. The EE binary lives in a license-gated proxy, so you must supply a license JWT.
temps upgrade --tier ee --license-path /path/to/license.jwt
EE currently ships linux-amd64 only. On any other platform the command fails early — macOS and arm64 EE builds are on the roadmap. The EE binary refuses to start without a valid license, so you must restart the service after switching.
EE flags
| Flag | Default | Description |
|---|---|---|
--tier <oss|ee> | oss | Which edition to install. oss downloads from GitHub releases. CLI-only — no env-var fallback. |
--license-path <path> | — | Path to the EE license JWT. Required with --tier ee. |
--ee-api <url> | https://temps.sh | Base URL of the Temps Cloud EE proxy (--tier ee only). A trailing slash is trimmed. |
--data-dir <path> | $TEMPS_DATA_DIR, else ~/.temps | Data dir whose data/license.jwt receives the license. Also reads the TEMPS_DATA_DIR env var. |
If you pass --tier ee without --license-path, the command errors with:
--tier ee requires --license-path <path-to-license.jwt>. Download yours from https://temps.sh/dashboard/license
What the switch does
- Validates the license JWT shape before downloading anything. The CLI decodes (but does not verify the signature — the EE binary checks the signature at boot) and rejects: malformed JWTs that are not three dot-separated segments, any
tierclaim that is notpremiumorenterprise, and licenses whoseexpclaim is already in the past. - Resolves the version — the pinned
--version, or the latest from<ee-api>/api/ee/releases. - Fetches the checksum and tarball from
<ee-api>/api/ee/download/<version>/<asset>/sha256and<ee-api>/api/ee/download/<version>/<asset>, authenticating with the license JWT as anAuthorization: Bearerheader. The asset name istemps-ee-<version-without-v>-linux-amd64.tar.gz. The checksum is verified before the swap. - Replaces the current binary atomically.
- Copies the license to
<data-dir>/data/license.jwt(mode0600). - Best-effort systemd wiring (Linux only): if
/etc/systemd/system/temps.serviceexists and does not already contain aTEMPS_EE_LICENSE_PATH=line, the upgrader insertsEnvironment=TEMPS_EE_LICENSE_PATH=<installed-license-path>after the[Service]header and runssystemctl daemon-reload, so the binary finds its license on every restart. If the variable is already present it is left untouched; non-Linux hosts and missing units are skipped silently.
Use --check to preview the planned switch without installing, and -y/--yes to skip the confirmation prompt. After the switch, restart the service to activate:
sudo systemctl restart temps
Upgrade Localup (tunnel)
If you use tunnel mode and are not using the upgrade script, upgrade the localup binary separately:
curl -fsSL https://localup.dev/install.sh | bash
# Restart the tunnel service
sudo systemctl restart localup-tunnel # Linux
launchctl kickstart -k gui/$(id -u)/dev.temps.localup-tunnel # macOS
The upgrade.sh script handles this automatically when tunnel mode is
detected.
Rolling back
Downgrade to a specific version by passing it to the upgrade command:
temps upgrade --version vX.Y.Z
If the new version added database migrations, restoring from a pre-upgrade backup is the safest path:
# 1. Restore the database backup
docker exec -i temps-timescaledb psql -U temps temps < temps-backup-YYYYMMDD.sql
# 2. Downgrade the binary
temps upgrade --version vX.Y.Z
# 3. Restart
sudo systemctl restart temps
Rolling back database migrations is not automatically supported. If a new version added migrations, restoring the database from a pre-upgrade backup is the safest way to revert.
Troubleshooting
Service fails to start after upgrade
# Check logs for errors
sudo journalctl -u temps -n 50 --no-pager # Linux
tail -50 ~/.temps/logs/temps.log # macOS
# Common fix: ensure data directory permissions are correct
chmod 700 ~/.temps/data
chmod 600 ~/.temps/data/encryption_key
Database migration errors
Migrations run on startup and the server will not start if they fail. Confirm the database is reachable, then read its logs:
# Check that the database is reachable
docker exec temps-timescaledb pg_isready -U temps
# Check database logs
docker logs temps-timescaledb --tail 50
If the database container is not running, start it first:
docker start temps-timescaledb