Install
Quick start (Docker Compose)
Section titled “Quick start (Docker Compose)”mkdir stoop && cd stoopR=https://github.com/getstoop/stoop/releases/latest/downloadcurl -fLO $R/docker-compose.ymlcurl -fLO $R/livekit.yamlcurl -fLO $R/livekit-entrypoint.shcurl -fL -o .env $R/env.example# edit .env — at minimum set POSTGRES_PASSWORDdocker compose up -dThe four files come from the release itself, so they always match the
image the compose file pins. The compose file needs Docker Compose 2.20 or
newer (docker compose version).
Open http://localhost:8080. A fresh instance walks you through setup: create the admin account (the first account operates the server), create your first space, and copy an invite link for your people. Later, the Invite button in a space’s header makes more.
docker compose ps shows stoop as healthy once it has migrated the
database and is answering. Container logs are capped at 30 MB a service.
To let people in from outside the machine, see Reaching your server. Voice works once its media has a reachable path: see Voice.
Upgrading
Section titled “Upgrading”Fetch the stoop binary for the machine once, then run its upgrade
verb from the install directory whenever a release is out (Server admin
→ About says when one is):
curl -fsSL https://github.com/getstoop/stoop/releases/latest/download/stoop_linux_amd64.tar.gz | tar -xz stoop./stoop upgrade(stoop_linux_arm64.tar.gz and stoop_darwin_arm64.tar.gz are the
other builds.) It fetches the newest release’s compose file, shows what
that release’s migrations will do to the database and which releases can
still start against it afterwards, lists settings the release’s
env.example has that your .env does not, and asks. Then it backs up
the database and the uploads into backups/ (readable by your user
only; the dump is the whole database), keeps the old bundle files as
.prev (docker-compose.yml, livekit.yaml, livekit-entrypoint.sh),
puts the new ones in place and starts. A docker-compose.override.yml
beside the compose file is honoured, in the plan as well as the start. If
the new release does not come up healthy it prints the log and the way
back. ./stoop upgrade --plan stops after showing; --to 0.4.0 picks a
release; --yes skips the question. The copy you fetched keeps working
for later releases: the judgment about the database comes from the new
image, not from this binary.
Release notes say when the LiveKit or Postgres pin moves. Moving to a new Postgres major is the one thing the tool refuses to do; see Supported Postgres and LiveKit versions.
Going back. ./stoop upgrade rollback puts the previous compose file
back and restarts. Each release keeps its schema readable by the release
before it, so this needs no restore, unless the upgrade ran a contract
migration: the tool says so before it upgrades, and rollback refuses
afterwards and points at the backup it took
(Restoring in place). Stoop refuses to start
against a database that a much newer release has reshaped, and says so
plainly, rather than misbehaving.
By hand. The tool only runs compose commands you can run yourself. Fetch the new release’s compose file, ask the new image what it will do while the old one is still running, then restart on it; migrations run at startup, so there is no separate step:
curl -fLO https://github.com/getstoop/stoop/releases/latest/download/docker-compose.ymldocker compose run --rm --no-deps stoop migrate plandocker compose pull && docker compose up -dmigrate plan lists the migrations that will run and says which
releases can still start against the database afterwards, which is the
rollback you will have. It changes nothing. Exit status 2 means there is
something to run, 3 that the release is older than the database. Rolling
back by hand is putting the previous image tag back in the compose file
and docker compose up -d again.
Coming from 0.2.0, add COMPOSE_PROFILES=bundled-postgres to .env
first. Without it the bundled Postgres does not start, and the log says
lookup postgres: no such host.
An image tag of the form 0.2 follows patch releases of that minor;
latest follows everything. Both exist for people who prefer them to the
pinned tag.
Supported Postgres and LiveKit versions
Section titled “Supported Postgres and LiveKit versions”Stoop is tested on Postgres 16, which the compose file runs. Other majors that Postgres itself still supports should work, but are not tested; if you run one and something breaks, that is a bug worth reporting. A patch or minor release of Stoop never raises the minimum Postgres major; if a future release has to, the notes say so one minor ahead.
Moving to a newer Postgres major is the one upgrade docker compose pull
cannot do, because Postgres does not read a data directory written by an
older major. Dump with the old container, switch the image tag, restore:
docker compose exec postgres pg_dump -U stoop -Fc stoop > stoop.dumpdocker compose downdocker volume ls | grep postgres-data # then remove that one volume, and only that onedocker volume rm <name>_postgres-data# edit docker-compose.yml: postgres:16-alpine → postgres:17-alpinedocker compose up -d postgresdocker compose exec -T postgres pg_restore -U stoop -d stoop < stoop.dumpdocker compose up -dKeep stoop.dump until the restored instance has been used for a while;
the stoop-data volume with the uploads is untouched by all of this.
LiveKit is pinned in the compose file to the exact version a Stoop release was tested against, and Stoop needs nothing newer than that pin. The pin moves only in a minor release and the notes say when.
Using your own Postgres
Section titled “Using your own Postgres”In .env, take bundled-postgres out of COMPOSE_PROFILES and name your
server:
COMPOSE_PROFILES=STOOP_DATABASE_URL=postgres://stoop:secret@192.168.1.20:5432/stoop?sslmode=requireThen docker compose up -d. The bundled Postgres no longer starts, and
POSTGRES_PASSWORD is unused.
- Create the database and its role first. Stoop creates tables, not databases.
- The bundled URL says
sslmode=disablebecause it never leaves the compose network. A remote server usually wantsrequire. - A Postgres on the same machine is
host.docker.internalon Docker Desktop and the machine’s LAN address on Linux;localhostis the container itself. - Backups of that database are then yours: the
pg_dumplines there run against your server instead ofdocker compose exec postgres. Thestoop-datavolume still holds the uploads.
Where the data lives
Section titled “Where the data lives”To keep uploads and the database on a disk you already back up, set the
paths in .env and run Stoop as the user that owns the uploads path:
STOOP_DATA_PATH=/mnt/tank/stoop/dataPOSTGRES_DATA_PATH=/mnt/tank/stoop/postgresPUID=1000 # id -uPGID=1000 # id -gmkdir -p /mnt/tank/stoop/data /mnt/tank/stoop/postgreschown 1000:1000 /mnt/tank/stoop/datadocker compose up -d- A path starts with
/or./; anything else is read as a volume name. - Postgres owns its path itself. Give it a directory nothing else uses.
PUIDandPGIDgo withSTOOP_DATA_PATH. On the defaultstoop-datavolume, leave them unset.- If the owner is wrong, uploads fail and Server admin → Diagnostics → File storage says the directory is not writable.
- Backups and the restore runbook then mean those two paths,
in place of the
stoop-dataandpostgres-datavolumes.
To move an existing install, stop the stack and copy each volume out before setting the path:
docker compose stopdocker run --rm --volumes-from "$(docker compose ps -aq stoop)" -v /mnt/tank/stoop/data:/to busybox cp -a /data/. /toThe database copies the same way, from the postgres container’s
/var/lib/postgresql/data.
Tuning the bundled Postgres
Section titled “Tuning the bundled Postgres”Put postgres -c flags in POSTGRES_ARGS in .env, then
docker compose up -d:
POSTGRES_ARGS=-c shared_buffers=256MB -c max_connections=50Postgres’s defaults are right for a chat database of this size, so most
installs leave this unset. A misspelt setting stops the container, and
docker compose logs postgres names it.
Bare binary (no Docker)
Section titled “Bare binary (no Docker)”Release binaries are static with the web UI embedded — no runtime
dependencies beyond Postgres (and a LiveKit server if you want voice).
Each release carries
stoop_linux_amd64.tar.gz, linux_arm64 and darwin_arm64
archives and a checksums.txt to verify them against:
STOOP_DATABASE_URL=postgres://stoop:secret@localhost:5432/stoop ./stoop./stoop --version prints the release and commit; the same appears in
the first log line and, for admins, under Server admin → Server.
For voice, point it at your LiveKit with STOOP_LIVEKIT_URL and start
LiveKit against the key file Stoop writes:
STOOP_LIVEKIT_URL=http://127.0.0.1:7880 ./stoop # mints on first bootlivekit-server --config livekit.yaml \ --key-file ./data/livekit/keys.yaml # same pair, no copyingLiveKit refuses a key file others can read, so leave it 0600 as written.
Start Stoop first: LiveKit exits if the file isn’t there yet.