ductus.yaml
ductus.yaml: the project's settings, for every interface in it and the engine that runs them: how long messages are kept, the REST API and web UI, how people sign in, the audit log, alerts, and the engine's own connection checks.
The file sits at the top of the project and is optional: every setting has a default, which ductus init writes out for the main ones. Only alerts: may use the environment's ${NAME} and ${secret:NAME}; everything else is read as written.
Schema for editors: docs/schema/ductus.json (written into a project by ductus types). Files: ductus.yaml.
ports
Type: settings, below
The port ranges ductus new interface picks a free port from for a new interface's listener (each interface's own port is in its interface.yaml). Set them to the ranges your firewall team opened, so new interfaces land inside. Default: MLLP 6661-6699, HTTP 8080-8099. Example: ports: { mllp: 7000-7099 }.
ports.mllp
Type: port range (6661-6699)
The range a new MLLP interface's port is picked from, as first-last. Default: 6661-6699. Example: mllp: 7000-7099.
ports.http
Type: port range (6661-6699)
The range a new HTTP interface's port is picked from, as first-last (HTTP interfaces can also share one port). Default: 8080-8099. Example: http: 9080-9099.
isolates
Type: settings, below
Limits of the JavaScript engine that runs interface code (heap_mb). Default: heap_mb: 512.
isolates.heap_mb
Type: number
The memory limit, in MB, of each isolate: one copy of the JavaScript engine (V8) that runs interface code. At least 64.
Every thread of the shared pool has an isolate (one thread per CPU core, or --threads), and so does every worker of an isolation: dedicated interface, so the code can use up to about heap_mb × (threads + dedicated workers) in all: size the server with that. Code that fills its isolate is stopped, its message quarantined and its interface stopped until a restart; the engine and every other interface keep running. In the shared pool the limit is shared by every interface on the thread, so the one that runs out isn't always the one that filled it (a cache in another interface that only grows).
Raise it for code that holds a lot on purpose (a large lookup table loaded once), or give that interface isolation: dedicated; lower it on a small server with many cores. Default: 512. Example: isolates: { heap_mb: 1024 }.
require_about
Type: true or false
Make ductus validate fail (not only warn) when an interface doesn't name the application or vendor on each side in about:, so ductus impact never misses one. Turn it on once the existing interfaces are documented, and every new one must be. Default: false. Example: require_about: true.
api
Type: settings, below
The REST API and the web UI: where they listen, HTTPS, and who may connect. Default: 127.0.0.1:7700, plain HTTP, this machine only.
api.listen
Type: text
Where the REST API and the web UI listen, as host:port, or off to run without them (then ductus status --token, drain, pause and the web UI can't reach this engine).
The default listens on this machine only, so opening it to the network is a choice you make. For people to use the web UI from their own computers, listen on the server's address (or 0.0.0.0 for all of them) and add tls (the UI's sign-in needs HTTPS anywhere but on the server itself) and allow. Every call needs a token or a signed-in person either way. ductus run --api-listen (or DUCTUS_API_LISTEN) overrides it for one engine. Default: 127.0.0.1:7700. Example: listen: 0.0.0.0:7700.
api.tls
Type: settings, below
HTTPS only, presenting the certificate named here (a certificates: entry in resources.yaml); with clients, callers must present a certificate too. Needed for the web UI anywhere but on the server itself (its sign-in cookie is only sent over HTTPS), and for tokens not to cross the network readable; the start warns without it when listen isn't this machine only. Default: plain HTTP. Example: tls: { certificate: ductus-api }.
api.tls.certificate
Type: text · Required
The certificate this listener presents: a certificates: entry in resources.yaml with the certificate and its key, for the name senders connect to. A certificate the engine can't use (expired, its key doesn't match) stops the start with the reason; renewed files are picked up within a minute, without a restart. Required. Example: certificate: ductus-mllp.
api.tls.clients
Type: settings, below
Ask senders for a certificate of their own, and refuse any connection without one that ca issued and, with subjects, that names an allowed system. A client certificate says which system is connecting, beside allow:'s where from. Default: no client certificates asked for. Example: clients: { ca: hospital-ca, subjects: ["CN=*.lab.hospital.org"] }.
api.tls.clients.ca
Type: text · Required
The CA that issues senders' certificates: a certificates: entry holding the CA's certificate (ca or ca_file). Only certificates it issued are taken. Required. Example: ca: hospital-ca.
api.tls.clients.subjects
Type: list of text
Which of that CA's certificates are taken: a certificate matching any one pattern. A pattern is ATTR=value parts separated by commas, all of which must match, with * and ? wildcards and case ignored: CN, O, OU, C, L, ST, DC, or DNS for the certificate's DNS names. Needed when the CA issues certificates to more than your senders (a hospital-wide CA). Default: any certificate the CA issued. Example: subjects: ["CN=bridges*.hospital.org", "O=Quest, OU=Lab"].
api.allow
Type: list of text
Who may connect: addresses, subnets and host names (the operators' and developers' networks, the monitoring server). Anyone else is disconnected before anything is read. List 127.0.0.1 too, or commands run on the server itself (ductus status --token, drain) are refused. Default: anyone who can reach listen. Example: allow: [127.0.0.1, 10.1.50.0/24].
retention
Type: 1w, 3w or 7w
How long messages are kept, for every interface whose interface.yaml has no retention: 1w, 3w or 7w (or the same in days: 7d, 21d, 49d).
Only these three, on purpose: each is a set of partitions of the message tables, and old messages go by dropping a whole partition at once, which costs nothing however busy the feed (deleting rows one by one would slow the busiest tables). A message is kept at least its window and is gone within a day (1w) or a week (3w, 7w) after it. Messages still waiting for a destination, and quarantined ones (see quarantined), are never deleted: past the window they move to the held area until they're delivered or resolved.
Pick the window that covers how far back you look into problems; longer history belongs in the source system or an archive. Shortening it later deletes messages, so it waits for ductus retention confirm <interface>. Default: 7w. Example: retention: 3w.
quarantined
Type: keep, purge
What happens to quarantined messages once the retention window has passed, for every interface whose interface.yaml doesn't say: keep them in the held area until someone resends, corrects or dismisses them, or purge them with the rest.
In most engines unresolved quarantines pile up for years; here they're kept until a person decides, with no second time limit. Watch them with ductus retention and the ductus_held_messages metric. purge suits feeds whose senders resend anyway. Default: keep. Example: quarantined: purge.
auth
Type: settings, below
How people sign in to the web UI and the API: sessions, passwords, lockout, API tokens, and a directory (Active Directory, OpenLDAP). Local accounts are made with ductus user on the server. Default: local accounts and tokens, with the session and password rules below.
auth.session
Type: settings, below
How long a browser session lasts: idle (unused) and max (in all). Default: 12 hours idle, 7 days at most.
auth.session.idle
Type: duration
A session ends after this long unused, and the person signs in again: a shift, with room to spare, so an analyst isn't signed out mid-task. Shorten it where screens are shared or left unlocked. No longer than max. Default: 12h. Example: idle: 30m.
auth.session.max
Type: duration
A session ends this long after sign-in however much it's used, so a stolen session cookie doesn't last forever. Default: 7d. Example: max: 1d.
auth.password
Type: settings, below
What a local account's password must be (min_length). Directory accounts follow the directory's rules. Default: at least 12 characters.
auth.password.min_length
Type: number
The shortest password a local account may have, at least 8. Length matters more than mixing kinds of characters, so there's no rule for those (a few ordinary words together work well); a password can't contain the username, be one character repeated, or be one of the most common ones. Applies to new passwords; existing ones keep working. Default: 12. Example: min_length: 16.
auth.lockout
Type: settings, below
How many wrong passwords lock a username, and for how long. Default: 5 within 15 minutes lock it for 15 minutes.
auth.lockout.attempts
Type: number
How many wrong passwords for one username, within window, lock it, at least 1. It slows anyone guessing; a person who forgot waits for, or an admin unlocks them (ductus user unlock). Directory accounts count here and in the directory. Default: 5. Example: attempts: 10.
auth.lockout.window
Type: duration
How far back wrong passwords are counted. Default: 15m. Example: window: 1h.
auth.lockout.for
Type: duration
How long a locked username stays locked. Default: 15m. Example: for: 30m.
auth.token_sign_in
Type: true or false
Whether the sign-in page also takes an API token instead of a username and password: how the first people get in before accounts exist. Turn it off once everyone has an account; ductus user on the server always works. Default: true. Example: token_sign_in: false.
auth.user_tokens
Type: true or false
Whether people may make API tokens of their own (for scripts, under Account in the web UI). A person's token can do no more than they can, and stops when their account is disabled. Turn it off to keep tokens to the ones admins make. Default: true. Example: user_tokens: false.
auth.ldap
Type: settings, below
Sign-in with a directory (Active Directory, OpenLDAP), beside local accounts: which ldap: entry in resources.yaml, where people are, and which groups give which role. People in none of the groups can't sign in. Default: local accounts only. Example: ldap: { resource: corp-ad, user_base: "OU=Staff,DC=hospital,DC=org", groups: { admin: "CN=Ductus Admins,OU=Groups,DC=hospital,DC=org" } }.
auth.ldap.resource
Type: text · Required
The directory to use: the name of an ldap: entry in resources.yaml (its address, TLS and service account). Required. Example: resource: corp-ad.
auth.ldap.user_base
Type: text · Required
Where people are searched for, as a DN: the whole subtree under it. Narrow it to the branch your staff are in, so service accounts and contacts can't sign in by accident. Required. Example: user_base: "OU=Staff,DC=hospital,DC=org".
auth.ldap.user_filter
Type: text
How a person is found from the name they type: an LDAP filter where {username} stands for it, escaped so it can't change the filter. More than one entry found is refused. (sAMAccountName={username}) is Active Directory's sign-in name; OpenLDAP and FreeIPA use (uid={username}); (|(sAMAccountName={username})(mail={username})) takes either. Default: (sAMAccountName={username}). Example: user_filter: "(uid={username})".
auth.ldap.attributes
Type: settings, below
Which of the person's attributes hold their name, email, sign-in name and lasting id. The defaults suit Active Directory. Default: displayName, mail, the filter's attribute, and auto for the id.
auth.ldap.attributes.display_name
Type: text
The attribute with the person's name as others see it in the web UI and the audit log. Default: displayName. Example: display_name: cn.
auth.ldap.attributes.email
Type: text
The attribute with the person's email address: shown in the web UI, matched against owner texts (about.owner: anna@hospital.org), and used to find owners in the directory before their first sign-in. Default: mail. Example: email: userPrincipalName.
auth.ldap.attributes.username
Type: text
The attribute with the sign-in name, so a refresh notices it change and renames the account. Needed only when user_filter doesn't match {username} against one attribute plainly (ductus validate warns then). Default: the attribute the filter first matches {username} against (sAMAccountName for the default filter). Example: username: uid.
auth.ldap.attributes.id
Type: text
The attribute that tells one person from another through any rename: auto (Active Directory's objectGUID, else the standard entryUUID), another attribute's name (nsUniqueId), or none. With an id, a renamed person keeps their account, and a sign-in name given to someone new gets a new account instead of the old one's role and history. none matches by sign-in name only, so those two can't be told apart (validate warns). Default: auto. Example: id: nsUniqueId.
auth.ldap.groups
Type: settings, below · Required
Which directory groups give which role (admin, operator, viewer) and which add a permission (permissions.payloads, permissions.audit). The highest role a person's groups give wins; a person in none can't sign in. At least one role group. Required. Example: groups: { operator: "CN=Interface Team,OU=Groups,DC=hospital,DC=org" }.
auth.ldap.groups.admin
Type: text, or a list
The group (a DN), or groups, whose members are admins: everything operators can do, plus accounts, tokens and every permission. Write several one per line in a YAML list, not as [a, b] (DNs have commas). Default: none. Example: admin: "CN=Ductus Admins,OU=Groups,DC=hospital,DC=org".
auth.ldap.groups.operator
Type: text, or a list
The group or groups whose members are operators: what viewers can do, plus resend, edit, dismiss, pause, drain and run connection checks. Default: none. Example: operator: "CN=Interface Team,OU=Groups,DC=hospital,DC=org".
auth.ldap.groups.viewer
Type: text, or a list
The group or groups whose members are viewers: they see interfaces, health, queues and messages' details, but change nothing (and see payloads only with payloads). Default: none. Example: viewer: "CN=Help Desk,OU=Groups,DC=hospital,DC=org".
auth.ldap.groups.permissions
Type: settings, below
Groups that add a permission on top of the role: payloads (read message contents, usually patient data) and audit (read the audit log). Admins have both anyway. Default: none.
auth.ldap.groups.permissions.payloads
Type: text, or a list
The group or groups whose members may read message payloads (and edit them, as operators): the people who need to see patient data to do their work. Every read is in the audit log. Default: none. Example: payloads: "CN=Ductus PHI,OU=Groups,DC=hospital,DC=org".
auth.ldap.groups.permissions.audit
Type: text, or a list
The group or groups whose members may read and export the audit log: compliance and security staff. Default: none. Example: audit: "CN=Ductus Auditors,OU=Groups,DC=hospital,DC=org".
auth.ldap.nested
Type: true or false
Count members of groups inside the configured groups too (a department group placed in "Ductus Operators"). Active Directory answers this itself; other directories are walked group by group, at most 8 levels deep. Default: false (direct members only). Example: nested: true.
auth.ldap.group_base
Type: text
Where groups are searched for when nested groups are walked (not Active Directory, which answers by itself), as a DN. Default: the directory's own top (its naming context). Example: group_base: "ou=groups,dc=example,dc=org".
auth.ldap.refresh
Type: duration
How often the engine asks the directory again about everyone with a session or a token, and about directory people who own something (at least 1m). Someone removed from the groups, disabled or deleted there loses access within this long, sessions and tokens alike; a renamed person keeps their account. Shorter means quicker revocation and more directory searches. Default: 15m. Example: refresh: 5m.
audit
Type: settings, below
The audit log of who did what (sign-ins, resends, edits, pauses, account changes, payload reads): how long it's kept and whether reading a message's payload is logged. Default: kept 6 years, payload reads logged.
audit.keep
Type: duration (or years: 6y)
How long audit rows, and the record of what was done to messages, are kept: at least a year, in years (6y, 365 days each) or any duration (2190d). Older rows are deleted hourly. Six years is the usual HIPAA documentation period; ask your compliance office for yours. The log is the record of who did what, so it can't be shorter than a year. Default: 6y. Example: keep: 7y.
audit.payload_reads
Type: true or false
Log who reads a message's payload (in the web UI or through the API), before it's shown: with patient data, who looked matters as much as who changed. Turn it off only where messages hold no personal data. Reading needs the payloads permission either way. Default: true. Example: payload_reads: false.
audit.payload_read_window
Type: duration
One person reading the same message again within this long counts as one read, one row (a page that reloads itself would otherwise write a row each time). 0s writes a row for every read. Default: 10m. Example: payload_read_window: 0s.
alerts
Type: settings, below
Where notifications go and when: a mail server, channels (email lists, chat webhooks), and rules saying which health states alert, how badly and to whom. The engine judges every interface and destination every 15 seconds and tells people once, then reminds, and says when it's fine again.
The only section that may use ${NAME} and ${secret:NAME}, read for the environment the engine runs in (webhook URLs and mail passwords are secrets). Default: no alerts (states show in the web UI only). Example: alerts: { channels: { oncall: { email: oncall@hospital.org } }, rules: [{ when: [error, stalled], severity: critical, to: [oncall] }] }.
alerts.smtp
Type: settings, below
The mail server that email channels (and owners' email) go through. Needed only for email; webhooks need none. Default: none. Example: smtp: { host: smtp.hospital.org, from: ductus@hospital.org }.
alerts.smtp.host
Type: text · Required
The mail server's host name: your organization's relay or submission server. Its certificate must be for this name. Required. Example: host: smtp.hospital.org.
alerts.smtp.port
Type: number
The mail server's port. Default: 587 with tls: starttls, 465 with tls: tls, 25 with tls: none. Example: port: 2525.
alerts.smtp.tls
Type: starttls, tls, none
How the connection is protected:
starttls: a plain connection turned into TLS before anything else (submission, port 587); refused if the server can't.tls: TLS from the first byte (port 465).none: no encryption, for a relay on this machine or its network segment only; mail and any password cross readable.
Default: starttls. Example: tls: tls.
alerts.smtp.username
Type: text
The account to log in as, when the server asks for one (most submission servers do; an internal relay often doesn't). Goes with password. Default: none (no login). Example: username: ductus@hospital.org.
alerts.smtp.password
Type: text
The account's password, from a secret (${secret:SMTP_PASSWORD}). Goes with username. Example: password: "${secret:SMTP_PASSWORD}".
alerts.smtp.from
Type: text · Required
The address notifications come from. Use one your mail server lets this account send as, and that recipients' filters let through (ask the mail team to add it to their allow list). Required. Example: from: ductus@hospital.org.
alerts.smtp.ca
Type: text
A CA to trust for the mail server besides the ones this server trusts (a certificates: entry in resources.yaml), for an internal relay with a private CA's certificate. Not with tls: none. Default: the system's trusted CAs only. Example: ca: hospital-ca.
alerts.smtp.certificate
Type: text
A client certificate to present to the mail server (a certificates: entry with its key), for servers that admit senders by certificate. Not with tls: none. Default: none. Example: certificate: ductus-client.
alerts.channels
Type: names, each with settings, below
Where alerts can go, by a name rules use in to:: each an email list, a chat webhook, or both. Send to teams (a mailing list, a chat channel) rather than to one person: people change and sleep; a team's list doesn't. ductus alerts test <channel> sends a test from the command line, no engine needed. Default: none. Example: channels: { oncall: { email: interfaces-oncall@hospital.org }, chat: { webhook: { url: "${secret:CHAT_WEBHOOK}", format: teams } } }.
alerts.channels.<name>.email
Type: text, or a list
The address, or addresses, notifications are mailed to: best a team's list (interfaces-oncall@hospital.org), or a pager's email gateway. Needs alerts.smtp. Default: none. Example: email: [interfaces-oncall@hospital.org, lab-it@hospital.org].
alerts.channels.<name>.webhook
Type: settings, below
A chat or incident tool's incoming webhook that notifications are posted to (Teams, Slack, or your own tool with format: json). Default: none. Example: webhook: { url: "${secret:CHAT_WEBHOOK}", format: teams }.
alerts.channels.<name>.webhook.url
Type: text · Required
The webhook's URL. A chat webhook's URL is its own password (anyone with it can post to the channel), so keep it in a secret: ${secret:CHAT_WEBHOOK}. The engine shows only its scheme and host anywhere. Required. Example: url: "${secret:CHAT_WEBHOOK}".
alerts.channels.<name>.webhook.format
Type: json, slack, teams
What the posted body looks like:
json: Ductus's own JSON, every field, for scripts and incident tools.slack: Slack incoming webhooks (also Mattermost and Rocket.Chat).teams: Microsoft Teams Workflows webhooks (an Adaptive Card; the old Office 365 connectors are being retired).
Default: json. Example: format: teams.
alerts.channels.<name>.webhook.ca
Type: text
A CA to trust for the webhook's server besides the ones this server trusts (a certificates: entry in resources.yaml), for an internal tool with a private CA's certificate. Default: the system's trusted CAs only. Example: ca: hospital-ca.
alerts.channels.<name>.webhook.certificate
Type: text
A client certificate to present to the webhook's server (a certificates: entry with its key), for tools that admit callers by certificate. Default: none. Example: certificate: ductus-client.
alerts.rules
Type: list of settings, below
Which health states alert, how badly, and to whom. Each state is matched by the first rule that names it; a state no rule names doesn't alert (ductus validate says which). Default: none (nothing alerts). Example: rules: [{ when: [error, stalled, stopped], severity: critical, to: [oncall, chat] }, { when: [behind, silent, missed, certificate], severity: warning, to: [chat] }].
alerts.rules.when
Type: list of error, stalled, behind, stopped, silent, missed, certificate · Required
The health states this rule covers:
error: a destination has quarantined messages someone must look at.stalled: a destination has had messages waiting for over a minute and sent none (its receiver is down, or a message keeps failing).behind: a destination's queue is past itsmonitor.behind.stopped: an interface's code was stopped (it ran away or ran out of memory).silent: nothing received withinmonitor.active_within.missed: nothing received bymonitor.active_by.certificate: a certificate the engine uses or connects to nears expiry, or expired.
A paused destination never alerts: it's paused on purpose. Required. Example: when: [error, stalled, stopped].
alerts.rules.severity
Type: warning, critical · Required
How bad these states are: warning (worth knowing today; held during quiet hours) or critical (act now; never held). An alert that goes from warning to critical is told again. An expired certificate is always critical. Required. Example: severity: critical.
alerts.rules.to
Type: list of text · Required
Who is told: channel names from channels, and owner (whoever owns the destination or its interface: its owner, else about.owner, mailed at their account's email, an owners: entry, or the text itself if it's an address). Lead with team channels; add owner where a person should hear directly. Required. Example: to: [oncall, chat, owner].
alerts.repeat
Type: duration, or 0
While an alert stays open and nobody has acknowledged it, remind its recipients this often; 0 never reminds. Acknowledging (on the Alerts page) stops reminders until it gets worse or recovers. Keep it long where a channel pages someone. Default: 4h. Example: repeat: 1h.
alerts.recovery
Type: true or false
Tell the people who heard about an alert when it's fine again (after settle), so they can stand down. Default: true. Example: recovery: false.
alerts.settle
Type: duration, or 0
How long a state must be fine before its alert counts as over. Bad again sooner, and the same alert goes on: a receiver flapping up and down is one alert, not dozens. 0 ends it at once. Default: 2m. Example: settle: 10m.
alerts.quiet
Type: settings, below
Hours when notifications of some severities wait until morning (warnings, overnight). A warning that comes and goes in the night is never sent, only kept in the history; one that turns critical goes at once. Default: none. Example: quiet: { between: "22:00-06:00", severities: [warning] }.
alerts.quiet.between
Type: hours (06:00-22:00) · Required
The quiet hours, in the server's local time (mind a server or container that runs on UTC): "22:00-06:00". Notifications due in them wait until they end. Required. Example: between: "21:00-07:00".
alerts.quiet.severities
Type: list of warning, critical
Which severities wait during the quiet hours. Keep critical out: a critical alert that waits until morning wasn't critical. Default: [warning]. Example: severities: [warning].
alerts.heartbeat
Type: settings, below
A URL the engine calls every every while it runs, for a service elsewhere that raises its own alarm when the calls stop (healthchecks.io, Better Stack, Uptime Kuma, a monitoring tool's push check). An engine that is down, or can't reach its database, can't send alerts itself: this is how anyone hears about it. Set it in production. Default: none. Example: heartbeat: { url: "${secret:HEARTBEAT_URL}", every: 5m }.
alerts.heartbeat.url
Type: text · Required
The URL the engine calls (an HTTP GET) while it runs: the "ping" or "push" URL the watching service gives you. It often holds a secret: ${secret:HEARTBEAT_URL}. Use a service that doesn't run on the engine's server, or it goes down with it. Required. Example: url: "${secret:HEARTBEAT_URL}".
alerts.heartbeat.every
Type: duration
How often it's called. Set the watching service's grace period to about twice this. Default: 5m. Example: every: 1m.
alerts.heartbeat.ca
Type: text
A CA to trust for the heartbeat's server besides the ones this server trusts (a certificates: entry in resources.yaml). Default: the system's trusted CAs only. Example: ca: hospital-ca.
alerts.heartbeat.certificate
Type: text
A client certificate to present to the heartbeat's server (a certificates: entry with its key). Default: none. Example: certificate: ductus-client.
alerts.keep
Type: duration (or years: 6y)
How long alerts' history (what fired, who was told, who acknowledged) is kept, in years (1y) or any duration. Default: 1y. Example: keep: 2y.
alerts.certificates
Type: settings, below
When an expiring certificate alerts (certificate in a rule): the steps before expiry. Default: 30, 14 and 7 days.
alerts.certificates.warn_days
Type: list of number
The days before a certificate expires at which its alert is told: it fires at the first (with the rule's severity) and is told again at each later one, then as critical once expired. No reminders between steps: the steps are the reminders. Counted in whole days, from the earliest expiry in the certificate's chain. Pick the first step to leave time for your slowest renewal (a vendor's CA, a change board). Default: [30, 14, 7]. Example: warn_days: [45, 14, 3].
owners
Type: names, each with settings, below
Owners that aren't accounts here, by the name interfaces give in about.owner, with the address that reaches them: a team's mailing list ("Lab Systems": { email: lab-systems@hospital.org }). Alert rules with to: owner mail it. Owners who are accounts (best written as their email) need no entry. Default: none.
owners.<name>.email
Type: text, or a list
The address, or addresses, that reach this owner: a team's mailing list. Alert rules with to: owner mail it for the interfaces and destinations this owner owns. Default: none. Example: email: lab-systems@hospital.org.
doctor
Type: settings, below
Connection checks the engine runs by itself, as ductus doctor would: by default every six hours, only as far as each server's certificate (nothing logs in), so expiring certificates alert 30, 14 and 7 days ahead. Default: schedule: 6h, mode: certificates.
doctor.schedule
Type: duration, or off
How often the engine checks its connections: a duration of at least 1m, or off. The first check is a minute or two after the engine starts (at random, so engines started together don't check together). Each check takes well under a second for a handful of servers. Turn it off only if something else watches every certificate the engine connects to. Default: 6h. Example: schedule: 1h.
doctor.mode
Type: certificates, full
What a check covers:
certificates: DNS, TCP and the TLS handshake of every connection with a certificate. Nothing logs in, so no service account's log fills up and none is ever locked out.full: everythingductus doctorchecks, logins included (databases, SFTP, the directory), so a changed password is noticed before a message needs it.
Use full where the servers' owners agree to a login every schedule. Default: certificates. Example: mode: full.