Documentation

Configuration

Every YAML key with type, default, and effect. Source of truth: internal/config/config.go.

#Top-level structure

server:    {...}
log:       {...}
db:        {...}
auth:      {...}
backends:  [{...}, ...]
quotas:    {...}
ratelimit: {...}
s3_proxy:  {...}
audit:     {...}

#server

KeyTypeDefaultNotes
server.listenstring:8080HTTP listen address for the dashboard. Required.
server.shutdown_timeoutduration10sDrain window after SIGTERM/SIGINT.
server.public_urlstring""Used to render absolute share URLs. Optional.
server.trusted_proxies[]CIDR[]CIDRs whose X-Forwarded-* headers are honoured. Empty = trust every immediate peer.
server.secret_key_filestring""Path to a file holding the AES-256 root key. Auto-generated mode 0600 if missing.

#log

KeyTypeDefaultNotes
log.levelstringinfodebug, info, warn, error.
log.formatstringjsonjson or text.

#db

KeyTypeDefaultNotes
db.driverstringsqliteOnly sqlite is implemented today.
db.sqlite.pathstring./stowage.dbPath to the SQLite database file.

#auth

auth:
  modes: [local]
  session:
    lifetime: 8h
    idle_timeout: 1h
  local:
    allow_self_registration: false
    require_admin_approval: false
    password:
      min_length: 12
      prevent_reuse: true
    lockout:
      max_attempts: 5
      window: 15m
    reset_email:
      enabled: false
  oidc:
    issuer: ""
    client_id: ""
    client_secret_env: ""
    scopes: [openid, profile, email]
    role_claim: ""
    role_mapping: {}
  static:
    enabled: false
    username: ""
    password_hash_env: ""
KeyTypeDefaultNotes
auth.modes[]string[local]At least one of local, oidc, static.
auth.session.lifetimeduration8hHard ceiling.
auth.session.idle_timeoutduration1hIdle-out window.
auth.local.password.min_lengthint12Minimum password length.
auth.local.password.prevent_reusebooltrueReject changes that match the current password.
auth.local.lockout.max_attemptsint5Per-user failed-login limit before lockout.
auth.local.lockout.windowduration15mLockout window.
auth.oidc.issuerstring""OIDC issuer URL. Required when mode includes oidc.
auth.oidc.client_idstring""OIDC client ID.
auth.oidc.client_secret_envstring""Name of env var holding the client secret.
auth.oidc.scopes[]string[openid, profile, email]
auth.oidc.role_claimstring""ID-token claim listing groups.
auth.oidc.role_mappingmap[role]→[]group{}Stowage role → group strings.
auth.static.enabledboolfalse
auth.static.usernamestring""The static account's username.
auth.static.password_hash_envstring""Env var holding the argon2id hash.

#backends

A list. Each entry:

KeyTypeNotes
idstringUnique stable identifier. Required.
namestringHuman-readable label.
typestringDriver. Today only s3v4.
endpointstringBase URL of the upstream API.
regionstringAWS region or backend's region label.
access_key_envstringEnv var holding the access key.
secret_key_envstringEnv var holding the secret key.
path_styleboolUse path-style addressing.

#quotas

KeyTypeDefaultNotes
quotas.scan_intervalduration30mScheduled re-count cadence. Negative = disabled.

#ratelimit

KeyTypeDefaultNotes
ratelimit.api_per_minuteint600Per-session req/min on /api/*. 0 disables.

#s3_proxy

KeyTypeDefaultNotes
s3_proxy.enabledboolfalseMaster switch for the proxy.
s3_proxy.listenstring:8090Bind address for the proxy. Must differ from server.listen.
s3_proxy.host_suffixes[]string[]Virtual-hosted-style host suffixes (e.g. s3.example.com).
s3_proxy.global_rpsfloat0Total RPS ceiling across all credentials. 0 = unlimited.
s3_proxy.per_key_rpsfloat0Per-credential RPS ceiling. 0 = unlimited.
s3_proxy.anonymous_enabledboolfalseCluster-wide kill switch for anonymous reads.
s3_proxy.anonymous_rpsfloat20Per-source-IP RPS default for anonymous reads.
s3_proxy.kubernetes.enabledboolfalseRead virtual creds from a Kubernetes Secret informer.
s3_proxy.kubernetes.namespacestringstowage-systemNamespace holding the operator-written Secrets.
s3_proxy.kubernetes.kubeconfigstring""Optional kubeconfig path. Empty = in-cluster.

#audit

KeyTypeDefaultNotes
audit.sampling.proxy_success_read_ratefloat (0..1)0.0Fraction of successful proxy reads to record. Writes/deletes/errors always recorded.

#Environment variables

The following env vars override config-file values at runtime:

VariableOverrides
STOWAGE_LISTENserver.listen
STOWAGE_PUBLIC_URLserver.public_url
STOWAGE_LOG_LEVELlog.level
STOWAGE_LOG_FORMATlog.format
STOWAGE_SQLITE_PATHdb.sqlite.path
STOWAGE_SECRET_KEY_FILEserver.secret_key_file

The following env vars are read directly (no config-file equivalent):

VariableEffect
STOWAGE_SECRET_KEYAES-256 root key. 64 hex chars or 44 base64 chars. Takes precedence over secret_key_file.
STOWAGE_PPROF_LISTENIf set, exposes /debug/pprof/* on the given address.

Backend access keys, OIDC client secrets, and the static-auth password hash are read from env vars named by the config-file fields (access_key_env, client_secret_env, password_hash_env) — the secrets themselves never appear in the YAML.

#Validation rules

Loader rejects any of these:

  • server.listen empty.
  • log.format ∉ {json, text, ""}.
  • log.level ∉ {debug, info, warn, error, ""}.
  • db.driver ∉ {sqlite, ""}.
  • db.driver=sqlite and db.sqlite.path empty.
  • auth.modes empty or contains anything outside local, oidc, static.
  • Two backends sharing the same id.
  • A backend with empty id or type.
  • s3_proxy.enabled=true and s3_proxy.listen empty or equal to server.listen.