Skip to content

Environment Variables

All Sairo configuration is done through environment variables. This page lists every supported variable grouped by category.

VariableDefaultDescription
S3_ENDPOINT(required)S3-compatible endpoint URL
S3_ACCESS_KEY(required)S3 access key ID
S3_SECRET_KEY(required)S3 secret access key
S3_REGION(empty)S3 region
S3_MAX_POOL_CONNECTIONS32Max pooled connections per S3 client, so parallel crawl/delta list calls don’t serialize on a small pool
VariableDefaultDescription
UPLOAD_PROXY_CONCURRENCY3Files streamed in parallel through the proxy-upload fallback. Bounds peak server memory (~100 MB per in-flight file × this value). The default direct browser→S3 path uses no server memory.
MULTIPART_URL_EXPIRY3600Lifetime (seconds) of each presigned multipart part URL. Parts are signed just-in-time, so this only needs to cover a single part’s upload.
MAX_UPLOAD_SIZE5368709120 (5 GB)Maximum total size for a proxy upload request. Does not apply to direct browser→S3 uploads.
VariableDefaultDescription
AUTH_MODElocalAuthentication mode: local (username/password) or s3 (log in with S3 access key + secret; access is scoped to each user’s own keys via the provider’s IAM)
ADMIN_USERadminUsername for the default admin account
ADMIN_PASS(auto-generated)Password for the default admin account. If not set, a random password is printed to logs on first startup.
JWT_SECRET(auto-generated)Secret key for signing JWT tokens. Set explicitly for multi-instance deployments.
SESSION_HOURS24Session duration in hours
SECURE_COOKIEtrueSet to false for HTTP (non-HTTPS) deployments or cookies will silently fail
VariableDefaultDescription
RECRAWL_INTERVAL120Seconds between automatic reindex cycles for each bucket
DB_DIR/dataDirectory where SQLite index databases are stored
FULL_CRAWL_INTERVAL3600Seconds between full reconcile crawls for large buckets (delta crawls run on RECRAWL_INTERVAL in between)
LARGE_BUCKET_SECONDS60A bucket whose full crawl takes longer than this is treated as “large” and kept fresh with delta crawls + periodic full reconcile, instead of full re-crawls every interval
REBUILD_MAX_DURATION7200Seconds a search-index rebuild may hold its bucket. Past this the reservation is abandoned so crawls and deltas can resume, mirroring the equivalent ceiling on a crawl. Raise it only if a single bucket’s rebuild legitimately runs longer than two hours.
FTS_PROBE_MS10000Milliseconds the search-index health probe may run before it gives up. The probe is three constant-time queries, so only an unreadable or corrupt index reaches this; one that does is treated as unhealthy and rebuilt rather than blocking the caller.

These bound how the incremental delta crawler discovers new data on large buckets. The defaults suit time-partitioned layouts (e.g. year=/month=/day=/hour=); they rarely need changing.

