100 lines
5.2 KiB
Markdown
100 lines
5.2 KiB
Markdown
---
|
|
title: "⬆️ Install, upgrade, backup"
|
|
description: "Bring-up, status, logs, the pinned-image upgrade procedure, and the postgres backup and restore commands for the Coder stack in /home/loca/dev/coder."
|
|
source: "verified deployment on the loca operator host, 2026-08-19"
|
|
reviewed: 2026-08-19
|
|
---
|
|
|
|
# ⬆️ Install, upgrade, backup
|
|
|
|
## 🔑 Ground rules
|
|
|
|
- every docker command needs `sudo -n`; user `loca` is not in the `docker` group, which is intentional because docker group membership grants root-level privileges on the host
|
|
- always run compose from the project root so the project name, `.env` and volume scoping resolve: `cd /home/loca/dev/coder`
|
|
- `.env` holds `CODER_PG_PASSWORD` at mode 600 and is git-ignored; never echo it, copy it into a template, or paste it into a ticket
|
|
- the deployed version is pinned twice on purpose: the image tag in `docker-compose.yml` and the plain-text pin in `config/runtime-version.txt` (currently `v2.35.3`). Both change together or neither changes
|
|
|
|
## 🚀 Bring-up
|
|
|
|
```bash
|
|
cd /home/loca/dev/coder
|
|
sudo -n docker compose up -d
|
|
sudo -n docker compose ps
|
|
curl -sf http://127.0.0.1:52226/healthz
|
|
```
|
|
|
|
- `database` starts first and `coder` waits on its healthcheck (`pg_isready -U coder -d coder`), so a cold start can take a few seconds before `/healthz` answers
|
|
- expected steady state: container `coder` running, container `coder-database` running and healthy, one published socket `127.0.0.1:52226`
|
|
- full proof sequence: [[operations/verification]]
|
|
|
|
## 📋 Status, logs, stop
|
|
|
|
```bash
|
|
cd /home/loca/dev/coder
|
|
sudo -n docker compose ps # both containers, database health
|
|
sudo -n docker compose logs -f coder # server log stream
|
|
sudo -n docker compose logs --tail 200 database
|
|
sudo -n docker compose restart coder # server only, database untouched
|
|
sudo -n docker compose stop # keep containers, stop processes
|
|
sudo -n docker compose down # remove containers, keep named volumes
|
|
```
|
|
|
|
- `down` never removes `coder_pgdata` or `coder_home`; only an explicit `down -v` would, and that destroys every user, template and workspace record
|
|
- restarting `coder` alone is safe and is the normal way to pick up an environment change in `docker-compose.yml`
|
|
|
|
## ⬆️ Upgrade the pinned image
|
|
|
|
Upstream states plainly that Coder does not support rollbacks, so the database snapshot is step one, not an optional extra.
|
|
|
|
```bash
|
|
cd /home/loca/dev/coder
|
|
|
|
# 1. snapshot the database first
|
|
sudo -n docker compose exec -T database pg_dump -U coder coder | gzip > /home/loca/dev/coder/backup-$(date +%F).sql.gz
|
|
|
|
# 2. edit the tag in docker-compose.yml, for example ghcr.io/coder/coder:v2.36.0
|
|
# and write the same value into config/runtime-version.txt
|
|
|
|
# 3. pull and recreate only the server
|
|
sudo -n docker compose pull coder
|
|
sudo -n docker compose up -d coder
|
|
|
|
# 4. verify the running build matches the new pin
|
|
curl -sf http://127.0.0.1:52226/api/v2/buildinfo
|
|
curl -sf http://127.0.0.1:52226/healthz
|
|
curl -sSI https://code.loca.zone/
|
|
```
|
|
|
|
- upstream's docker-compose upgrade path is exactly `pull` then `up -d` for the `coder` service; the database service is left alone unless the postgres major version itself is being changed
|
|
- `buildinfo` is the authority on what is actually running: it reports the semantic version plus commit, the advertised `dashboard_url`, and whether telemetry is enabled
|
|
- if `buildinfo` still shows the old version, the tag edit did not land or `pull` fetched a cached digest; re-check `docker-compose.yml` before restarting anything else
|
|
- a postgres major-version bump is a separate operation: dump with the old image, `down`, change the image, bring up a fresh volume, restore the dump
|
|
|
|
## 💾 Backup and restore
|
|
|
|
```bash
|
|
# backup
|
|
cd /home/loca/dev/coder && sudo -n docker compose exec -T database pg_dump -U coder coder | gzip > /home/loca/dev/coder/backup-$(date +%F).sql.gz
|
|
|
|
# restore
|
|
gunzip -c /home/loca/dev/coder/backup-2026-08-19.sql.gz | sudo -n docker compose exec -T database psql -U coder -d coder
|
|
```
|
|
|
|
- `-T` is required; without it compose allocates a TTY and the dump stream is corrupted by terminal translation
|
|
- the dump carries everything Coder persists: users, templates, template versions, workspace records and Terraform state
|
|
- restore into a running database that is otherwise idle; stop the `coder` service first with `sudo -n docker compose stop coder` so no writes race the restore, then start it again
|
|
- keep at least the snapshot taken immediately before the last upgrade; store it outside the repo tree if it must be retained long-term
|
|
|
|
## 🔁 If an upgrade goes wrong
|
|
|
|
- there is no supported downgrade path, so recovery is: `sudo -n docker compose stop coder`, restore the pre-upgrade dump, set the old tag back in `docker-compose.yml` and `config/runtime-version.txt`, then `sudo -n docker compose up -d coder`
|
|
- verify with `buildinfo` that the old version is live before letting any workspace agent reconnect
|
|
- if only the proxy is broken, nothing about the image needs touching: `sudo -n nginx -t` and the debug order in [[operations/index]] cover that case
|
|
|
|
## 📚 Sources
|
|
|
|
- https://coder.com/docs/install/docker
|
|
- https://coder.com/docs/install/upgrade
|
|
- https://coder.com/docs/admin/setup
|
|
- https://docs.docker.com/engine/install/linux-postinstall/
|