Vaze
Getting Started

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

VariableRequiredDescription
BASE_URLYesThe public base URL of your Vaze instance, e.g. https://files.example.com. Used by authentication and for building absolute URLs.
AUTH_SECRETYesA long random string used to sign session tokens. Keep it secret and stable — rotating it invalidates existing sessions.
VAZE_PORTNo (3000)Host port the container is published on. Compose-only — it maps to port 3000 inside the container.
VAZE_BIND_ADDRNo (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_VERSIONNo (latest)Image tag to run. Pin it (e.g. 2.2.0) if you want upgrades to be a deliberate step.
TZNo (UTC)Timezone used inside the container.
PORTNo (3000)The port the server listens on inside the container.

Limits

VariableDefaultDescription
MAX_UPLOAD_SIZE5gbLargest single file accepted by an upload. Accepts b/kb/mb/gb/tb suffixes, e.g. 500mb.
MAX_FILES_PER_REQUEST100Cap on the number of files in one multipart request.
API_REQUEST_RETENTION_DAYS90How long API request-log rows are kept before being pruned.
ACTIVITY_RETENTION_DAYS90How long activity history is kept before being pruned.
MAX_DELETE_BATCH500Cap on the number of file ids accepted by one batch delete.
MAX_MOVE_BATCH500Cap on the number of file ids accepted by one batch move.
MAX_DOWNLOAD_BATCH1000Cap on the number of file ids accepted by one multi-file zip download.

Uploads stream to disk, so MAX_UPLOAD_SIZE bounds what a single request may store — not how much memory the server uses.

Hosting traffic for the dashboard is stored as one small row per day rather than per request, so it has no setting: counts per file are kept for 30 days and instance totals for a year. See Stats.

MAX_UPLOAD_SIZE, API_REQUEST_RETENTION_DAYS and ACTIVITY_RETENTION_DAYS can be changed at runtime under Settings in the dashboard or the mobile app, or with PUT /api/settings. Each variable only sets the starting value: it is copied in the first time Vaze starts (or first starts after an upgrade that adds the setting), and changing it later has no effect.

File access

VariableDefaultDescription
DEFAULT_FILE_VISIBILITYpublicVisibility given to an upload that doesn't ask for one. Set to private to make the instance private-first.
DEFAULT_PRESIGN_TTL_SECONDS3600Lifetime of a signed URL when the caller doesn't specify one.
MAX_PRESIGN_TTL_SECONDS604800Longest lifetime a signed URL may be minted with. Seven days, matching S3's cap.
HOSTING_CACHE_MAX_AGE0max-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.

All four can be changed at runtime under Settings in the dashboard or the mobile app, or with PUT /api/settings. Each variable only sets the starting value: it is copied in the first time Vaze starts (or first starts after an upgrade that adds the setting), and changing it later has no effect.

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 32

AUTH_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 /var/lib/vaze:

  • db/: the SQLite database with file metadata, users, and API keys.
  • uploads/: all uploaded files and folders, stored as plain files on disk.
  • tmp/: in-flight uploads, staged here and moved into uploads/ once fully received. Cleared on startup.
  • thumbnails/: cached image previews for the dashboard, rebuilt on demand.

The container runs as an unprivileged user, so a bind mount at /var/lib/vaze must be writable by uid 1000.

compose.prod.yaml mounts a named Docker volume there:

volumes:
  - vaze_data:/var/lib/vaze

Named 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:/var/lib/vaze

To 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.

Vaze refuses to start unless /var/lib/vaze is on a mounted volume, since without one every file and account is lost when the container is replaced. Set ALLOW_EPHEMERAL_DATA=true to start without one anyway, for example on a throwaway test instance.

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 ps

Reverse 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:

.env
BASE_URL=https://files.example.com
VAZE_BIND_ADDR=127.0.0.1

Remember to raise your proxy's request body size limit if you plan to upload large files (e.g. client_max_body_size in nginx).

On this page