VariableDefaultDescription
DELTA_SAMPLE3000How many of the most recently-indexed objects to sample to locate the “hot” prefixes a delta crawl should re-list
DELTA_MAX_TARGETS40Cap on the number of hot prefixes re-listed per delta crawl
DELTA_BRANCH_FANOUT8Levels with more children than this are treated as time partitions (follow only the newest few); fewer means a descriptive branch (follow all)
DELTA_NEWEST_K2How many of the newest partitions to re-list at a partition level (current + just-rolled)
DELTA_MAX_DEPTH12Safety cap on prefix-walk depth
LIST_CONCURRENCY16Total S3 list calls in flight across every bucket the crawler is working on, covering initial crawls, reconciles, delta discovery and delta target listing. The per-bucket settings below bound one bucket; this bounds the process. Raising it raises peak memory, since each in-flight listing holds a response body and a batch buffer. Clamped to S3_MAX_POOL_CONNECTIONS so concurrent lists never overflow the connection pool.
DELTA_LIST_CONCURRENCY16Parallel S3 list calls per level during delta discovery, within the LIST_CONCURRENCY total
DELTA_MAX_NODES2000Safety cap on folders visited per delta crawl
DELTA_NODE_MAX_PAGES3Delimiter pages read per folder during delta discovery, at 1,000 entries each. A folder wider than this is left unvisited and the delta is reported partial rather than certified. Raise it if a single folder legitimately holds more than 3,000 children.
VariableDefaultDescription
LDAP_ENABLEDfalseEnable LDAP authentication
LDAP_SERVER(none)LDAP server URI (e.g., ldap://ldap.example.com:389 or ldaps://ldap.example.com:636)
LDAP_BASE_DN(none)Base DN for user searches (e.g., ou=people,dc=example,dc=com)
LDAP_USER_FILTER(sAMAccountName={username})LDAP search filter. {username} is replaced with the login username.
LDAP_BIND_DN(none)DN of the service account used to search for users
LDAP_BIND_PASSWORD(none)Password for the bind DN
LDAP_ADMIN_GROUP(none)LDAP group DN whose members are assigned the admin role
LDAP_DEFAULT_ROLEviewerDefault role for LDAP-provisioned users
VariableDefaultDescription
OAUTH_GOOGLE_CLIENT_ID(none)Google OAuth 2.0 Client ID
OAUTH_GOOGLE_CLIENT_SECRET(none)Google OAuth 2.0 Client Secret
OAUTH_GITHUB_CLIENT_ID(none)GitHub OAuth App Client ID
OAUTH_GITHUB_CLIENT_SECRET(none)GitHub OAuth App Client Secret
OAUTH_DEFAULT_ROLEviewerDefault role for OAuth-provisioned users
OAUTH_ALLOWED_DOMAINS(none)Comma-separated list of allowed email domains for Google OAuth

Generic OIDC SSO for any compliant provider. Enabled when OIDC_ISSUER and OIDC_CLIENT_ID are both set. See OAuth, OIDC & LDAP for per-provider setup.

VariableDefaultDescription
OIDC_ISSUER(none)Issuer URL, e.g. https://login.example.com/realms/main. Endpoints are auto-discovered from <issuer>/.well-known/openid-configuration
OIDC_CLIENT_ID(none)Client/application ID from your provider
OIDC_CLIENT_SECRET(none)Client secret. Omit for a public client (PKCE is always used)
OIDC_PROVIDER_NAMESSOLabel on the login button
OIDC_USERNAME_CLAIMpreferred_usernameClaim used as the local username (e.g. email for Google)
OIDC_SCOPESopenid profile emailRequested scopes
OIDC_DEFAULT_ROLEviewerRole for new users (they get no bucket access until an admin grants it)
OIDC_ALLOWED_DOMAINS(none)Comma-separated email-domain allowlist
OIDC_ADMIN_GROUP(none)If set, members of this group become admins (enables group→role mapping)
OIDC_GROUPS_CLAIMgroupsClaim that carries the user’s groups
OIDC_REQUIRE_VERIFIED_EMAILfalseReject logins whose email isn’t verified
OIDC_RP_LOGOUTfalseAlso end the IdP session on logout (single logout)
VariableDefaultDescription
APP_NAMESairoApplication name displayed in the UI and browser tab
PRIMARY_COLOR#3b82f6Primary theme color (hex code, e.g., #2563eb)
APP_LOGO(none)URL to a custom logo image displayed on the login page and sidebar
LOGIN_MESSAGE(none)Custom message displayed on the login page (supports plain text)
VariableDefaultDescription
RATE_LIMIT120/minuteGeneral API rate limit per IP
UPLOAD_RATE_LIMIT30/minuteRate limit for upload requests per IP

Login attempts are rate-limited with two layers: 10 per minute via slowapi and 10 per 5 minutes per IP via a hardcoded window. Neither is independently configurable.

VariableDefaultDescription
TELEMETRYtrueSend an anonymous usage heartbeat (schema v2: aggregate counts, instance health, and activation timestamps only — never names, keys, paths, or content). Set to false to disable entirely. See Telemetry.
TELEMETRY_INTERVAL3600Seconds between heartbeats.
TELEMETRY_URLhttps://dashboard.sairo.dev/api/v1/pingEndpoint the heartbeat is POSTed to. Override to point at your own collector (or leave unset to disable by setting TELEMETRY=false).
SAIRO_STORAGE_EPHEMERAL(auto)Optional hint for the telemetry id_persistence field: true if DB_DIR is ephemeral (e.g. emptyDir), false if durable. The Helm chart sets it from persistence.enabled; otherwise Sairo infers it from the mount table.
services:
sairo:
image: stephenjr002/sairo:latest
ports:
- "8000:8000"
environment:
# S3
S3_ENDPOINT: "https://s3.us-east-1.amazonaws.com"
S3_ACCESS_KEY: "AKIAIOSFODNN7EXAMPLE"
S3_SECRET_KEY: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
S3_REGION: "us-east-1"
# S3_PATH_STYLE is configured per-endpoint via the UI, not globally
# Auth
ADMIN_USER: "admin"
ADMIN_PASS: "super-secret-password"
JWT_SECRET: "a-long-random-string-for-signing"
SESSION_HOURS: "24"
SECURE_COOKIE: "true"
# Crawler
RECRAWL_INTERVAL: "120"
# Branding
APP_NAME: "My Storage"
PRIMARY_COLOR: "#2563eb"
LOGIN_MESSAGE: "Welcome to the storage portal"
# Rate Limiting
RATE_LIMIT: "120/minute"
UPLOAD_RATE_LIMIT: "30/minute"
volumes:
- sairo-data:/data
volumes:
sairo-data: