Sluby

Configuration reference

Every environment variable of every Sluby service, with its default and what it does.

This page lists every setting a Sluby server reads: the backend, the web proxy, the Studio build, the production override with Caddy, and the image builds. You set them in the .env file in the folder where you cloned Sluby. Docker Compose reads that file and passes each value to the service that needs it. Two exceptions: STUDIO_API_PROXY_TARGET goes in frontend/.env, and the rows that say Compose sets the value (DATABASE_URL, REDIS_URL, PORT, HOST, UPLOAD_DIR, TRANSCODE_OUTPUT_DIR) ignore .env in the Compose stack.

How settings are read

  • Docker Compose reads .env from the project folder and substitutes the values into docker-compose.yml (and docker-compose.prod.yml when you use it).
  • An empty value counts as unset. SIA_DATA_SHARDS= behaves exactly like leaving the line out, so the backend takes its own default.
  • On/off settings accept true, false, 1 or 0. The backend refuses any other value, such as yes or TRUE, and does not start.
  • The backend reads its settings once, at startup. After you change one, run docker compose up -d (with the same -f files you started with) so Compose recreates the containers whose settings changed.
  • The VITE_ settings are compiled into the Studio when the web image is built. After you change one, rebuild the web image: docker compose up -d --build web (with the same -f files you started with).
  • When the backend finds an invalid value, it prints Refusing to start, the configuration is not valid: followed by one line per problem, and exits. See Troubleshooting.

The Default column shows the value the shipped Docker Compose stack runs with. Where the backend's own default differs (it applies when you run the backend from source), the description says so.

Backend: server and logging

Read by the backend service.

VariableDefaultDescription
NODE_ENVdevelopmentdevelopment, production or test. production turns on the startup checks (a strong SESSION_SECRET is required, AUTH_DISABLED=true is refused, BOOTSTRAP_API_KEY must be a generated key) and switches the logs to JSON. Outside production the logs are colored text. docker-compose.prod.yml sets it to production.
LOG_LEVELinfoLog level of the backend and of the Sia storage SDK it uses: fatal, error, warn, info, debug, trace or silent.
EXPOSE_ERROR_STACKSfalsetrue adds the internal error message and stack trace to API error responses. They contain file paths and internals, so use it only for debugging. The backend logs a warning at startup while it is on.
PUBLIC_URLhttp://localhost:8080The address people open in the browser, without a trailing slash. The backend builds upload URLs, the GitHub callback URL, invite and reset links, signed playback URLs and watch page links from it. The session cookie is marked Secure only when it starts with https://. docker-compose.prod.yml sets it to https:// plus DOMAIN. Backend default: http://localhost:3000.
PORT3000Port the backend listens on. Compose sets it to 3000, the port the web proxy connects to (backend:3000). Backend default: 3000.
HOST0.0.0.0Address the backend listens on. Compose sets it to 0.0.0.0. Backend default: 0.0.0.0.

Backend: database and queue

VariableDefaultDescription
POSTGRES_PASSWORDslubyPassword of the sluby database user. Compose passes it to the postgres service and puts it, unencoded, into DATABASE_URL, so use letters and digits only: generate one with openssl rand -hex 32. A value with / makes the backend refuse to start with DATABASE_URL: Invalid URL. docker-compose.prod.yml requires it. The postgres image applies it only when it creates the database on an empty volume, so set it before the first start.
DATABASE_URLpostgresql://sluby:<POSTGRES_PASSWORD>@postgres:5432/slubyPostgreSQL connection string. Compose sets it for the backend container, so you do not set it in the Compose stack. Backend default: postgresql://sluby:sluby@localhost:5432/sluby.
REDIS_URLredis://redis:6379Redis connection string, used for the job queues. Compose sets it for the backend container. Backend default: redis://localhost:6379.

To run the backend from source against the Compose databases, docker-compose.dev.yml publishes PostgreSQL on 127.0.0.1:5433 and Redis on 127.0.0.1:6380. Then set these two lines in .env:

.env
DATABASE_URL=postgresql://sluby:sluby@localhost:5433/sluby
REDIS_URL=redis://localhost:6380

Backend: Sia storage

How to get these values: Connect Sia storage.

VariableDefaultDescription
SIA_INDEXER_URLhttps://sia.storageBase URL of the indexer's application API, without a trailing slash. The backend connects to this indexer to store and read media on Sia.
SIA_NETWORKmainnetThe Sia network the indexer runs on: mainnet, zen, testnet or anagami. Used for labels in the Studio and to pick the explorer for host and contract links (zen and testnet link to Zen Siascan, every other value to Siascan).
SIA_APP_IDemptyThe 32-byte app ID (hex) that connect-indexer.mjs prints. Keep it the same across restarts. docker-compose.prod.yml requires it.
SIA_APP_KEYemptyThe 32-byte app key (hex) that connect-indexer.mjs prints. The backend signs every indexer request with it. It can read and delete everything this app stores, so keep it secret. Without it the backend starts but uploads fail, and it logs a warning. docker-compose.prod.yml requires it.
SIA_DATA_SHARDSunsetData shards per slab. Leave both shard settings unset for the SDK default of 10 data and 20 parity shards (30 hosts per slab). Set both, and only to fit an indexer with a smaller host pool. The SDK and the indexer reject ratios whose recovery probability is under 99.99% or whose redundancy is outside 1.5x to 4x. When only one of the two is set, uploads use the SDK default.
SIA_PARITY_SHARDSunsetParity shards per slab. See SIA_DATA_SHARDS.
SIA_ADMIN_URLhttp://127.0.0.1:9980Admin API of a self-hosted indexd, without a trailing slash. Used only when SIA_ADMIN_PASSWORD is set, to add contract IDs and the wallet address to the storage breakdown.
SIA_ADMIN_PASSWORDemptyHTTP Basic password of that admin API (the indexd adminAPI.password). Empty turns the admin lookups off.

