# maglevd Configuration Guide ## Overview `maglevd` consumes a YAML configuration file of a specific format. Validation is performed in two stages: 1. **Structural parsing**: the YAML is unmarshalled into typed Go structs. Unknown fields and type mismatches are rejected immediately. 1. **Semantic validation**: cross-field and cross-object rules are enforced, for example ensuring that every backend referenced by a frontend exists, that address families are consistent within a frontend, and that IP source addresses are the correct family. If you want to get started quickly, take a look at the [example config](#example). ## Basic structure The YAML configuration file has the following top-level structure: ```yaml maglev: healthchecker: [ Global health checker settings ] healthchecks: my-check: [ Health check definition ] backends: my-backend: [ Backend definition ] frontends: my-frontend: [ Frontend (VIP) definition ] ``` All four sections live under the top-level `maglev:` key. The `healthchecks`, `backends`, and `frontends` sections are maps keyed by an arbitrary name of your choosing. Names must be unique within their section and are case-sensitive. --- ## healthchecker Global settings for the health checker engine. * ***transition-history***: An integer >= 1 that controls how many state transitions are retained per backend for display via the gRPC API. Defaults to `5`. * ***netns***: The name of a Linux network namespace in which probes are executed. When empty or omitted, probes run in the current (default) network namespace. Useful when backends are reachable only through a dedicated dataplane namespace. Example: ```yaml maglev: healthchecker: transition-history: 10 netns: dataplane ``` --- ## healthchecks A named map of health check definitions. Each health check describes *how* to probe a backend. Backends reference health checks by name. The same health check can be reused across any number of backends; each backend is probed exactly once regardless of how many frontends reference it. Common fields (all types): * ***type***: Required. One of `icmp`, `tcp`, `http`, or `https`. * ***port***: The destination port to probe. Required for `tcp`, `http`, and `https`. Must be omitted for `icmp`. * ***probe-ipv4-src***: An optional IPv4 source address used when probing IPv4 backends. Must be an IPv4 address. When omitted, the OS chooses the source address. * ***probe-ipv6-src***: An optional IPv6 source address used when probing IPv6 backends. Must be an IPv6 address. When omitted, the OS chooses the source address. * ***interval***: Required. A positive Go duration string (e.g. `2s`, `500ms`) controlling how often a probe is sent when the backend is fully healthy (counter at maximum). * ***fast-interval***: Optional. A positive duration used instead of `interval` while the backend's health counter is degraded (between down and up) or in `unknown` state. When omitted, `interval` is used. * ***down-interval***: Optional. A positive duration used instead of `interval` while the backend is fully down (counter at zero). When omitted, `interval` is used. Setting this to a longer value reduces probe traffic to backends that are known to be offline. * ***timeout***: Required. A positive duration after which an in-flight probe is abandoned and counted as a failure. * ***rise***: The number of consecutive successes required to transition from down to up. Defaults to `2`. Must be >= 1. * ***fall***: The number of consecutive failures required to transition from up to down. Defaults to `3`. Must be >= 1. ### type: icmp Sends an ICMP echo request (ping) to the backend address. Requires `CAP_NET_RAW`. No `port` may be specified. No `params` block is used. ```yaml healthchecks: ping: type: icmp probe-ipv4-src: 10.0.0.1 probe-ipv6-src: 2001:db8::1 interval: 2s timeout: 1s rise: 2 fall: 3 ``` ### type: tcp Opens a TCP connection to the backend and immediately closes it upon success. Use `params` to optionally wrap the connection in TLS. * ***params.ssl***: A boolean. When `true`, a TLS handshake is performed after the TCP connection is established. Defaults to `false`. * ***params.server-name***: The TLS SNI hostname sent during the handshake. When omitted, the backend IP address is used. * ***params.insecure-skip-verify***: A boolean. When `true`, the TLS certificate presented by the server is not verified. Defaults to `false`. ```yaml healthchecks: imaps-check: type: tcp port: 993 params: ssl: true server-name: imaps.example.com interval: 5s timeout: 3s rise: 2 fall: 3 ``` ### type: http / https Opens a TCP (or TLS for `https`) connection, sends an HTTP request, and evaluates the response code. An optional regexp can additionally match against the response body. * ***params.path***: Required. The HTTP request path, e.g. `/healthz`. * ***params.host***: The `Host` header value sent in the request. When omitted, the backend IP address is used. * ***params.response-code***: The expected HTTP response code. Can be a single value (`"200"`) or an inclusive range (`"200-299"`). Defaults to `"200"`. * ***params.response-regexp***: An optional Go regular expression matched against the response body. If specified, the body must match for the probe to succeed. * ***params.server-name***: The TLS SNI hostname (`https` only). Defaults to the value of `params.host` if not set. * ***params.insecure-skip-verify***: A boolean. Skip TLS certificate verification (`https` only). Defaults to `false`. ```yaml healthchecks: nginx-http: type: http port: 80 params: path: /healthz host: nginx.example.com response-code: "200-204" interval: 2s fast-interval: 500ms down-interval: 30s timeout: 3s rise: 2 fall: 3 nginx-https: type: https port: 443 params: path: /healthz host: nginx.example.com server-name: nginx.example.com insecure-skip-verify: false interval: 5s timeout: 3s ``` --- ## backends A named map of individual backend servers. Each backend has a single IP address and optionally references a health check by name. Backends are probed exactly once, even if they appear in multiple frontends. * ***address***: Required. The IPv4 or IPv6 address of this backend server. * ***healthcheck***: The name of a health check defined in the `healthchecks` section. When empty or omitted, no probing is performed and the backend is assumed permanently healthy. This is useful for backends that are always available or managed by other means. * ***enabled***: A boolean controlling whether this backend participates in any frontend. When `false`, the backend is excluded entirely and no probe goroutine is started. Defaults to `true`. Examples: ```yaml backends: nginx0-ams: address: 198.51.100.10 healthcheck: nginx-http nginx0-lon: address: 198.51.100.11 healthcheck: nginx-http nginx0-draining: address: 198.51.100.12 healthcheck: nginx-http enabled: false static-backend: address: 198.51.100.20 # no healthcheck: assumed always healthy ``` --- ## frontends A named map of virtual IPs (VIPs). Each frontend ties together a listener address with an ordered list of backend pools. The gRPC API exposes frontends by name. * ***description***: An optional free-text string for documentation purposes. * ***address***: Required. The IPv4 or IPv6 address of the VIP. * ***protocol***: The IP protocol, either `tcp` or `udp`. When omitted, the frontend matches all traffic to the VIP address regardless of protocol. If `port` is specified, `protocol` must also be set. * ***port***: The destination port of the VIP, an integer between 1 and 65535. Requires `protocol` to be set. When omitted, the frontend matches all ports. Note that the frontend port is independent of the healthcheck port: a frontend on port 443 may use a healthcheck that probes port 80. * ***pools***: Required. A non-empty ordered list of pool objects. Pools express priority: the first pool is preferred; subsequent pools act as fallbacks. All backends across all pools in a frontend must have addresses of the same address family (all IPv4 or all IPv6). Each pool has: * ***name***: Required. A non-empty string identifying the pool (e.g. `primary`, `fallback`). * ***backends***: A map of backend names to per-pool backend options. Every name must refer to an existing entry in the `backends` section. Per-pool backend options: * ***weight***: An integer between 0 and 100 (inclusive) expressing the relative weight of this backend within the pool. `0` keeps the backend in the pool but assigns it no traffic. Defaults to `100`. Weight is per-pool, not global — the same backend can appear with different weights in different frontends. Examples: ```yaml frontends: nginx-v4-http: description: "IPv4 HTTP VIP with fallback" address: 198.51.100.1 protocol: tcp port: 80 pools: - name: primary backends: nginx0-ams: { weight: 10 } nginx0-lon: {} - name: fallback backends: nginx0-fra: {} maildrop-imaps: description: "IMAPS VIP" address: 2001:db8::1 protocol: tcp port: 993 pools: - name: primary backends: maildrop0-ams: {} maildrop0-lon: {} ``` --- ## Example A complete configuration tying all sections together: ```yaml maglev: healthchecker: transition-history: 5 netns: dataplane healthchecks: nginx: type: http port: 80 params: path: /healthz host: nginx.example.com response-code: "200" interval: 2s fast-interval: 500ms down-interval: 30s timeout: 3s rise: 2 fall: 3 dovecot: type: tcp port: 993 params: ssl: true server-name: imaps.example.com interval: 5s fast-interval: 1s down-interval: 30s timeout: 3s rise: 2 fall: 3 ping6: type: icmp probe-ipv6-src: 2001:db8:probe::1 interval: 2s timeout: 1s backends: nginx0-ams: address: 198.51.100.10 healthcheck: nginx nginx0-lon: address: 198.51.100.11 healthcheck: nginx nginx0-fra: address: 198.51.100.12 healthcheck: nginx maildrop0-ams: address: 2001:db8:1::10 healthcheck: dovecot maildrop0-lon: address: 2001:db8:1::11 healthcheck: dovecot frontends: nginx-http: description: "HTTP VIP with fallback" address: 198.51.100.1 protocol: tcp port: 80 pools: - name: primary backends: nginx0-ams: { weight: 10 } nginx0-lon: {} - name: fallback backends: nginx0-fra: {} nginx-https: description: "HTTPS VIP — same backends, different port" address: 198.51.100.1 protocol: tcp port: 443 pools: - name: primary backends: nginx0-ams: { weight: 10 } nginx0-lon: {} - name: fallback backends: nginx0-fra: {} maildrop-imaps: description: "IMAPS VIP" address: 2001:db8::1 protocol: tcp port: 993 pools: - name: primary backends: maildrop0-ams: {} maildrop0-lon: {} ``` --- For a detailed description of the health state machine, probe intervals, and all transition events, see [healthchecks.md](healthchecks.md).