Operations
Updates, backups, monitoring and troubleshooting — everything you need after the first start.
Updating
An update is a new image on the same volume. Data, tokens and links are kept.
docker compose pull
docker compose up -dOr without compose:
docker pull flytachi/s5w:latest
docker stop -t 45 s5w && docker rm s5w
docker run -d --name s5w … flytachi/s5w:latest # the same command, the same volume- Make a backup before updating — see below.
- Pin the version in production (
flytachi/s5w:<version>, notlatest): that way an update happens when you decide, not on an accidentalpull. - Read the release notes — they describe what changes for those who update. For moving from 1.0.x there is a separate page.
Schema migrations
Tables are created on the first start, when the database is empty. An update does not change
the schema by itself: call db migrate creates missing tables but does not alter existing
ones. If a release needs a schema change, its notes will include the exact command.
Backup
The whole state of the service is in the /var/lib/s5w volume: the database, the files and
the signing key. A copy of the volume is a complete copy of the service.
- Stop the container
bash docker stop -t 45 s5wA copy of a running volume may be inconsistent: the database and the files on disk change independently. Stopping takes a few seconds.
- Copy the volume into an archive
bash docker run --rm \ -v s5w_data:/data:ro \ -v "$PWD":/backup \ --entrypoint tar flytachi/s5w:latest \ czf /backup/s5w-$(date +%F).tar.gz -C /data . - Start the container
bash docker start s5w
If the volume is mounted as a host directory (/srv/s5w), any directory copying tool works
instead of the second step — tar, rsync, a filesystem snapshot — while the container is
stopped.
The archive is everything
The archive holds every file of every bucket and the WINTER_KEY signing key. Keep it as
safely as the data itself, and not next to the server.
Database copy without stopping
As an extra safeguard, the metadata can be dumped on the fly:
docker exec s5w pg_dump -U s5w -h /run/postgresql -Fc s5w > s5w-db-$(date +%F).dumpThis is a copy of the database only. A full restore is done from a copy of the volume.
Restore
- Create a volume and unpack the archive into it
bash docker volume create s5w_data docker run --rm \ -v s5w_data:/data \ -v "$PWD":/backup:ro \ --entrypoint tar flytachi/s5w:latest \ xzpf /backup/s5w-2026-11-08.tar.gz -C /dataThe
pflag keeps owners and permissions: the database directory requires them. - Start the container on this volume
With the same command as usual. The service comes up with the same buckets, files, tokens and temporary links: the signing key is restored together with the volume.
Moving to another server is the same: an archive from one server, a restore on the other.
Healthcheck
There is no dedicated health endpoint. The sign that the application accepts requests is that
GET /v1/check without a token answers 401.
services:
s5w:
# …
healthcheck:
test: ["CMD-SHELL", "test \"$$(curl -s -o /dev/null -w %{http_code} http://127.0.0.1:9090/v1/check)\" = 401"]
interval: 30s
timeout: 5s
start_period: 30s
retries: 3Do not use curl -f
curl -f treats 401 as an error, and the healthcheck will always be red. Compare the
response code instead.
Database readiness separately:
docker exec s5w pg_isready -h /run/postgresql -U s5wMonitoring
| What to watch | How | Why |
|---|---|---|
| The container is alive | the healthcheck above | the API and delivery respond |
| Free space on the volume | host disk metric | when it fills up, uploads get 507 and the database stops |
| Application parts | call app status |
crashes and restarts are visible |
| Errors in the log | docker logs, level error |
processing failures, disk problems |
| Bucket quotas | the panel, “Overview” | a bucket at its limit starts rejecting uploads (413) |
docker exec s5w su-exec winter php call app statusThe command shows every part — HTTP, scheduler, panel — with its state, PID, uptime and restart count. A growing restart count is a reason to look at the log.
Logs
docker logs -f s5w # everything: application, PostgreSQL, supervisor
docker logs --since 1h s5w # the last hourEvery part writes to the container output, which Docker and any log collector pick up. The
level is set by LOG_LEVEL — see Configuration.
Maintenance commands
docker exec -it s5w sh # shell in the container
docker exec s5w su-exec winter php call app status # state of the parts
docker exec -it s5w psql -U s5w -h /run/postgresql s5w # psql into the bundled database
docker exec s5w su-exec winter php call db migrate # create missing tablesApplication commands run as the winter user — hence su-exec winter.
Scheduled maintenance (retention, cleanup, space recalculation) runs inside the container by itself — no separate cron is needed. The list of tasks is in the architecture.
Common problems
| Symptom | Cause | What to do |
|---|---|---|
| Cannot sign in to the panel, login fails with the right password | ADMIN_LOGIN / ADMIN_PASSWORD are not set |
Set both variables and recreate the container |
Login answers 429 |
Five failed attempts within 15 minutes | Wait 5 minutes (Retry-After) |
/admin/… answers 404 from outside |
The admin API is in local mode |
That is by design; for scripts — ADMIN_API=public |
| Links in the panel point to the panel domain | PUBLIC_BASE_URL is not set |
Set the address of the API domain |
Upload through the proxy — 413 with an HTML page |
The proxy’s request body limit | Raise the limit to 32 MiB |
Upload — 413 with JSON |
The bucket quota, or a file over 32 MiB in one request | Raise the quota or upload in chunks |
Chunked upload — 507 |
Less than 512 MiB of reserve on disk | Free up space |
| After a stop the database takes long to start | Docker killed it too early | --stop-timeout 45 / stop_grace_period: 45s |
| Temporary links suddenly stopped working | WINTER_KEY changed, or a new volume |
Bring back the key or the volume; otherwise issue the links again |
| All data is gone after an update | The volume was not mounted | Restore from a backup; mount the volume |