Tusile does not ship a one-click backup UI. Operators use standard tools: PostgreSQL dumps for the database, a copy of the data volume, and a copy of uploaded files (Docker volume or S3 bucket). Match database and files to the same point in time when possible so attachment paths stay valid.
What to back up
- Database: channels, messages, roles, invites, and metadata live in Postgres. A logical dump (
pg_dump) is enough for backup and migration. - Files (local storage): with the default
STORAGE_BACKEND=local, uploads are in the Docker volume mounted at/app/uploadsinside the community-server container (see Configuration forSTORAGE_LOCAL_PATH). - Files (S3): if you use
STORAGE_BACKEND=s3, uploads are in your bucket. Use your provider’s replication, versioning, or export tools; thecommunity-uploadsvolume is not the source of truth. - Data volume: the
community-datavolume, mounted at/app/data(DATA_DIR). It holds the install ID, an unused Offgrid owner claim token and, on an Offgrid server,community_key: the signing key the server’s identity is derived from. Lose that and every session is invalidated, the server ID changes, every voice room is renamed and custom emoji break, even with the database restored. It is a few small files; back it up every time. - Config: your
.env,Caddyfileandlivekit.prod.yaml..envholds the server token and LiveKit keys, so store it as carefully as the dumps.
Compose project and volume names
The project name comes from COMPOSE_PROJECT_NAME in .env, which the setup script writes for new installs as community-<hash> (community-offgrid-<hash> for Offgrid). Named volumes are therefore prefixed with it: community-<hash>_community-pgdata, community-<hash>_community-uploads, community-<hash>_community-data. Run docker volume ls to see the exact names.
Deployments installed before that change have no COMPOSE_PROJECT_NAME line, and compose falls back to community-${SERVER_TOKEN}, so their volumes look like community-<token>_community-pgdata. That fallback is kept on purpose: the project name decides which volumes the stack attaches to, so adding the line to an existing .env would orphan your database and uploads. Leave it alone.
Either way, run all docker compose commands from the same directory and .env you use in production so the project name matches.
Default Postgres credentials in the sample compose are user tusile_community, database tusile_community. If you changed the password or user in compose, use those values in the commands below.
Backup (export)
Database
From the directory that contains your docker-compose.yml, with the stack running:
Custom format (recommended for restore with pg_restore):
docker compose exec -T postgres pg_dump -U tusile_community -d tusile_community -Fc > tusile_community.dump
Plain SQL (restore with psql):
docker compose exec -T postgres pg_dump -U tusile_community -d tusile_community --clean --if-exists > tusile_community.sql
Store dump files securely; they contain community data. On Windows PowerShell, > file.dump works with -T on docker compose exec; alternatively run the same commands from Git Bash or WSL.
Data and local uploads volumes
Replace PROJECT with your project name from docker volume ls:
docker run --rm -v PROJECT_community-data:/data -v "$(pwd):/backup" alpine tar czf /backup/data.tgz -C /data .
docker run --rm -v PROJECT_community-uploads:/data -v "$(pwd):/backup" alpine tar czf /backup/uploads.tgz -C /data .
On Windows without a Unix shell, use docker volume inspect to find the mountpoint and archive that folder with your preferred tool, or run the one-liner from WSL/Git Bash.
Restore on a fresh install
- Deploy a new host or directory with the same configuration as before. Copying the old
.envis simplest. On Cloud the server re-registers as the same community fromSERVER_TOKENandCOMMUNITY_PUBLIC_URL. On Offgrid keepOFFGRID_MODE=true; the identity comes from the data volume restored below. - Bring up Postgres only, or stop the
community-serverservice so nothing writes to the database during restore:docker compose up -d postgres - Custom-format dump: copy the file into the container (or use stdin), then restore:
docker compose cp tusile_community.dump postgres:/tmp/tusile_community.dump docker compose exec postgres pg_restore --clean --if-exists -U tusile_community -d tusile_community /tmp/tusile_community.dump - Plain SQL:
docker compose exec -T postgres psql -U tusile_community -d tusile_community < tusile_community.sql - Restore the data volume and uploads into the new
community-dataandcommunity-uploadsvolumes (empty them first if you recreated the stack). Example using a temporary container:docker run --rm -v PROJECT_community-data:/data -v "$(pwd):/backup" alpine sh -c "cd /data && tar xzf /backup/data.tgz" docker run --rm -v PROJECT_community-uploads:/data -v "$(pwd):/backup" alpine sh -c "cd /data && tar xzf /backup/uploads.tgz" - Start the full stack:
docker compose up -d. The community server runs migrations on startup; with a restored DB, migrations should be no-ops or incremental fixes.
Moving between versions
Community server (application)
Pull a newer image (for example karolrzotki/tusile-community-server:latest), then docker compose up -d. Schema migrations run automatically when the process starts. Always take a fresh database dump (and file backup) before upgrading.
PostgreSQL major version
Upgrading the Postgres container major version (for example 16 → 17) is not a simple image tag change. Prefer: dump with the old major version, start a new empty data directory with the new major version, restore the dump, then point compose at the new volume. Test in a copy of your environment first.