Configuration
S5W is configured with environment variables only — there are no configuration files. No variable is required to run the storage; signing in to the panel needs two — a login and a password.
When changes take effect
Variables are read at start-up. For a change to take effect the container has to be
recreated: docker compose up -d (compose recreates the changed service by itself) or
docker rm -f s5w and a new docker run with the same volume. A plain docker restart is not
enough — it does not change the container’s environment.
Recommended start
docker compose
services:
s5w:
image: flytachi/s5w:latest
ports:
- "9090:9090" # API and delivery
- "9091:9091" # admin panel
environment:
ADMIN_LOGIN: admin
ADMIN_PASSWORD: ${S5W_ADMIN_PASSWORD} # from .env next to the compose file
PUBLIC_BASE_URL: https://files.example.com
TIME_ZONE: Asia/Tashkent
LOG_LEVEL: warning
volumes:
- s5w_data:/var/lib/s5w
# The application stops first (up to 35 s), then PostgreSQL. Docker's default
# 10 s is not enough: after a SIGKILL the database recovers on the next start.
stop_grace_period: 45s
restart: unless-stopped
volumes:
s5w_data:docker run
docker run -d --name s5w -p 9090:9090 -p 9091:9091 \
-e ADMIN_LOGIN=admin -e ADMIN_PASSWORD="$S5W_ADMIN_PASSWORD" \
-e PUBLIC_BASE_URL=https://files.example.com \
-e TIME_ZONE=Asia/Tashkent \
-e LOG_LEVEL=warning \
-v s5w_data:/var/lib/s5w \
--stop-timeout 45 \
--restart unless-stopped \
flytachi/s5w:latestAll variables
| Variable | Default | In short |
|---|---|---|
ADMIN_LOGIN |
— | Panel login. Without it, signing in is closed. |
ADMIN_PASSWORD |
— | Panel password. Without it, signing in is closed. |
ADMIN_UI |
true |
Whether to run the panel on 9091. |
ADMIN_API |
(from ADMIN_UI) |
Where the admin API is accepted from: local or public. |
TRUSTED_PROXIES |
private |
Which proxies to believe in X-Forwarded-For. |
PUBLIC_BASE_URL |
(request address) | Base address of file links. |
TIME_ZONE |
UTC |
Time zone of panel statistics when the browser did not report its own. |
CACHE_DEFAULT_MAX_AGE |
86400 |
Default max-age for the shared cache. |
CACHE_PRIVATE_MAX_AGE |
0 |
Default max-age for the private cache. |
LOG_LEVEL |
info |
Log verbosity. |
LOG_OUTPUT |
auto |
Where logs go. |
SERVER_MEMORY_LIMIT |
512M |
Memory ceiling of one process. |
SERVER_REQUEST_TIMEOUT |
30 |
Request processing timeout, seconds. |
WINTER_KEY |
(generated) | Signing key of sessions and temporary links. |
The panel variables (ADMIN_*, TRUSTED_PROXIES) are covered in detail on the
Admin panel page, the resource variables (SERVER_*) on
Resources and performance. The rest are below.
No database settings
And none are needed: the database is bundled and the only one, and it listens only inside the container. No connection string, host or password has to be set — and an external database cannot be connected.
PUBLIC_BASE_URL
What it does. Sets the start of every address the service hands out itself: publicUrl
and privateUrl of files, url of temporary links, addresses in the panel. Written with the
scheme and without a trailing /: https://files.example.com.
If not set. The address is built from the incoming request: scheme, host and port. As long as clients reach the service directly, this works. Behind a proxy the result depends on which headers the proxy passes, and in the panel addresses are built from the panel’s domain — that is, they point to the wrong place. In that case the panel shows a warning.
When to set it. Always, if the service sits behind a proxy or the API has its own domain. Give the address where files are reachable from outside — the API domain, not the panel’s.
Links already handed out
Addresses are built at response time and stored nowhere. If you change PUBLIC_BASE_URL, new
responses get the new address, while links already handed to clients keep the old domain —
and work only as long as the old domain still points to the service.
TIME_ZONE
What it does. The time zone in which the panel splits traffic statistics into days when the browser did not report its own. Usually the browser does, and the variable is a fallback.
What it does not change. The maintenance schedule (always in UTC), the time in logs and the
time in API responses — there it carries an explicit offset (+00:00).
Value. A name from the time zone database: Europe/Moscow, Asia/Tashkent. An unknown
name is silently replaced with UTC.
CACHE_DEFAULT_MAX_AGE and CACHE_PRIVATE_MAX_AGE
What they do. The max-age values in the Cache-Control header used when neither the
folder nor the bucket has its own max-age. CACHE_DEFAULT_MAX_AGE — for the shared cache
(public: browser and CDN), a day by default. CACHE_PRIVATE_MAX_AGE — for the private one
(private: browser only), 0 by default: the browser asks again every time, and ETag makes
such a request cheap.
When to change them. To change the default behaviour for all buckets at once. For a single bucket or folder it is easier to set the policy in the panel — it takes precedence over these variables. How exactly the header is built is on the Caching page.
LOG_LEVEL and LOG_OUTPUT
LOG_LEVEL — debug · info · warning · error. The default is info: start and stop of
the parts, bucket creation, errors. For a production server warning is usually enough. An
empty value turns the application logs off.
LOG_OUTPUT — auto · stdout · stderr · file. auto means stdout, which is exactly
what docker logs and any container log collector pick up. file writes to files inside the
container; under Docker this is usually not needed.
PostgreSQL and s6 supervisor logs go to the same container output regardless of these variables.
WINTER_KEY
What it does. The secret key that signs panel sessions and /t/… temporary links.
If not set. On the first start the key is generated and saved in the volume, in
/var/lib/s5w/.runtime_secrets, and read from there on later starts. Same volume, same key. The
first start’s log shows this as WINTER_KEY auto-generated.
If set. The value from the environment takes precedence over the one saved in the volume. Set it if you want to keep the key in a secrets store rather than in the volume, or if you bring the service up on a new volume and want old temporary links to keep working.
If changed. Every panel session and every temporary link issued in every bucket stops working. Files, access tokens and public links are not affected.
The /var/lib/s5w volume
/var/lib/s5w/
postgresql/ PostgreSQL cluster — metadata
buckets/ files, one directory per bucket
staging/ unfinished chunked uploads
.runtime_secrets the generated WINTER_KEYMount one volume as a whole. It has no parts that can be moved out separately: buckets/
and staging/ must be on the same filesystem (a chunked upload finishes with a rename, which is
atomic only within one filesystem), and the database without the files or the files without
the database are useless.
Without a volume the container is disposable. The data ends up in the container layer and disappears when the container is recreated — and it is recreated on every image update and every change of variables.
A host directory instead of a named volume is fine: -v /srv/s5w:/var/lib/s5w. The
directory must be on a local filesystem: PostgreSQL on network filesystems such as NFS is
unreliable.
The PostgreSQL version is tied to the volume. Currently it is 18. If the image ever moves
to a new major version, the cluster will need pg_upgrade — this will be described separately
in the release notes.
docker compose down -v
The -v flag deletes volumes, and with them the database and every file. To stop, use
docker compose down without it, or docker compose stop.
Ports
The ports inside the container are fixed: 9090 — API and delivery, 9091 — the panel. For a
different port outside, change only the publishing: -p 8080:9090. Behind a proxy on a shared
docker network the ports need not be published at all — see Behind a reverse proxy.