website/content/docs/config-reference.md

438 lines
18 KiB
Markdown

# Configuration reference
Every configuration block and field echoIRCd understands. For the format itself and a quick start,
see [Configuration](/docs/configuration). Most options re-apply on `echoircd rehash` (SIGHUP) with
no restart; the TLS certificate is re-read on rehash too.
## Format
echoIRCd config files use a **block format**: `section { field value; field value; … }`.
- **One field per `;`** terminator; a block may span multiple lines.
- **Comments**: `#` and `//` for line comments, `/* … */` for block comments. An inline `#` on an
*active* line is treated as part of the value unless the value is quoted — quote values that
contain `#`.
- **Booleans** are `yes` / `no`. A bare field with no value (e.g. `operprefix;`) enables it.
- **Quoting**: quote any value containing spaces or `#`.
- A legacy flat `key = value` format is also accepted; blocks are translated to flat keys
internally, so the two are exactly equivalent.
**Structural blocks** (`server`, `listen`, `tls`, `cloak`, `brand`, `oper`, `opertype`, `class`,
`link`, `webirc`, `motd`, `opermotd`) map their fields to specific keys. **Grouping blocks**
(`limits`, `timeouts`, `flood`, `connections`, `channels`, `users`, `opers`, `logging`, `modules`,
`dns`, `antiabuse`, `restrictions`, `accounts`, `verification`, `reputation`, `securitygroups`,
`websocket`, `sts`, `services`, `dnsbl`, …) are cosmetic — each field inside is simply a flat key,
so you could equally place it at top level.
Password fields accept plaintext, `sha256:<hex>`, `pbkdf2:…`, or a bcrypt `$2b$` hash. Generate one
with `printf '%s' 'pw' | ./echoircd mkpasswd`.
## server
Server identity (not repeatable).
| Field | Description |
| --- | --- |
| `name` | This server's unique name on the network |
| `network` | Network name shown to clients |
| `sid` | 3-char server ID for S2S (a digit + two alphanumerics) |
| `description` (`desc`) | Shown in LINKS / WHOIS 312 |
| `pidfile` | PID file so `echoircd rehash` / `kill -HUP` can find the process (omit to disable) |
## listen
A bound socket. **Repeatable.** `ip "*"` / `"[::]"` binds IPv4+IPv6 dual-stack.
| Field | Description |
| --- | --- |
| `ip` | Bind address (`0.0.0.0`, `[::]`, `*`, `127.0.0.1`, …) |
| `port` | Bind port |
| `type` | `client` (default) or `server` (S2S) |
| `tls` | `yes` = direct-TLS listener |
| `wss` | `yes` = WebSocket-over-TLS (browser clients) |
| `ws` | `yes` = plaintext WebSocket |
## tls
TLS certificate (re-read on rehash).
| Field | Description |
| --- | --- |
| `cert` | Path to the certificate PEM |
| `key` | Path to the private-key PEM |
| `backend` | `openssl` (default) or `rustls` (pure-Rust, no system OpenSSL) |
| `sni` | Per-host cert `"<hostname> <cert-path> <key-path>"`**repeatable** |
| `handshake_timeout` | Seconds before a stalled TLS handshake is dropped |
## brand
Per-SNI branding — one daemon presenting multiple identities. A client that connected via this TLS
SNI host sees this `servername`/`network` (welcome burst, ISUPPORT `NETWORK=`, numeric source)
instead of the globals. Needs TLS+SNI. **Repeatable.**
| Field | Description |
| --- | --- |
| `host` | The TLS SNI hostname this brand applies to |
| `servername` | Server name shown on this host |
| `network` | Network name shown on this host |
## motd / opermotd
Lines of the MOTD (shown on connect) and the oper MOTD (`/OPERMOTD`). Each quoted line is one
entry; **repeatable**.
## oper
An oper account. **Repeatable.** A block with neither password nor fingerprint is refused.
| Field | Description |
| --- | --- |
| `name` | Oper account name |
| `password` | Auth secret (plaintext / `sha256:` / `pbkdf2:` / bcrypt) |
| `fingerprint` (`fp`, `certfp`) | Require this TLS client-cert SHA-256 fingerprint (2FA, or alone) |
| `type` | References an `opertype` (role); no type = full access |
| `level` | Operlevel (KILL-protection tier) |
## class
A reusable capability class that opertypes compose. **Repeatable.**
| Field | Description |
| --- | --- |
| `name` | Class name |
| `commands` | Commands granted (`*` = all, `-TOKEN` removes one) |
| `privs` | Privileges granted (`*` = all, `-token` removes one) |
| `snomasks` | Snomask letters granted |
| `usermodes` | Oper-only user modes the type may set (letters, or `*`) |
| `chanmodes` | Oper-only channel modes the type may set (letters, or `*`) |
## opertype
A named oper role (WHOIS "is a `<title>`"). **Repeatable.** Ships five: `helpop`, `globop`, `admin`,
`servadmin`, `netadmin` (only netadmin holds every privilege).
| Field | Description |
| --- | --- |
| `name` | Opertype name (referenced by `oper.type`) |
| `classes` | Space-separated capability classes to compose |
| `modes` | User modes auto-applied on oper-up |
| `title` | WHOIS title |
| `level` | Operlevel for this type |
## link
A trusted S2S peer. **Repeatable.**
| Field | Description |
| --- | --- |
| `name` | Peer server name |
| `ip` | Peer address |
| `port` | Peer port |
| `password` | Shared link secret |
| `autoconnect` | Dial the peer on boot / after a netsplit (`no` default) |
| `services` (`uline`) | Mark the peer as a U-lined services server |
## services
The linked server that handles SASL (client `AUTHENTICATE` is relayed to it). Unset = SASL disabled.
| Field | Description |
| --- | --- |
| `sasl_server` | Server name that handles SASL |
## webirc
Trusted web gateways (kiwiirc / CGI:IRC) that send `WEBIRC` with the real client's host+ip.
**Repeatable.**
| Field | Description |
| --- | --- |
| `password` | Shared WEBIRC secret |
| `name` (`gateway`) | Gateway name |
| `mask` (`ipmask`) | Restrict which source IP may use the password |
## cloak
Host cloaking for user mode `+x`.
| Field | Description |
| --- | --- |
| `key` | Long random hex secret (keep private; changing it re-cloaks everyone) |
| `method` | `hmac-sha256` (default) / `account` / `fingerprint` / `static`**ordered, first match wins** |
| `account_prefix` | Prefix for the `account` method (default `account`) |
| `cert_prefix` | Prefix for the `fingerprint` method (default `cert`) |
| `static_host` (`static`) | Host shown for the `static` method |
## dns
Reverse-DNS and ident behaviour.
| Field | Description |
| --- | --- |
| `resolve_hosts` | Reverse-DNS on connect (default `yes`; `no` = bare IP) |
| `use_resolved_host` | Use a resolved name in the hostmask (default `yes`) |
| `useident` | Look up every client's ident (RFC 1413) |
| `requireident` | Refuse clients whose ident can't be confirmed |
| `ident_timeout` | Seconds to wait for the ident reply (default `5`) |
## dnsbl
A DNS blocklist checked on connect. **Repeatable.**
| Field | Description |
| --- | --- |
| `dnsbl` | Blocklist zone, or a full per-list string `"domain=<zone> name=<label> action=<a> duration=<d> reason=<r>"` |
| `dnsbl_action` | `mark` (default) / `kill` / `kline` / `gline` / `zline` |
| `dnsbl_reason` | Reason string |
| `dnsbl_duration` | Ban seconds for a *line action (default `86400`) |
## limits
Advertised in ISUPPORT and enforced.
| Field | Default | Description |
| --- | --- | --- |
| `maxnick` | 30 | Nick length (NICKLEN) |
| `maxchannel` | 50 | Channels a user may join |
| `maxbans` | 100 | Ban-list entries per channel |
| `maxinvites` | 100 | Pending invites per user |
| `modes` | 20 | Mode changes per MODE line |
| `max_line` | 16384 | Max bytes per line / recvq |
| `max_sendq` | 1048576 | Queued output before a slow client is dropped |
| `whowas_maxentries` | 256 | Historical nick records retained |
| `maxwatch` | 128 | WATCH entries per user |
| `maxmonitor` | 128 | MONITOR entries per user |
| `maxsilence` | 32 | SILENCE entries per user |
| `maxaccept` | 64 | `/ACCEPT` (caller-id) entries per user |
| `maxsignore` | 64 | Server-ignore entries per user |
| `metadata_maxkeys` | 32 | IRCv3 METADATA keys per target |
| `metadata_maxvalue` | 512 | METADATA value length |
| `multiline_maxbytes` | 4096 | draft/multiline max bytes |
| `multiline_maxlines` | 24 | draft/multiline max lines |
| `chathistory_limit` | 256 | CHATHISTORY messages kept per conversation |
| `chathistory_maxage` | 604800 | Max age (s) a client may request |
| `event_playback` | yes | Record JOIN/PART/QUIT/NICK/MODE/TOPIC/KICK into history |
| `webpush` | yes | draft/webpush master switch (RFC 8291/8292) |
| `webpush_away_only` | yes | Only push to away users |
| `webpush_ttl` | 259200 | Push TTL (s) |
| `dccallow_maxentries` | 20 | `/DCCALLOW` entries per user |
| `http_max_concurrent` | 32 | In-flight outbound HTTP requests (API modules) |
`webpush_sub`, `webpush_vapid_file`, `webpush_database` tune the Web Push key/store paths.
## timeouts
| Field | Default | Description |
| --- | --- | --- |
| `registration_timeout` | 60 | Drop clients that never register |
| `ping_frequency` | 90 | Idle time before a PING is sent |
| `ping_timeout` | 60 | Then drop if no PONG within this long |
| `slow_command_ms` | 200 | Snotice when one core event takes ≥ this (0 = off) |
## flood
| Field | Default | Description |
| --- | --- | --- |
| `flood_messages` | 8 | Messages per window before dropping (opers exempt) |
| `flood_seconds` | 4 | The flood window |
| `joinflood_duration` | 60 | `+j` default window |
| `nickflood_duration` | 60 | `+F` default window |
| `connflood` | "5 10" | Refuse > N connections per S seconds from one IP |
| `blockamsg` | yes | Block mass `/amsg` and `/ame` |
| `blockamsg_delay` | 3 | Same text to a different target list within N s = block |
| `blockamsg_action` | block | `block` / `kill` / `gline` / `kline` / `zline` |
| `blockamsg_duration` | 900 | Ban seconds for a *line action |
## connections
| Field | Default | Description |
| --- | --- | --- |
| `conn_waitpong` | yes | Hold registration until the client echoes a PING cookie |
| `conn_waitpong_killonbadreply` | yes | Drop on a wrong pong |
| `conn_waitpong_exempt_localhost4/6` | yes | Exempt loopback |
| `connectban` | yes | Z-line an IP range that opens too many connections |
| `connectban_threshold` | 10 | Connections from a range before it's banned |
| `connectban_duration` | 21600 | Ban seconds |
| `connectban_bootwait` | 120 | Grace after startup (reconnect storm) |
| `connectban_ipv4cidr` / `connectban_ipv6cidr` | 32 / 128 | Range width for counting |
| `connectban_exempt` | — | Never ban this glob/CIDR (**repeatable**) |
| `accept_rate` / `accept_burst` | 0 | Max new connections/sec per source IP at the accept edge |
| `proxy` | — | Trust the PROXY header from these sources (**repeatable**) |
## classes
Per-class connection policy. `connectclass` is **repeatable**; each is a single quoted string
(first match wins).
Tokens: `allow=<mask[,mask]>`, `deny=yes`, `parent=<name>`, `requiressl=yes|trusted`,
`password=<pw>`, `hash=<algo>`, `port=<p[,p]>`, `asn=<n[,n]>`, `localmax=<n>`, `globalmax=<n>`,
`limit=<n>`, `maxchans=<n>`, `pingfreq=<s>`, `timeout=<s>`, `modes=<+modes>`, `recvq=<bytes>`,
`softsendq=<bytes>`, `hardsendq=<bytes>`, `fakelag=no`, `penaltythreshold=<n>`, `commandrate=<s>`,
`useident=yes`, `requireident=yes`, `resolvehostnames=no`, `maxconnwarn=yes`. `connectclass_required
yes` refuses clients that match no allow class.
## sts
Strict Transport Security. Off unless `sts_duration > 0`.
| Field | Description |
| --- | --- |
| `sts_duration` | Seconds clients should stick to TLS (`0` = off) |
| `sts_port` | The TLS port to upgrade to |
| `sts_preload` | Advertise preload eligibility |
## opers
| Field | Default | Description |
| --- | --- | --- |
| `operprefix` | yes | Give every oper a `!` prefix (mode `y`, above owner) |
| `ojoin` / `ojoin_op` | yes | `/OJOIN` as network staff, optionally opped |
| `oper_svslogin` | yes | Allow services to SVSLOGIN opers |
| `maphide` | yes | Hide LINKS / MAP from non-opers |
| `hideservices` | yes | Hide U-lined services from MAP/LINKS/STATS |
| `hidewhois` | yes | Hide sensitive WHOIS lines from ordinary users |
`hidewhois_*` sub-keys tune exactly which WHOIS lines (server, idle, secure) are hidden and whether
opers/self see everything.
## channelvis
Restrict who sees a mode change or list mode, by rank. **Repeatable.**
| Field | Description |
| --- | --- |
| `hidemode` | Hide a mode change below a rank: `"<mode> <rank>"` |
| `hidelist` | Only this rank+ may view a list mode: `"<mode> <rank>"` |
## channels
| Field | Description |
| --- | --- |
| `announce_channels` (`chancreate`) | Snotice opers when a new channel is created |
| `channames_deny` | Forbid these chars in new channel names |
| `permchannels_database` | `+P` permanent-channel store path |
| `markread_database` | draft/read-marker store path |
| `restrictchans` | Only opers may **create** channels |
| `restrictchan` | Glob whitelist ordinary users may create (**repeatable**) |
| `badchan` | Forbid joining a glob: `"<glob> reason=… redirect=… allowopers=yes"` |
| `goodchan` | Whitelist back out of a broad `badchan` (**repeatable**) |
## users
On-connect behaviour.
| Field | Description |
| --- | --- |
| `connbanner` | NOTICE sent at connect (**repeatable**) |
| `conn_umodes` (`autoumodes`) | User modes auto-set on every client |
| `autojoin` (`conn_join`) | Channels every client auto-joins (**repeatable**) |
| `seenicks` | Snotice opers on every nick change |
| `opermodes` (`oper_umodes`) | Extra user modes set on oper-up |
| `operjoin` | Channels an oper auto-joins on oper-up (**repeatable**) |
| `vhost` | Self-service vhost: `"<user> <pass> <host>"` (**repeatable**) |
## accounts
Bridges IRCv3 draft/account-registration to an HTTP backend.
| Field | Description |
| --- | --- |
| `account_registration` | Master switch (default `no`) |
| `acctregister_registerurl` / `acctregister_verifyurl` | REGISTER / VERIFY endpoints |
| `acctregister_apikey` | Sent as `X-API-Key` |
| `acctregister_autologin` / `acctregister_beforeconnect` / `acctregister_emailrequired` / `acctregister_requiretls` | Policy toggles |
| `acctregister_ratecount` / `acctregister_ratetime` | Rate limit per IP |
## verification
Anti-bot gates (reCAPTCHA / Cloudflare challenge). Keys: `recaptcha`, `recaptcha_secret`,
`recaptcha_url`, `recaptcha_issuer`, `recaptcha_ttl`, `recaptcha_message`,
`recaptcha_whitelistports` (repeatable) — and the matching `cloudflare_*` set.
## antiabuse
| Field | Description |
| --- | --- |
| `antirandom` | Score random-looking nick/ident/realname (drones) |
| `antirandom_threshold` / `antirandom_checkfull` / `antirandom_action` / `antirandom_duration` / `antirandom_reason` / `antirandom_showfailed` | Tuning + action |
| `hashident` / `hashident_key` | Replace ident with a stable opaque per-IP token (HMAC key) |
| `locale` / `locale_dir` | Server-wide language (`en` default; `fr`/`es` ship); rehash to switch |
| `solvemsg` | Unvouched users answer one arithmetic question before PMs deliver |
| `antimixedutf8` / `amu_threshold` / `amu_minlen` / `amu_action` / `amu_target` / `amu_reason` | Block look-alike mixed-script spam |
| `badword` | `+G` censor word `"<find> [replacement]"` (**repeatable**) |
## restrictions
| Field | Description |
| --- | --- |
| `restrictmsg` | Only opers/services may be PM'd by ordinary users |
| `disabled_commands` | Refuse these commands to ordinary users (**repeatable**) |
| `restrictcommand` | Per-command: `"<CMD> connectdelay=<s> exemptidentified=yes exempttls=no reason=…"` |
| `securelist` + `securelist_*` | Delay `/LIST` for new connections (defeats list-spam bots) |
| `autodrop_commands` | Silently drop a pre-registration client that sends any of these (HTTP scanners) |
## reputation
Per-address scoring plus the `y:` score extban.
| Field | Description |
| --- | --- |
| `reputation_database` | Store path |
| `reputation_minchanmembers` | Only bump if in a channel this big |
| `reputation_scorecap` | Maximum score |
| `reputation_whois` | Who sees the score: `all` / `opers` / `self` / `none` |
| `reputationexpire` | Decay rule `"<score> <age>"` (**repeatable**) |
## securitygroups
Named groups usable as an extban (`+b g:<name>`). `securitygroup` is **repeatable**, each a quoted
string: `"<name> <criteria…>"` where criteria include `public`, `tls`, `insecure`, `account`,
`unregistered`, `oper`, `exclude-oper`, `bot`, `webirc`, `mask=<glob>`, `exclude=<glob>`,
`scoremin=<n>`, `scoremax=<n>`, `asn=<n[,n]>`.
## logging
| Field | Description |
| --- | --- |
| `syslog` / `syslog_target` / `syslog_facility` / `syslog_tag` | Mirror the log stream to syslog (Unix socket or `host:port` UDP) |
| `log_json` | Append the log stream to a file as JSONL |
| `snoop_stderr` | Also echo server-notices to stderr |
| `metrics_bind` | OpenMetrics/Prometheus scrape endpoint (bind privately), e.g. `"127.0.0.1:9109"` |
| `chanlog` | Mirror oper snotices into a channel, optionally filtered by snomask letters (**repeatable**) |
## modules
Extra features toggled here.
| Field | Description |
| --- | --- |
| `abbreviation` | A unique command prefix resolves to its command (WHOI→WHOIS) |
| `alias` | Command alias `"<ALIAS> <target>"`, e.g. `"NS NickServ"` (**repeatable**) |
| `customprefix` | Reconfigure or add channel-prefix tiers |
| `customtitle` | `/TITLE <name> <pass>` grants a WHOIS title (+ optional vhost) |
| `randquote` | Greet each connecting user with a random line (**repeatable**) |
| `showfile` | Serve a text file as its own command: `"<CMD> <path>"` |
| `filter_engine` | Oper `/FILTER` pattern engine: `glob` (default) or `regex` |
| `geoip_database` / `geoip_asn_database` | MaxMind `.mmdb` for country/city and ASN (enables `G:`/`asn=` and WHOIS geo) |
| `network_icon` | Advertise a network icon (draft/ICON) |
| `relaymsg_separators` / `relaymsg_ident` / `relaymsg_host` | draft/relaymsg (`/RELAYMSG`) for bridges |
| `extjwt_secret` / `extjwt_duration` / `extjwt_chunk` / `extjwt_service` | `/EXTJWT` token issuance |
| `filehost_*` | Advertise a file-upload service + issue upload tokens |
| `dccallow_blockfile` / `dccallow_blockchat` | Block unwanted DCC unless `/DCCALLOW +<nick>` |
| `http_tls_verify` | Verify upstream TLS certs for the HTTP client (API modules) |
## websocket
Relevant only with a `ws`/`wss` listener.
| Field | Default | Description |
| --- | --- | --- |
| `ws_origin` | — | Allowed Origin globs (**repeatable**; empty = any) |
| `ws_proxyranges` | — | Proxies whose `X-Real-IP`/XFF we trust (**repeatable**) |
| `ws_trust_proxy` | no | Trust those headers from ANY peer |
| `ws_allowmissingorigin` | yes | Allow clients that send no Origin |
| `ws_defaultmode` | text | Frame mode with no subprotocol: `text` / `binary` / `reject` |
| `ws_nativeping` | yes | Liveness via WebSocket pings (else IRC PING) |
| `ws_handshake_timeout` | 10 | Seconds to complete the HTTP Upgrade |
| `ws_ping_interval` | 60 | Seconds between keepalive pings |
| `ws_timeout` | 120 | Drop after this many seconds of silence |