Back to docs

Environment Variables

Storage UI reads all server-side settings from environment variables. Storage credentials stay on the server and are never shipped to the browser.

For local development, copy the example file and edit it:

cp .env.example .env.local

On a hosting platform (Vercel, Docker, etc.), set the same variables in that platform's environment settings.

Application

VariableDefaultDescription
NEXT_PUBLIC_APP_URLlocalhost:3000Public URL of the app.
NEXT_PUBLIC_BASE_PATH(root)Serve from a subpath, e.g. /drive. Also redirects / to that path.
NEXT_PUBLIC_ASSET_PREFIX(none)Set only when static assets are served from a separate origin.

Authentication

Set a username and password to turn on the built-in login screen. Leave either blank to keep the app open.

AUTH_USERNAME=admin
AUTH_PASSWORD=change-me
AUTH_SECRET=a-long-random-string
VariableRequiredDescription
AUTH_USERNAMEFor loginLogin username.
AUTH_PASSWORDFor loginLogin password.
AUTH_SECRETRecommendedSigns the session cookie. Without it, the password doubles as the signing key, so changing the password logs everyone out.

Sessions last 7 days. The login form can also carry a bot challenge, see Turnstile below.

Storage connections

Each connection is a numbered group of variables, STORAGE_1_* through STORAGE_50_*. Users can still add more connections from the UI at runtime. Which variables a slot uses depends on its provider. S3 and the services compatible with it share one set, WebDAV takes another.

S3 and compatible services

A connection loads once its BUCKET, ACCESS_KEY_ID, and SECRET_ACCESS_KEY are set (plus REGION or ENDPOINT for some providers, noted below).

VariableRequiredDescription
STORAGE_n_BUCKETYesBucket name.
STORAGE_n_ACCESS_KEY_IDYesAccess key ID (Tencent SecretId, B2 key ID).
STORAGE_n_SECRET_ACCESS_KEYYesSecret access key (Tencent SecretKey, B2 application key).
STORAGE_n_PROVIDERNo (s3)Provider, see list below.
STORAGE_n_NAMENoDisplay name in the sidebar. Defaults to the bucket name.
STORAGE_n_REGIONProviderRequired for alibaba, tencent, backblaze-b2. Ignored by r2. Defaults to auto for S3.
STORAGE_n_ENDPOINTProviderRequired for minio. Optional override for other S3-compatible providers.
STORAGE_n_ACCOUNT_IDR2 onlyCloudflare account ID (R2 derives its endpoint from this).
STORAGE_n_FORCE_PATH_STYLENoPath-style addressing. Defaults to true for minio, false otherwise.
STORAGE_n_PUBLIC_BASE_URLNoPublic or CDN base URL for file links.
STORAGE_n_READ_ONLYNoSet to true to disable all edits for this bucket.

Supported providers: s3, r2, alibaba, tencent, backblaze-b2, minio, s3-compatible.

Always set a real region.

STORAGE_1_PROVIDER=s3
STORAGE_1_NAME=Production
STORAGE_1_BUCKET=my-bucket
STORAGE_1_REGION=us-east-1
STORAGE_1_ACCESS_KEY_ID=...
STORAGE_1_SECRET_ACCESS_KEY=...

WebDAV

Works with Nextcloud, ownCloud, Apache mod_dav, and most NAS boxes. There is no bucket, and ENDPOINT is the only required variable.

STORAGE_8_PROVIDER=webdav
STORAGE_8_NAME=Nextcloud
STORAGE_8_ENDPOINT=https://cloud.example.com/remote.php/dav/files/alice
STORAGE_8_USERNAME=alice
STORAGE_8_PASSWORD=...
STORAGE_8_ROOT=/Photos
VariableRequiredDescription
STORAGE_n_PROVIDERYesMust be webdav.
STORAGE_n_ENDPOINTYesThe WebDAV collection URL.
STORAGE_n_USERNAMENoUsername. Falls back to ACCESS_KEY_ID.
STORAGE_n_PASSWORDNoPassword. Falls back to SECRET_ACCESS_KEY.
STORAGE_n_AUTH_TYPENoAuth strategy, see below.
STORAGE_n_ROOTNoBrowse only this folder on the server. Defaults to the collection root.
STORAGE_n_NAMENoDisplay name in the sidebar. Defaults to the server URL.
STORAGE_n_PUBLIC_BASE_URLNoPublic base URL for file links, see below.
STORAGE_n_READ_ONLYNoSet to true to disable all edits for this connection.

AUTH_TYPE accepts password (the default when a username is set), basic (the same strategy under another name), digest, auto (try anonymous, fall back to the challenge the server returns), and none. An unrecognized value is ignored with a warning.

Two differences from the S3 providers.

  • WebDAV always routes through this app's server, whatever the Direct client requests setting says, so the server needs network access to the WebDAV host. On a private address, see Private endpoints below.
  • Without PUBLIC_BASE_URL, file bytes stream through the app server rather than through a signed URL. Set it to a public HTTP origin fronting the same files to get direct preview URLs.

Private endpoints

VariableDefaultDescription
ALLOW_PRIVATE_ENDPOINTSfalseLet connections added from the UI point at a private address.

In production, a connection a user adds from the UI may not point at a private address, because the server fetches that endpoint on the user's behalf. Blocked are localhost, *.local, *.internal, the loopback, link-local, and carrier-grade NAT ranges, and the private ranges 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16.

ALLOW_PRIVATE_ENDPOINTS=true

Set it when the deployment legitimately browses a LAN NAS or a sibling container. Two things it does not cover.

  • STORAGE_n_* connections are the operator's own and are never checked, so a self-hosted setup that only uses env-configured buckets does not need this.
  • Local development is exempt, so the restriction appears only once the app runs with NODE_ENV=production.

Turnstile

Add a Cloudflare Turnstile challenge to the login form. Create a widget in the Cloudflare dashboard, then set both keys.

TURNSTILE_SITE_KEY=0x4AAAAAAA...
TURNSTILE_SECRET_KEY=0x4AAAAAAA...
VariableRequiredDescription
TURNSTILE_SITE_KEYFor the challengeWidget site key. Public, sent to the browser.
TURNSTILE_SECRET_KEYFor the challengeWidget secret key. Server-side only.

The challenge stays off unless both are set, and a warning is logged when only one is. It applies to the login form, so it does nothing without AUTH_USERNAME and AUTH_PASSWORD.

Neither key is read at build time, so the same Docker image works with any pair of keys, and both can be changed with a restart.