# Configuration > Status: the loader in `src/volumen/config.py` is the source of truth. This > document lists every key it understands, with type, default, and meaning. volumen is configured by a single **TOML** file. By default it lives at `/etc/volumen/config.toml` and is auto-generated on first start. CLI flags passed to `volumen serve` override the file. A template you can copy as a starting point is at [`config.toml.example`](../config.toml.example) in the repository root. The template ships with development defaults (`host = "::"`, `env = "development"`, `cookie_secure = false`) — flip them for production. ## Example `config.toml` ```toml [server] host = "::1" port = 9090 env = "production" trust_proxy = true content_dir = "/var/lib/volumen/posts" users_file = "/var/lib/volumen/users.toml" [site] title = "My Blog" description = "A blog powered by volumen." base_url = "https://example.com" language = "en" author = "Anonymous" fediverse_creator = "@you@example.social" [admin] password_hash = "" session_key = "" session_ttl = 86400 min_password_length = 10 max_password_length = 1024 max_upload_bytes = 10485760 # 10 MB cookie_secure = true ``` ## Key reference ### `[server]` | Key | Type | Default | Description | |----------------|---------|---------------|-------------| | `host` | string | `"::"` | Bind address. `"::"` listens on IPv6 with automatic IPv4 fallback; use `"::1"` (or `"127.0.0.1"`) when running behind a reverse proxy. | | `port` | integer | `9090` | TCP port the Uvicorn worker binds to. | | `env` | string | `"development"` | Runtime environment. `"production"` enables strict startup safety checks (refuses to boot with an empty `admin.password_hash`, warns on a short `admin.session_key`, enforces `cookie_secure`); `"development"` is more forgiving for local runs. | | `trust_proxy` | boolean | `false` | When `true`, honour the `X-Forwarded-Proto` header set by an upstream reverse proxy (nginx). Set `true` ONLY when running behind a trusted proxy that strips client-supplied values; otherwise an attacker could fake `https://` and force `Secure` cookies. | | `cookie_secure`| boolean | `false` | Mark session cookies as `Secure` (browser only sends them over HTTPS). Default `false` so local HTTP development works without TLS; set to `true` in production behind HTTPS. The runtime also auto-promotes cookies to `Secure` when `[server].trust_proxy = true` and `X-Forwarded-Proto: https` is observed. | ### Top-level | Key | Type | Default | Description | |----------------|---------|----------------------------------|-------------| | `content_dir` | string | `"/var/lib/volumen/posts"` | Directory of `.md` files with `+++` TOML frontmatter. | | `users_file` | string | `"/var/lib/volumen/users.toml"` | File storing admin users (managed from the admin Settings page). | ### `[site]` | Key | Type | Default | Description | |---------------------|-----------------|--------------------------|-------------| | `title` | string | `"My Blog"` | Exposed as `site.title`. | | `description` | string | `"A blog powered by volumen."` | Exposed as `site.description`. | | `base_url` | string | `"https://example.com"` | Used to build absolute URLs in the RSS feed, JSON feed, sitemap, and the public API. | | `language` | string | `"en"` | Default language for posts and the admin UI. | | `author` | string | `"Anonymous"` | Default author when a post frontmatter omits it. | | `fediverse_creator` | string \| null | `null` | Site-wide fediverse handle (e.g. `@user@instance.tld`). Exposed as `site.fediverse_creator` and rendered as `` in the RSS feed and `authors[].name` in the JSON feed. Per-post frontmatter overrides it. | ### `[admin]` | Key | Type | Default | Description | |-----------------------|---------|-----------|-------------| | `password_hash` | string | `""` | Bootstrap admin login: paste a hash from `volumen hash-password` to sign in as user `admin`. Once you create users from the Settings page, `users_file` wins. | | `session_key` | string | `""` | Secret used to sign session cookies. Must be `>= 64` bytes; empty value = a random secret per start (sessions reset on restart, do not use in production). | | `session_ttl` | integer | `86400` | Session lifetime in seconds (default 24h). `0` or negative = no expiry until the browser session ends. | | `min_password_length` | integer | `10` | Minimum length required for admin-chosen passwords on the Settings page. Must be `>= 8`; the bootstrap hash is not affected. | | `max_password_length` | integer | `1024` | Maximum length for admin-chosen passwords (cap to avoid scrypt abuse; scrypt is CPU-bound by design). | | `max_upload_bytes` | integer | `10485760` | Maximum upload size in bytes (default 10 MB). Uploads larger than this are rejected with HTTP 413. | | `cookie_secure` | boolean | `false` | Mark session cookies as `Secure` (browser only sends them over HTTPS). Default `false` so local HTTP development works without TLS; set to `true` in production behind HTTPS. The runtime also auto-promotes cookies to `Secure` when `[server].trust_proxy = true` and `X-Forwarded-Proto: https` is observed. | ## CLI overrides ```bash volumen serve --config /etc/volumen/config.toml \ --content ./posts \ --host 127.0.0.1 \ --port 9000 ``` ## Why TOML - **First-class dates** — `date = 2026-01-15` is a real date, not a string. - **Explicit typing** — no YAML-style implicit coercion (`no` → false, etc.). - **No whitespace pitfalls** — indentation is not significant. The same format is used for post frontmatter; see the post format section in the project [`README.md`](../README.md). The Python standard library `tomllib` (3.11+) parses the file at load time; no extra TOML dependency is required at runtime. `tomli-w` is bundled for the admin to round-trip TOML frontmatter on post edits.