Backend: sign-in and sessions

How to use these: Set up sign-in.

VariableDefaultDescription
SESSION_SECRETunsetSecret that signs session cookies and private playback URLs. The setup code for the first admin is also derived from it. Outside production, when it is unset, the backend generates one on its first start and keeps it in its database, so restarts sign nobody out. In production the backend refuses to start unless it is set, at least 32 characters long, and not the old public development value. Generate one with openssl rand -base64 32. Changing it signs everyone out and makes signed links already handed out stop working. docker-compose.prod.yml requires it.
AUTH_DISABLEDfalsetrue turns sign-in off: every request acts as one local admin account. The API then sends no CORS headers to origins that are not listed in CORS_ORIGIN. Production refuses to start with it on, and docker-compose.prod.yml forces it to false.
GITHUB_CLIENT_IDunsetClient ID of a GitHub OAuth app. GitHub sign-in is offered when both GitHub settings are set.
GITHUB_CLIENT_SECRETunsetClient secret of that GitHub OAuth app.
GITHUB_ALLOWED_USERSemptySetting from versions before members and roles. The first start after the upgrade removes the GitHub accounts it refused. After that the backend ignores it and logs a warning at every start while it is set. Remove it after the upgrade.
OPERATOR_USERSemptySetting from versions before members and roles, as comma-separated <provider>:<entry> values such as github:octocat. The first start after the upgrade makes the listed accounts admins. After that the backend ignores it and logs a warning at every start while it is set. Remove it after the upgrade.
BOOTSTRAP_API_KEYunsetAn API key with every scope that the backend creates before it takes requests. It is created once: after you delete or rotate it, it is never created again, and the backend logs a warning while the old value is still set. In production it must look like a generated key (sluby_ and at least 32 more letters, digits, - or _). Generate one with node -e "console.log('sluby_' + require('crypto').randomBytes(32).toString('base64url'))".

Backend: API access and limits

