Configuration
Environment variables and persistent storage
Vaze is configured entirely through environment variables and a single mounted volume.
If you used the quick install, all of this
lives in the .env next to your compose.prod.yaml (./vaze/.env by default).
Edit it and apply with docker compose -f compose.prod.yaml up -d.
Environment variables
| Variable | Required | Description |
|---|---|---|
BASE_URL | Yes | The public base URL of your Vaze instance, e.g. https://files.example.com. Used by authentication and for building absolute URLs. |
AUTH_SECRET | Yes | A long random string used to sign session tokens. Keep it secret and stable — rotating it invalidates existing sessions. |
VAZE_PORT | No (3000) | Host port the container is published on. Compose-only — it maps to port 3000 inside the container. |
VAZE_BIND_ADDR | No (0.0.0.0) | Host address the port is bound to. Set 127.0.0.1 when a reverse proxy fronts Vaze, so the container isn't reachable directly. |
VAZE_VERSION | No (latest) | Image tag to run. Pin it (e.g. 2.2.0) if you want upgrades to be a deliberate step. |
TZ | No (UTC) | Timezone used inside the container. |
PORT | No (3000) | The port the server listens on inside the container. |
Limits
| Variable | Default | Description |
|---|---|---|
MAX_UPLOAD_SIZE | 5gb | Largest single file accepted by an upload. Accepts b/kb/mb/gb/tb suffixes, e.g. 500mb. |
MAX_FILES_PER_REQUEST | 100 | Cap on the number of files in one multipart request. |
API_REQUEST_RETENTION_DAYS | 90 | How long API request-log rows are kept before being pruned. |
MAX_DELETE_BATCH | 500 | Cap on the number of file ids accepted by one batch delete. |
Uploads stream to disk, so MAX_UPLOAD_SIZE bounds what a single request may
store — not how much memory the server uses.
File access
| Variable | Default | Description |
|---|---|---|
DEFAULT_FILE_VISIBILITY | public | Visibility given to an upload that doesn't ask for one. Set to private to make the instance private-first. |
DEFAULT_PRESIGN_TTL_SECONDS | 3600 | Lifetime of a signed URL when the caller doesn't specify one. |
MAX_PRESIGN_TTL_SECONDS | 604800 | Longest lifetime a signed URL may be minted with. Seven days, matching S3's cap. |
HOSTING_CACHE_MAX_AGE | 0 | max-age for public hosted responses. Zero revalidates every time, which is cheap because a match answers with a bodiless 304. Raise it when keys are effectively immutable. |
Public files are served to anyone with the link; private files require a signed URL, an API key, or a dashboard session. See signing a URL.
Generate a strong secret with:
openssl rand -base64 32AUTH_SECRET is the one value worth backing up. The installer generates it
once and never overwrites it, but if you rebuild the .env by hand with a new
secret, every session is invalidated and users have to log in again — and
every outstanding signed URL stops working, since signing keys are derived
from it.
Persistent storage
Inside the container, Vaze keeps everything under /app/data:
uploads/— all uploaded files and folders, stored as plain files on disk.tmp/— in-flight uploads, staged here and moved intouploads/once fully received. Cleared on startup.- the SQLite database with file metadata, users, and API keys.
The container runs as an unprivileged user, so a bind mount at /app/data
must be writable by uid 1000.
compose.prod.yaml mounts a named Docker volume there:
volumes:
- vaze_data:/app/dataNamed volumes are the safer default — SQLite's locking is unreliable on bind mounts backed by network filesystems. If you want the data at a specific path on the host, swap it for a bind mount:
volumes:
- /srv/vaze:/app/dataTo back up the named volume:
docker run --rm -v vaze_vaze_data:/data -v "$PWD:/backup" alpine \
tar czf /backup/vaze-backup.tar.gz -C /data .Upgrading never touches this volume. The installer and
docker compose -f compose.prod.yaml up -d both replace only the container.
Without a volume mounted at /app/data, all files and accounts are lost when
the container is removed.
Health checks
The image exposes GET /api/health, and compose.prod.yaml uses it as the
container healthcheck. Check the current state with:
docker compose -f compose.prod.yaml psReverse proxy
If you put Vaze behind a reverse proxy (nginx, Caddy, Traefik, …), set
BASE_URL to the public URL served by the proxy — for example
https://files.example.com — so login and generated file URLs use the right
origin.
Also set VAZE_BIND_ADDR=127.0.0.1 so the container is only reachable through
the proxy instead of being exposed on every interface:
BASE_URL=https://files.example.com
VAZE_BIND_ADDR=127.0.0.1Remember to raise your proxy's request body size limit if you plan to upload
large files (e.g. client_max_body_size in nginx).
Vaze