Plan and test your backups
Silo is in active development before 1.0. These guides are updated frequently.
A Silo backup is the database, the encryption key, and the files the database points to. Test a restore on another host before you rely on it.
What to preserve
Section titled “What to preserve”| Data | Why it matters |
|---|---|
| PostgreSQL | Catalog, accounts, profiles, settings, and watch state |
SECRET_KEY | Silo can’t start on the database without it, and it can’t be recovered |
.env, Compose files, and overrides | Recreates the same paths, ports, and services |
| Exact image version | Restores with the software that matches the backup |
| Local artwork and S3 buckets | Uploaded images, downloaded subtitles, avatars, and cached artwork |
| Plugin files | Installed plugins |
| Original media | Silo’s database does not contain your media files |
Back up a Compose install
Section titled “Back up a Compose install”Run these from the directory that holds your Compose file.
-
Record the image you are running:
Terminal window docker compose images silo -
Dump the database, then check that the dump can be read:
Terminal window BACKUP="silo-$(date +%F).dump"docker compose exec -T -u silo silo pg_dump -h /run/postgresql -Fc silo > "$BACKUP"docker compose exec -T -u silo silo pg_restore --list < "$BACKUP" > /dev/null && echo "dump OK"Silo can keep running during the dump. With separate containers, dump from the
postgresservice instead, and replacesilowith yourPOSTGRES_USERandPOSTGRES_DBvalues if you changed them:Terminal window docker compose exec -T postgres pg_dump -U silo -Fc silo > "$BACKUP"docker compose exec -T postgres pg_restore --list < "$BACKUP" > /dev/null && echo "dump OK"If
DATABASE_URLpoints Silo at a PostgreSQL server of your own, dump that server with its own tools. -
Copy
.envand your Compose files, including any overrides, to a restricted location..envcontainsSECRET_KEY. -
Copy these directories from
SILO_DATA_ROOT(default/opt/silo):Directory Back up? config/silo, orartwork,plugins, andcompatwith separate containersYes. Uploaded posters and branding cannot be downloaded again. catalog-seedsYes, if you put files there config/postgres, orpostgresNo, use the dump instead config/redis,config/meilisearch,redis,meilisearch,transcode,download-artifactsNo. These hold temporary, cache, or rebuildable data. Silo prepares downloads again if devices are still waiting for them. -
If you use S3 storage, back up the public and private buckets with your provider’s tools, at about the same time as the dump.
Do not copy the PostgreSQL directory while the database is running: the copy may not start. If you need a file-level copy, run docker compose stop silo first, or docker compose stop postgres with separate containers.
Per-user data on SQLite
Section titled “Per-user data on SQLite”Silo keeps per-user data in PostgreSQL, where the dump covers it, unless the userdb.backend setting is sqlite. The admin pages have no control for this setting. To check it:
docker compose exec -T -u silo silo psql -h /run/postgresql -d silo -c "SELECT value FROM server_settings WHERE key = 'userdb.backend'"With separate containers, run docker compose exec -T postgres psql -U silo -d silo -c with the same query.
If it shows sqlite, Silo also writes per-user data to /var/lib/silo/userdb inside the container. In the single container that’s config/silo/userdb, which you already back up. With separate containers, the Compose file does not keep that directory. Mount it from the host and back it up with the dump.
Test a restore
Section titled “Test a restore”Restore to a separate host when you can, never over the live server.
- Copy
.envwith the originalSECRET_KEYand your Compose files into a new directory, and copy the data directories you backed up. - If the live server runs on the same host, edit the copied
.envbefore running any Compose command. SetSILO_DATA_ROOTto the new data directory, and setPORT,JF_PORT, andABS_PORT, plusPOSTGRES_PORT,REDIS_PORT, andMEILISEARCH_PORTwith separate containers, to ports the live server doesn’t use. Also setCOMPOSE_PROJECT_NAMEto a new name, such assilo-restore-test, so Compose can’t mistake the copy for the live server. Run every command from the new directory. - Pin the image you recorded with the backup:
SILO_OMNIBUS_IMAGE, orSILO_IMAGEwith separate containers. - Block the test copy’s outgoing traffic to your notification services and webhook targets, and make sure it can’t write to your production S3 buckets. The restored database holds the live server’s credentials for all of these. Until the restore finishes, also keep other devices from reaching the copy’s ports: it starts on an empty database with first-run setup open.
- Start the copy with
docker compose up -dand wait untildocker compose psshows ithealthy. It creates an empty database. Don’t open it in a browser or finish setup. - Load the dump, as in Restore a dump into the container. Silo applies any pending database migrations when it starts again.
With separate containers, replace steps 5 and 6: start only the database with docker compose up -d postgres, load the dump into the empty database with pg_restore, then start Silo with docker compose up -d.
Then sign in as an admin and as a normal account. Check profiles, libraries, artwork, watch progress, and one playback, and restart the copy once to make sure the state survives.
Restore a dump into the container
Section titled “Restore a dump into the container”These commands replace the container’s database with the dump in silo.dump. They stop Silo inside the container first, so nothing writes to the database while it loads, and leave PostgreSQL running:
docker compose exec silo /command/s6-svc -d /run/service/svc-silodocker compose exec silo /command/s6-svwait -D /run/service/svc-silodocker compose exec -u silo silo dropdb -h /run/postgresql silo &&docker compose exec -u silo silo createdb -h /run/postgresql silo &&docker compose exec -T -u silo silo pg_restore -h /run/postgresql -d silo --no-owner --role=silo --exit-on-error < silo.dump &&docker compose restart siloThe restart starts Silo again on the restored data. dropdb deletes the container’s database before the dump loads, so if pg_restore stops with an error, that database is incomplete and Silo stays stopped. The dump file is unchanged: fix the cause and run the commands again.
Before an update
Section titled “Before an update”A database migration can’t be undone by switching back to the old image. Take a fresh backup before every update and follow the update guide.