Skip to content

Configuration

S3 Lens reads YAML configuration. The standalone process automatically loads s3lens.yaml from its current directory when the file exists, or you can select one or more files with --config.

workspace:
id: local
display_name: Local storage
providers:
- id: garage
display_name: Garage
type: generic
endpoint: http://127.0.0.1:3900
region: garage
force_path_style: true
credentials:
access_key_id: ${GARAGE_ACCESS_KEY}
secret_access_key: ${GARAGE_SECRET_KEY}
server:
listen: http://127.0.0.1:8085
allow_insecure_remote: false
max_object_body_bytes: 16777216
logging:
level: info
ui:
enabled: false
# title: Local storage | S3 Lens

Provider type defaults to generic when omitted. See Storage providers for the supported types.

Unknown fields are rejected. Configuration validation is local: it checks YAML shape, identifiers, endpoints, credentials, and cross-field invariants without contacting a Provider.

Section Purpose
workspace Stable Workspace identity and its configured Providers.
server Listener safety and the maximum Object body permitted in bounded RPC operations.
logging Standalone process verbosity: error, warn, info, debug, or trace.
ui Serve the bundled browser application and set its optional browser title.
auth Optional OIDC authentication, policies, bindings, and durable API Keys.

When workspace is omitted, the server uses the development identity default / Default Workspace with no Providers. The default listener is http://127.0.0.1:8085.

ui.enabled defaults to false. When enabled, a binary built with the embed-ui Cargo feature serves the browser application at /, alongside the RPC and authentication endpoints. Static assets are public so the sign-in page can load before authentication. Existing API authentication still applies.

Run pnpm run build from the repository root to build target/release/s3lens with fresh production assets. The Docker image also includes the assets. Neither needs Node.js or frontend files at runtime.

Ordinary Cargo builds omit the assets. Starting one with ui.enabled: true or --ui fails with an error before opening the state database. The bundled UI uses the server’s origin, ignores VITE_RPC_URL, and is served at the origin root rather than a configurable URL prefix.

HTML, fonts, and favicons revalidate through ETags. Fingerprinted files under /assets/ use immutable caching. Browser navigation under /providers and /settings receives the application HTML, including Object paths containing dots. Missing assets and unknown API paths return errors instead of HTML.

GET /v1/instance is always available, including when the bundled UI is disabled. It returns the public Workspace display name as name and the configured ui.title as title. If ui.title is omitted, title uses the Workspace display name. The endpoint contains no authentication or Provider configuration.

The standalone process resolves values from lowest to highest precedence:

  1. Built-in defaults
  2. Configuration files from left to right
  3. Command-line options such as --listen, --log-level, --ui, and --allow-insecure-remote
Terminal window
cargo run -- serve \
--config ./base.yaml \
--config ./deployment.yaml \
--config ./local-secrets.yaml

Later mapping values override earlier ones. Provider lists merge by stable Provider ID: a later Provider with the same ID replaces the complete earlier entry while keeping its position. Other YAML sequences, including authentication policies and bindings, replace the earlier sequence as a whole.

Selected operational string fields support environment references:

  • ${NAME} requires a non-empty environment variable.
  • ${NAME:-} uses an empty-string fallback.
  • ${NAME:-value} uses value when the variable is absent or empty.

Expansion is supported in server.listen; Provider region, endpoint, and credential fields; auth.public_origin; Redis auth.session.url; and OIDC issuer, client_id, client_secret, redirect_uri, and post_logout_redirect_uri. Identity fields, display names, policy documents, bindings, OIDC scopes, and claim selectors remain literal.

credentials:
access_key_id: ${S3_ACCESS_KEY_ID}
secret_access_key: ${S3_SECRET_ACCESS_KEY}
session_token: ${S3_SESSION_TOKEN:-}

The server accepts plain HTTP because local and embedded hosts commonly terminate TLS elsewhere. Non-loopback listeners are rejected unless server.allow_insecure_remote or --allow-insecure-remote is explicitly enabled. That switch only relaxes the listener check; it does not add TLS, authentication, authorization, or origin restrictions.

Terminal window
cargo run -- config validate
cargo run -- config validate --config ./deployment.yaml

config show loads, merges, expands, and canonicalizes the same document the server would use. Provider credentials and OIDC client secrets are replaced by a visible [REDACTED] marker before the YAML is printed.

Terminal window
cargo run -- config show --config ./base.yaml --config ./deployment.yaml

For complete examples, see the configurations under examples/ and Storage providers.