# Configuration Every option can be given on the command line, in configuration files, or both. Precedence, lowest first: 1. built-in defaults; 2. configuration files, in the order of `--config` (repeatable; later files win); 3. command-line arguments. An argument that replaces a value from a file is logged (info) with both values and the file. Imported values are never logged, only where they come from; text with placeholders is logged as it ends up. Secrets (`mycelium-rest-url`, which may carry credentials) are never logged, however they are given. `continuum --help` lists all options with their defaults. ## Durations and sizes Durations (`--keepalive`, `--dormant-probe-max`, `--document-append`, `--document-rewrite`, `--electorate-window`, `--clock-skew-warn`, and the API's `settle`, `switchDelay` and retention `age`) are a bare number of seconds (`30`, `0.5`) or components with units in descending order: `ms`, `s`, `m`, `h`, `d`, e.g. `500ms`, `500s`, `1h30m`, `1d2h3s`, `1.5h`. Precision is a millisecond; anything finer is an error. Sizes (`--blob-chunk`) are a bare number of bytes or a number with `B`, `KiB`, `MiB` or `GiB`, e.g. `64KiB`, `1.5MiB`; they must come to whole bytes. In configuration files both may also be numbers (seconds, bytes). What the node reports (stats, `/peers`, remake reports) stays numeric, with the unit in the name: `uptimeSecs`, `dormantMs`, `savedBytes`. Timestamps are Unix milliseconds, named `…At` or `…Until`. ## Files TOML (`.toml`) for people, JSON (`.json`) for generated configuration. Keys are the long option names. Nested tables join their keys with `-`, so these are the same: ```toml mycelium-peers = ["tls://203.0.113.5:9651"] [mycelium] peers = ["tls://203.0.113.5:9651"] ``` Unknown keys are an error. An example ([`example.toml`](example.toml) has every option, explained): ```toml include = ["/run/secrets/continuum.json"] bind-addr = "[::1]:3000" htpasswd = "/etc/continuum/htpasswd" node-key-file = "/var/lib/continuum/node.key" seeds = ["node1.example.org", "node2.example.org"] alias = { command = ["hostname", "-s"] } keepalive = "1m" neighbours = 12 [mycelium] enable = true key-file = "/var/lib/continuum/mycelium.key" peers = ["tls://203.0.113.5:9651", "quic://203.0.113.6:9651"] ``` The same as JSON, as a system like NixOS would generate it: ```json { "include": ["/run/secrets/continuum.json"], "bind-addr": "[::1]:3000", "htpasswd": "/etc/continuum/htpasswd", "node-key-file": "/var/lib/continuum/node.key", "seeds": ["node1.example.org", "node2.example.org"], "alias": { "command": ["hostname", "-s"] }, "mycelium": { "enable": true, "key-file": "/var/lib/continuum/mycelium.key", "peers": ["tls://203.0.113.5:9651"] } } ``` ### Includes `include` (a path or a list) loads other files first, in the order listed; an entry `{ path = "…", optional = true }` is skipped where the file is missing. Relative paths are relative to the including file. The including file's own values win over its includes, later includes over earlier ones (with a warning, since two includes setting the same option is usually a mistake). A cycle is an error. This keeps public settings in version control and secrets elsewhere: ```toml # continuum.toml, committed: the secrets, then local settings over them include = ["/run/secrets/continuum.toml", { path = "local.toml", optional = true }] seeds = ["node1.example.org"] ``` ## Transports A node uses every transport enabled: `--mycelium-enable`, `--libp2p-enable` and `--tor-enable`, each in builds with its cargo feature (`--features mycelium,libp2p`, none by default). None is on by default: a node needs one at least, and without, the error says which this build has. As each is its own option, a file that configures a transport can enable it too, and including it is all it takes: ```toml # continuum.toml include = ["libp2p.toml"] # libp2p.toml [libp2p] enable = true listen = ["/ip4/0.0.0.0/tcp/9661", "/ip4/0.0.0.0/udp/9661/quic-v1"] ``` `--transport-order` is their order of preference (`mycelium,libp2p,tor` by default), whether enabled or not; those it leaves out come after, in the default order. How a node uses several: [`transports.md`](transports.md), Several transports. Options of a transport the node doesn't use (not enabled), or this build doesn't have, are ignored, and the node says which at start (`Options of a transport this node doesn't use are ignored`, with the transport, whether it's built, and the options); a configuration shared between nodes may carry them on purpose. A transport's options are checked when the configuration is loaded if the node uses it (Mycelium's always, where it is built), so `--print-config` catches a wrong one too. What each transport is for and its options: [`transports.md`](transports.md). ## Unsetting and conflicting options A later source can set an option back to its default: `--unset OPTION` on the command line (repeatable), `unset = ["option", …]` in a file (overriding its includes and earlier files), or `null` for the option in a JSON file. Some options can't be combined: `mycelium-rest-url` (use a Mycelium daemon running elsewhere) excludes the options of a supervised daemon (`mycelium-key-file`, `mycelium-key-create`, `mycelium-network-key-file`, `mycelium-network-name`, `mycelium-tcp-listen-port`). When a later source sets one side, values for the other side from earlier sources are dropped (and logged), so `--mycelium-rest-url` on the command line just works with a file that configures a supervised daemon. Setting both sides in the same source is an error. Other combinations contradict each other and are an error wherever their values come from: `genesis` with `seeds` (a new swarm has nobody to join) or with `recover-from`. To start a node with `--genesis` whose configuration file lists seeds, unset them: `--genesis --unset seeds`. ## Forcing Some checks refuse to start the node because something looks wrong, but can be overridden when you know better: `--force` lists them by name, or is `true` for all. An unknown name is an error. The API's `?force=` parameters use the same format. `--force` is accepted on the command line only: it is meant for the one start it was given for, and in a configuration file it would apply to every start. | Name | Check | |---|---| | `swarmId` | the document to start on (`--recover-from`, `--document-file`) is of another swarm than the state file remembers; with it, the document's swarm wins | | `badDocumentFile` | the document file can't be read; with it, it is moved aside and the node starts without it | | `replaceDocumentFile` | `--recover-from` while the document file holds a document; with it, the backup wins | Names are camelCase everywhere, on the command line too, like the API's (`switchDelay`, `supersede`, `alive`). ## Importing values A value can be taken from elsewhere instead of written out: | In a file | On the command line | Value | |---|---|---| | `{ env = "NAME" }` | `env:NAME` | environment variable | | `{ file = "PATH" }` | `file:PATH` | file contents | | `{ command = "COMMAND" }` | `cmd:COMMAND` | output of `sh -c COMMAND` | | `{ command = ["prog", "arg"] }` | | output of the program, no shell | Commands run as the node's user, at startup: whoever can write the configuration can run them ([`trust.md`](trust.md)). The content is text with trailing line breaks removed, read like a command-line value: numbers for numeric options, `true`/`false` for switches, comma- or line-separated items for lists. With `format = "json"` in a file, or `+json` on the command line (`env+json:SEEDS`, `file+json:PATH`, `cmd+json:COMMAND`), it is parsed as JSON instead (e.g. a list as `["a", "b"]`). In files, relative paths are relative to the file, and commands run in its directory. Any other text value can mix fixed text with imported values: each `${env:NAME}`, `${file:PATH}` or `${cmd:COMMAND}` in it is replaced by that content, as text (no `+json` in a placeholder). `$$` is a `$`, and any other `$` outside a placeholder is an error (a shell-style `$NAME` would otherwise silently stay as it is). A placeholder ends at the `}` that matches its `{`: braces inside it balance, and in a command, braces in shell quotes (`'...'`, `"..."`) or after a backslash don't count, so a command may hold `$`, quotes and braces of its own. Placeholders don't nest. `literal:` on the command line turns this off too. ```sh continuum --alias 'node-${env:HOSTNAME}' ``` ```toml alias = "${env:SITE}-${cmd:hostname -s}" # A command with both kinds of quotes: a TOML literal string ('''...''') needs no escapes. libp2p-listen = ['''/ip6/${cmd:ip -j addr show wireguard | jq -r '.[].addr_info[]|select(.family=="inet6" and .scope=="global").local'}/tcp/9661'''] ``` A command that prints several lines (above: several addresses) doesn't give one item per line: as a list element the text is one item, line breaks and all, and as a whole list value it is split at commas and line breaks, the fixed text going with the first and last item only. Make it print one (`| head -n 1`). List elements can be imported one by one: ```toml seeds = ["node1.example.org", { env = "EXTRA_SEED" }] ``` On the command line, `literal:` passes a value that happens to start with one of the prefixes: `--alias literal:env:prod`. ```sh continuum --config /etc/continuum.toml --alias env:HOSTNAME --seeds cmd+json:'my-inventory --seeds' ``` Imports are read once, at start. ## Checking the configuration `--print-config` prints the effective configuration as JSON and exits: every option with its value and where it came from (`default`, `file` with the file, or `argument`; `unset` if it was set back to its default there). Imported values are left out and their importers listed instead (`imported`), and secrets are left out however they were given (`secret`), so the output can be shared. Text with placeholders is shown as it ends up, with the text as written under `templates`: keep secrets of other options out of placeholders, and import them whole instead. A running node answers the same at `GET /admin/config`; with `?values=original`, text with placeholders is shown as written instead. ```sh continuum --config /etc/continuum.toml --print-config | jq .options.seeds ```