VariableDefaultDescription
CORS_ORIGINemptyComma-separated browser origins (scheme://host[:port], no path, no trailing slash) whose pages can call the API with the Studio session cookie. Every other origin can still call the API with an API key, without cookies, unless AUTH_DISABLED is on. docker-compose.prod.yml sets it to https:// plus DOMAIN.
TRUST_PROXYloopback, linklocal, uniquelocalWhich proxy hops the backend trusts for the client address in X-Forwarded-For: a hop count, true, false, or comma-separated addresses, CIDR ranges and the names loopback, linklocal and uniquelocal. The default trusts private networks, which covers the web proxy alone and Caddy in front of it.
API_IP_RATE_LIMIT600Requests per minute one client address can make to /api/v1 without a valid API key or session (sign-in routes, the API spec, failed authentication).
API_KEY_RATE_LIMIT_MAX10000The highest per-minute rate limit an API key can have. Creating a key that asks for more is refused, and older keys are held to this value.
API_KEYS_PER_ACCOUNT_MAX100How many API keys can be active at once. Revoked and expired keys do not count. Creating a key beyond this number is refused.
METRICS_TOKENunsetWhen set, GET /metrics requires Authorization: Bearer <token>. Unset, it answers anyone who reaches the backend port.
WEBHOOK_ALLOWED_NETWORKSemptyComma-separated CIDRs or addresses of private or otherwise special networks that webhook receivers can be on, such as 10.0.5.0/24,fd00:5::/64. Empty: webhooks reach public addresses only.

Backend: uploads, transcoding and delivery

VariableDefaultDescription
MAX_UPLOAD_SIZE10737418240Largest upload in bytes (10 GiB).
TRANSCODE_MAX_RENDITION1080pTallest rendition the transcoder makes: 2160p, 1440p, 1080p, 720p, 540p or 360p. 1440p and 2160p add renditions above 1080p for sources that tall. A lower value drops renditions. The full ladder is in Upload pipeline.
CACHE_MAX_SIZE_MB256Size of the backend's in-memory object cache in megabytes. It holds whole objects of up to 8 MB that are read without a Range header (manifests, playlists, thumbnails) and counts against the backend container's memory. Larger objects are streamed and never held.
UPLOAD_DIR/app/uploadsDirectory for incoming uploads. Compose sets it and mounts the uploads volume there. Backend default: ./uploads.
TRANSCODE_OUTPUT_DIR/app/transcode-outputDirectory for transcoder output. Compose sets it and mounts the transcode-output volume there. Backend default: ./transcode-output.

Backend: background jobs

What these jobs do: Deletion and reconciliation.

VariableDefaultDescription
RECONCILE_ENABLEDtrueRuns the scheduled reconciliation, which compares the database with what the indexer stores. false stops the schedule. Runs you start on demand still work.
RECONCILE_INTERVAL_MS3600000Time between scheduled reconciliation runs, in milliseconds (one hour).
RECONCILE_PAGE_SIZE500Page size when reconciliation reads the indexer's object list. At most 500, because the indexer answers larger pages with an error.
DELETION_GC_ENABLEDtrueRuns the deletion sweep, which finishes deletions that stopped before every object was unpinned.
DELETION_GC_INTERVAL_MS900000Time between deletion sweeps, in milliseconds (15 minutes).
DELETION_STUCK_THRESHOLD_MS600000How long ago a video must have been deleted before the sweep treats its unfinished deletion as stuck and starts it again, in milliseconds (10 minutes).

Web proxy

The web service is nginx. It serves the Studio and passes the API and video delivery to the backend. It checks these values when the container starts and exits with a message such as WEB_DELIVERY_RATE=fast is not valid (expected a rate such as 50r/s or 600r/m) when one is malformed.

VariableDefaultDescription
WEB_PORT8080Port on 127.0.0.1 where the base stack publishes the web proxy. Set PUBLIC_URL to match. docker-compose.prod.yml publishes no web port; Caddy connects to it instead.
WEB_DELIVERY_RATE100r/sRequest rate per client address on delivery paths (/v1/), as <n>r/s or <n>r/m.
WEB_DELIVERY_BURST400Requests a client can make on delivery paths above that rate before nginx answers 429.
WEB_DELIVERY_CONN200Open connections per client address on delivery paths.
WEB_AUTH_RATE10r/sRequest rate per client address on sign-in paths (/api/v1/auth/), as <n>r/s or <n>r/m.
WEB_AUTH_BURST50Requests a client can make on sign-in paths above that rate before nginx answers 429.
WEB_AUTH_CONN20Open connections per client address on sign-in paths.

Studio build

These are compiled into the Studio's JavaScript when the web image is built, so every visitor's browser receives them. Rebuild the web image after changing them: docker compose up -d --build web (with the same -f files you started with).

VariableDefaultDescription
VITE_SLUBY_SIA_INDEXER_URLunsetIndexer URL of the viewer identity for streaming from Sia in the browser. Use an https:// URL: the Studio's content security policy (connect-src 'self' https:) blocks plain http:// addresses. The Studio streams from Sia only when all three VITE_SLUBY_SIA_ values are set. See Stream from Sia in the browser.
VITE_SLUBY_SIA_APP_IDunsetApp ID of the viewer identity that provision-viewer.mjs prints.
VITE_SLUBY_SIA_APP_KEYunsetApp key of the viewer identity that provision-viewer.mjs prints. It is public once built in. Never put SIA_APP_KEY here.
VITE_SIA_EXPLORER_URLunsetSia explorer for host, contract and address links in the Studio. Unset, the Studio uses https://zen.siascan.com when SIA_NETWORK is zen or testnet, and https://siascan.com otherwise.
STUDIO_API_PROXY_TARGEThttp://localhost:3000Only for the Studio's development server (npm run dev in frontend/), read from frontend/.env: where it forwards /api, /v1, /health and /watch.

Production with Caddy

Read by docker-compose.prod.yml and the caddy service. See Run in production.

VariableDefaultDescription
DOMAINnone, requiredThe domain the server answers on, such as sluby.example.com. Caddy gets and renews its TLS certificate. The override also sets PUBLIC_URL and CORS_ORIGIN to https:// plus this value.
ACME_EMAILnone, requiredEmail address Caddy gives the certificate authority when it requests the certificate.

docker-compose.prod.yml also requires POSTGRES_PASSWORD, SESSION_SECRET, SIA_APP_ID and SIA_APP_KEY, and it sets NODE_ENV=production and AUTH_DISABLED=false whatever .env says.

Backend image build

VariableDefaultDescription
SIA_STORAGE_NATIVEunsetPath, relative to backend/vendor/, of a custom-built Sia storage native module to put in the backend image instead of the standard one, for example sia-storage-linux-x64-gnu/sia-storage.node. The build fails when the file is missing. backend/vendor/README.md explains how to build one.

Local indexer stack

Read by docker-compose.sia.yml, which runs indexd, its own PostgreSQL, walletd and a CPU miner for the Zen testnet. It is separate from the Sluby stack.

VariableDefaultDescription
INDEXD_POSTGRES_PASSWORDnonePassword of the indexd user in the indexer's own PostgreSQL.
WALLETD_API_PASSWORD1234API password of walletd, which the miner uses.
MINER_ADDRESSnoneWallet address the miner pays out to: the indexd wallet address.

On this page