Configuration

hybrids3 reads one YAML file, /config/config.yaml, at startup. It defines the master key, a few server settings and every bucket. There is no other configuration and no environment variable for any of this. Change the file and restart the container to apply a change.

The annotated example is config.example.yaml, and the parser is app/config.py.

Example

master_key: "change-me-to-something-secret"
master_public_key: "master"
cleanup_interval: 1m
lock_acquire_timeout: 30
lock_hold_timeout: 300
lock_max_waiters: 100
# path_prefix: /storage

buckets:
  uploads:
    public: true
    key: "uploads-secret"
    public_key: "uploads-id"
    ttl: 24h
    max_file_size: 50MB

  permanent:
    public: false
    key: "perm-secret"
    public_key: "permanent-id"
    ttl: 0
    max_file_size: 100MB

Replace every key before you expose the server. The example keys are public.

Top-level settings

Setting Default Meaning
master_key "" Secret that works on every bucket for every operation and is the only key that lists all buckets. Empty disables the master key. See Keys and access
master_public_key "master" Non-secret aws_access_key_id that pairs with master_key for S3 clients
cleanup_interval 60 Time between runs of the cleanup loop that deletes expired objects and orphan files. A duration or a number of seconds. Use a value above zero
lock_acquire_timeout 30 Seconds a request waits for the lock on one object before it gets 503. Decimals allowed
lock_hold_timeout 300 Seconds a request may hold the lock on one object. When it runs out, the lock is released and the request gets 503. Raise it if large uploads over slow links take longer
lock_max_waiters 100 Requests that may wait for the same object at once. The next one gets 503 immediately
path_prefix "" Serve every route under this path, for a reverse proxy at a subpath. /storage, /storage/ and storage all become /storage. Empty serves at the root
buckets none Map of bucket name to bucket settings. At least one bucket is required

Storage, expiry and locking explains the three lock settings.

Bucket settings

Each entry under buckets is keyed by the bucket name. A name must not be empty and must not contain / or ... S3 clients use path-style URLs (http://host:8080/<bucket>/<key>), so names do not have to be valid DNS labels, but lowercase letters, digits and hyphens keep every client happy.

Setting Default Meaning
key required The bucket’s private key. It is the Bearer token for HTTP and MCP and the aws_secret_access_key for S3. Keep it secret
public false true lets anyone read (GET, HEAD, list) without a key. Writes, deletes and presigning always need a key. Write it as an unquoted YAML boolean
public_key the bucket name Non-secret aws_access_key_id for this bucket. It appears in signed request headers and presigned URLs. Keep it unique across buckets and different from master_public_key
ttl 0 Objects expire this long after their last write. 0 keeps them forever. A duration or a number of seconds. See TTL expiry
max_file_size 0 Largest object accepted, as a size or a number of bytes. Bigger uploads get 413. 0 means no limit

Unknown settings are ignored without a warning, so check the spelling of anything that seems to have no effect.

Durations

ttl and cleanup_interval accept a number of seconds (86400) or a duration string parsed by pytimeparse2: 30s, 5m, 1h, 1h30m12s, 1d, 2d12h. 0 means never for ttl.

Sizes

max_file_size accepts a number of bytes (52428800) or a number with a unit: B, KB, MB, GB or TB, in any case, with an optional decimal part (1.5GB). Units are powers of 1024, so 1MB is 1048576 bytes.

Validation

hybrids3 checks the file at startup and exits with status 1 on the first problem, logging one JSON line that names it. Nothing is served until the file is valid. Troubleshooting lists every message with its fix.

Applying changes

hybrids3 reads the file only at startup. Restart the container after editing it. Removing a bucket from the file leaves its files and metadata in /data; see What lives in /data.