Configuration
enodia reads up to three files: enodia.yaml (required — your
service inventory), an optional separate credentials.yaml, and an
optional settings.yaml (personal display preferences, never
required). All three are plain YAML.
enodia.yaml
Section titled “enodia.yaml”Top level
Section titled “Top level”schemaVersion: 1credentials_file: credentials.yaml # optional, see belowdefaults: # optional timeout: 10s concurrency: 5 retries: 2 backoff: 500mscredentials: {} # optional, see "Credentials"targets: [] # your servicesschemaVersion is checked on read — a future version is refused with
advice to upgrade rather than parsed optimistically.
defaults
Section titled “defaults”Applies to every target unless overridden per-target.
| Field | Type | Meaning |
|---|---|---|
timeout |
duration | Per-request timeout (default: 10s if unset anywhere) |
concurrency |
int | How many targets are probed at once |
retries |
int | Retry count — only ErrUnreachable is retried; a rejected credential doesn’t improve on a second attempt |
backoff |
duration | Delay between retries |
Durations use Go’s duration syntax: 500ms, 10s, 2m, 1h30m.
targets
Section titled “targets”One entry per service:
targets: - id: jira-main # required, stable across renames - metrics and history key off this name: Jira (production) # optional, defaults to id product: jira # required - see Supported products address: https://jira.example.com # required credentials: jira-token # optional, name of an entry in credentials: timeout: 15s # optional, overrides defaults.timeout path: /rest/api/2/serverInfo # optional, product-specific - most probes have a sane default method: GET # optional headers: # optional, extra headers sent with every request X-Custom: value allow_insecure_transport: false # optional - see "HTTPS first" in Concepts tls: # optional, see "TLS" below ca_file: /etc/enodia/ca.pem options: # optional, product-specific key/value knobs key: value parser: # only for product: generic - see below type: regexaddress is written exactly as you’d type it — each probe parses it
itself. A bare host with no https:///http:// prefix is resolved
automatically (see Concepts),
or run enodia config resolve to see what scheme each target would use
without sending any credentials.
See Product setup in the sidebar (or the
Supported products table) for the exact endpoint, auth
requirements, and recorded fields for each of the 29 built-in probes —
path, credentials, and options above are the general shape; each
product’s own page says what it actually needs.
TLS (tls:)
Section titled “TLS (tls:)”Three levels, in descending order of correctness:
tls: ca_file: /etc/enodia/corp-ca.pem # a corporate CA bundle - most closed estates run their own PKI pin_sha256: # pinned leaf certificate fingerprint(s) - "AB:CD:...:EF" server_name: internal.example.com # SNI override min_version: "1.2" # TLS minimum version insecure: true # last resort - see belowinsecure: true warns on every run, not only at validation time,
because it has a habit of being added “temporarily” and living for
years. It also travels into the observation, so a report doubles as a
fleet-wide TLS audit — you can see which services are being checked
without verification.
Credentials
Section titled “Credentials”Named entries, referenced from a target’s credentials: field by name:
credentials: jira-token: kind: bearer value: "${JIRA_TOKEN}"
gitlab-token: kind: token-header header: PRIVATE-TOKEN value: "${GITLAB_TOKEN}"
vault-basic: kind: basic username: enodia password: "${VAULT_PASSWORD}"
redis-auth: kind: password password: "${REDIS_PASSWORD}"kind |
Fields used | Sends |
|---|---|---|
none (default if omitted) |
— | no credential |
bearer |
value |
Authorization: Bearer <value> |
token-header |
header, value |
a custom header, e.g. PRIVATE-TOKEN, X-Vault-Token |
basic |
username, password |
HTTP Basic auth |
password |
password |
protocol-native auth (Redis AUTH, a SQL connection’s own password, …) |
credentials_file
Section titled “credentials_file”A separate file, same shape as the inline credentials: map:
jira-token: kind: bearer value: "${JIRA_TOKEN}"schemaVersion: 1credentials_file: credentials.yamltargets: - id: jira-main product: jira address: https://jira.example.com credentials: jira-tokenThis is what lets a service inventory be committed to git while secrets
stay out of it entirely. Entries in credentials_file take precedence
over an inline entry of the same name. credentials_file resolves
relative to the config file that names it, not the current directory.
Environment variable interpolation
Section titled “Environment variable interpolation”Any string value in enodia.yaml or credentials.yaml can reference an
environment variable:
${VAR}— replaced with$VAR’s value; missing is an error.${VAR:-default}— replaced with$VAR’s value, ordefaultif unset.
The generic probe
Section titled “The generic probe”product: generic is the escape hatch for a target that will never get
a dedicated probe. Its vocabulary is deliberately small and frozen — no
conditionals, no loops, no chained requests, no templating. A target
needing any of that needs a real probe written in Go, not more generic
probe features.
targets: - id: in-house-api product: generic address: https://internal.example.com parser: type: regex # json | xml | header | plaintext | regex key: version # dotted path (json), tag/XPath-ish path (xml), or header name regex: 'v(\d+\.\d+\.\d+)' clean_regex: '^v' # first capture group wins - snake_case, see below line: 1 # plaintext only - which line to readFile locations
Section titled “File locations”Both enodia.yaml and settings.yaml are found the same way: an
explicit path (--config/--settings, or $ENODIA_CONFIG/
$ENODIA_SETTINGS for an exact file) always wins and must exist — a
typo is an error, never a silent fall-through to some other file. Absent
that, a search runs in order below; the first match wins outright,
nothing is merged from several found files. Location beats naming: a
match in the current directory always wins over one in
$XDG_CONFIG_HOME, which always wins over one in /etc/enodia/,
regardless of which name matched where.
enodia.yaml:
./enodia.yaml./enodia.yml./config.yaml./config.yml./.enodia.yaml./.enodia.yml./.config.yaml./.config.yml$XDG_CONFIG_HOME/enodia/enodia.yaml(~/.config/enodia/enodia.yamlif$XDG_CONFIG_HOMEis unset)$XDG_CONFIG_HOME/enodia/enodia.yml$XDG_CONFIG_HOME/enodia/config.yaml$XDG_CONFIG_HOME/enodia/config.yml/etc/enodia/enodia.yaml/etc/enodia/enodia.yml/etc/enodia/config.yaml/etc/enodia/config.yml
Finding nothing at all is an error — a config that can’t be found is
worth failing loudly over, since it usually means the wrong file (or
none) is about to be used. Run enodia config path to see which file
would actually be picked up.
settings.yaml — same idea, with a few differences: it also checks a
plain settings. name (not just enodia.settings.), it additionally
checks the directory the running executable lives in (not just the
current directory — see below), and finding nothing at all is not
an error — every field just falls back to its built-in default, since
this file is entirely optional:
./enodia.settings.yaml./enodia.settings.yml./settings.yaml./settings.yml./.enodia.settings.yaml./.enodia.settings.yml./.settings.yaml./.settings.yml<directory containing the running executable>/settings.yaml<same>/settings.yml$XDG_CONFIG_HOME/enodia/settings.yaml(~/.config/enodia/settings.yamlif$XDG_CONFIG_HOMEis unset)$XDG_CONFIG_HOME/enodia/settings.yml/etc/enodia/settings.yaml/etc/enodia/settings.yml
Step 9-10 is distinct from the current directory (steps 1-8): a portable
install (unzip anywhere, no package manager) runs from whatever
directory the operator happens to be standing in, which on Windows in
particular is essentially never the install directory itself
(install.ps1 defaults to %LOCALAPPDATA%\enodia, added to PATH — the
whole point of PATH is that the current directory stops mattering).
This step is deliberately limited to settings.yaml — it’s optional
display preferences, so a wrong or hijacked one in a shared install
directory is a cosmetic problem at worst. enodia.yaml carries
credentials and does not get an equivalent step.
settings.yaml
Section titled “settings.yaml”Personal, per-operator display preferences — never targets, never
credentials, never shared the way enodia.yaml usually is.
schemaVersion: 1
render: # compact (default) | lifecycle | drift | fleet default_view: fleet
export: # json (default) | prometheus | html - used whenever `export` itself # is run without --format default_format: html
html: # inline (default, fully offline) | cdn (loads Bootstrap/Bootswatch) assets: cdn
# none (no stylesheet at all) | default (plain Bootstrap) | any of # Bootswatch's 26 real themes: brite, cerulean, cosmo, cyborg, darkly, # flatly, journal, litera, lumen, lux, materia, minty, morph, pulse, # quartz, sandstone, simplex, sketchy, slate, solar, spacelab, # superhero, united, vapor, yeti, zephyr theme: lumen
# auto (default: races jsdelivr and cdnjs, uses whichever answers # first) | jsdelivr | cdnjs cdn: auto
# optional: restrict the export to one view instead of all four # view: fleetrender.default_view applies to check’s --view whenever the flag
itself wasn’t passed. export.default_format does the same for
export’s --format. html.* only matters for
export --format html — see Reporting for what each
field actually changes.