diff --git a/content/docs/configuration.md b/content/docs/configuration.md index a9ae6e1..b9ceda3 100644 --- a/content/docs/configuration.md +++ b/content/docs/configuration.md @@ -1,62 +1,306 @@ # Configuration -echoIRCd is configured from a single file (`echoircd.conf` by default). The format is a set of -**blocks** made of `key value;` fields. +echoIRCd reads one file — `echoircd.conf` by default. This page walks you from a two-line starter +config to a full, production-ready one, section by section. Every option (with its default) is listed +in the [Configuration reference](/docs/config-reference), and the shipped `echoircd.conf.example` is +the same thing as a file you can copy. -> Inline `#` comments are **not** stripped from a value — keep active lines to bare values and put -> comments on their own line. +```sh +cp echoircd.conf.example echoircd.conf # then edit it +``` -## Format +## The format + +Config is a set of **blocks** — `section { field value; … }`: + +- **One field per `;`.** A block may span multiple lines. +- **Comments:** `#` and `//` for a line, `/* … */` for a range. An inline `#` on an active line is + part of the value unless you quote the value, so quote anything containing `#` or spaces. +- **Booleans** are `yes` / `no`. A bare field (e.g. `operprefix;`) means `yes`. +- **Defaults are built in** — you only set a field to *change* it. +- Most changes re-apply on **`echoircd rehash`** (SIGHUP) with no restart; the TLS cert is re-read + too. + +> `echoircd.conf` holds secrets (oper password, cloak key, link password) — it's gitignored in the +> source tree for that reason. Never commit your real config. + +## Minimal config + +The smallest thing that boots — plaintext on 6667: ```ini -network "echoiRCd"; -sid "0AA"; +server { + name "irc.example.net"; # your server's unique name + network "ExampleNet"; # the network name clients see + sid "0AA"; # 3 chars: a digit + 2 alphanumerics +} -listen { ip "[::]"; port 6697; tls yes; } # dual-stack v4 + v6 +listen { ip "[::]"; port 6667; } # plaintext, IPv4 + IPv6 ``` +That's a working IRC server. Everything below adds TLS, operators, services, and hardening. + +## A complete example + +A realistic config you can copy and adapt. Uncommented lines are a sensible starting point; +commented lines show common extras. + +```ini +# ── server identity ────────────────────────────────────────────── +server { + name "irc.example.net"; + network "ExampleNet"; + sid "0AA"; + description "ExampleNet IRC"; + pidfile "echoircd.pid"; # lets `echoircd rehash` find the process +} + +# ── listeners (repeatable; [::] = IPv4 + IPv6) ─────────────────── +listen { ip "[::]"; port 6667; } # plaintext +listen { ip "[::]"; port 6697; tls yes; } # direct TLS +listen { ip "[::]"; port 7799; wss yes; } # WebSocket (browser clients) +listen { ip "[::]"; port 7000; type server; } # server-to-server links + +# ── TLS (cert re-read on rehash) ───────────────────────────────── +tls { + cert "./tls/cert.pem"; + key "./tls/key.pem"; + # backend openssl; # or rustls (pure-Rust, no system OpenSSL) +} + +# ── message of the day ─────────────────────────────────────────── +motd { + "Welcome to ExampleNet."; + "Be excellent to each other."; +} + +# ── host cloaking: mode +x hides a user's real host ────────────── +cloak { key "REPLACE-WITH-A-LONG-RANDOM-HEX-STRING"; } + +# ── operators ──────────────────────────────────────────────────── +# Hash the password: printf '%s' 'yourpass' | ./echoircd mkpasswd +oper { + name "admin"; + password "$2b$11$REPLACE_WITH_A_BCRYPT_HASH"; + type netadmin; # full access (a built-in type) + # fingerprint ""; # optional TLS-cert 2FA +} + +# ── link to services (NickServ / ChanServ / …) ─────────────────── +# link { +# name "services.example.net"; +# ip 127.0.0.1; +# port 7000; +# password "REPLACE-WITH-A-LINK-SECRET"; +# services yes; # mark it a U-lined services server +# } +# services { sasl_server "services.example.net"; } + +# ── sensible tuning ────────────────────────────────────────────── +flood { flood_messages 8; flood_seconds 4; } +timeouts { registration_timeout 60; ping_frequency 90; ping_timeout 60; } +antiabuse { antirandom yes; solvemsg yes; } +logging { metrics_bind "127.0.0.1:9109"; } +``` + +The rest of this page explains each piece. + ## Listeners -Each `listen` block opens one port. `tls yes` makes it a direct-TLS port, `wss yes` a -WebSocket-over-TLS port, and `type server` a server-to-server port. +Each `listen` block opens one socket; add as many as you need. `ip "[::]"` (or `"*"`) binds IPv4 and +IPv6 at once. `type server` is the port other servers (and the services package) link to. ```ini -listen { ip "[::]"; port 6667; } # plaintext clients -listen { ip "[::]"; port 6697; tls yes; } # direct-TLS clients -listen { ip "[::]"; port 7799; wss yes; } # WebSocket (wss) -listen { ip "[::]"; port 7700; type server; } # server links +listen { ip "[::]"; port 6667; } # plaintext +listen { ip "[::]"; port 6697; tls yes; } # direct TLS +listen { ip "[::]"; port 7799; wss yes; } # WebSocket-over-TLS +listen { ip "127.0.0.1"; port 8097; ws yes; } # plaintext WebSocket (behind a proxy) +listen { ip "[::]"; port 7000; type server; } # S2S ``` ## TLS -Point the `tls` block at a certificate and private key. Both the OpenSSL and rustls backends are -available, and certificates are re-read on rehash. Per-host certificates can be supplied with -repeatable `sni` entries. +Point the `tls` block at a certificate and key. Use a real certificate (Let's Encrypt) in production; +for a quick test, a self-signed one works: + +```sh +openssl req -x509 -newkey rsa:2048 -keyout tls/key.pem -out tls/cert.pem \ + -days 3650 -nodes -subj "/CN=irc.example.net" +``` ```ini tls { - cert "/etc/echoircd/tls/cert.pem"; - key "/etc/echoircd/tls/key.pem"; - backend openssl; # or: rustls - sni "irc.example.net ./tls/example.crt ./tls/example.key"; + cert "./tls/cert.pem"; + key "./tls/key.pem"; + backend openssl; # or: rustls + # Per-host certificate by TLS SNI (repeatable): + # sni "irc.other.net ./tls/other.crt ./tls/other.key"; } ``` -## Cloaking +The certificate is re-read on `echoircd rehash`, so a renewed cert applies without a restart. -Set a secret `cloak` key to enable host masking: +## Operators -```ini -cloak { key "a-long-random-secret"; } -``` - -## Applying changes - -Validate, then rehash the running server — no restart required: +First hash a password: ```sh -echoircd checkconfig echoircd.conf -echoircd rehash echoircd.conf # sends SIGHUP +printf '%s' 'my-strong-password' | ./echoircd mkpasswd ``` -See the shipped `echoircd.conf.example` for every available option. +Then an `oper` block ties a login to a role. `type netadmin` gives full access; drop `type` for full +access with no role. A block with neither a password nor a fingerprint is refused. + +```ini +oper { + name "alice"; + password "$2b$11$…"; # from mkpasswd + type netadmin; + host "*@192.0.2.0/24"; # optional: restrict where alice may oper from + # fingerprint "AA:BB:…"; # require this TLS client-cert (2FA, or alone) +} +``` + +`/oper alice my-strong-password` logs in. For custom roles — limiting which commands, privileges, and +modes an operator has — define `class` and `opertype` blocks; see [Operators](/docs/operators). + +## Host cloaking + +Mode `+x` replaces a user's host with a stable, keyed cloak. Set a long random secret and keep it +private (changing it re-cloaks everyone): + +```ini +cloak { + key "a-long-random-hex-secret"; + # method hmac-sha256; # default; or account / fingerprint / static +} +``` + +## Connection classes + +Fine-grained per-client policy, matched by IP/host/TLS/port — first match wins. Each class is one +quoted string of `key=value` tokens. + +```ini +classes { + connectclass "trusted allow=10.0.0.0/8 maxchans=200 pingfreq=120 fakelag=no"; + connectclass "secure allow=* requiressl=yes"; + connectclass "vpn allow=* parent=trusted localmax=2 maxchans=20 modes=+ix"; + connectclass "banned allow=1.2.3.0/24 deny=yes"; + # connectclass_required yes; # refuse clients matching no allow class +} +``` + +Common tokens: `allow=`, `deny=yes`, `requiressl=yes|trusted`, `password=`, `port=`, `asn=`, +`localmax=`/`globalmax=`, `maxchans=`, `pingfreq=`/`timeout=`, `modes=`, `recvq=`/`softsendq=`/ +`hardsendq=`, `fakelag=no`, `useident=yes`. The full list is in the +[reference](/docs/config-reference#classes). + +## DNS & ident + +```ini +dns { + resolve_hosts yes; # reverse-DNS on connect (no = show the bare IP) + use_resolved_host yes; # use the resolved name in the hostmask + # useident yes; # RFC 1413 ident lookups (adds connect latency) + # requireident yes; +} +``` + +## Limits, timeouts & flood + +All optional — the defaults are sane. Set only what you want to change. + +```ini +limits { maxchannel 50; maxnick 30; chathistory_limit 256; } +timeouts { registration_timeout 60; ping_frequency 90; ping_timeout 60; } +flood { flood_messages 8; flood_seconds 4; connflood "5 10"; } +``` + +## Anti-abuse + +Layered spam/drone defence — turn on what you need: + +```ini +antiabuse { + antirandom yes; # score random-looking nick/ident/realname + solvemsg yes; # unvouched users answer a sum before PMs deliver + # badword "spamword ***"; # +G censor (omit the replacement to block) +} + +restrictions { + # restrictmsg yes; # only opers/services may be PM'd by regular users + autodrop_commands "GET POST HEAD CONNECT PUT DELETE OPTIONS TRACE PATCH"; +} + +# DNS blocklists (repeatable): +# dnsbl { +# dnsbl "dnsbl.dronebl.org"; +# dnsbl_action "mark"; # mark | kill | kline | gline | zline +# } +``` + +See [Security & anti-abuse](/docs/security) for the whole picture. + +## Logging & metrics + +```ini +logging { + metrics_bind "127.0.0.1:9109"; # Prometheus endpoint (keep it private) + # syslog yes; # mirror to the system logger + # syslog_target "/dev/log"; + # log_json "/var/log/echoircd/events.jsonl"; + # chanlog "#snotices"; # mirror oper notices into a channel +} +``` + +See [Metrics & RPC](/docs/metrics-rpc). + +## Linking services + +The services package (NickServ, ChanServ, …) connects over the S2S port. Give it a `link` block, mark +it U-lined, and name it as the SASL server: + +```ini +listen { ip "[::]"; port 7000; type server; } + +link { + name "services.example.net"; + ip 127.0.0.1; + port 7000; + password "shared-link-secret"; + services yes; # U-lined services server +} + +services { sasl_server "services.example.net"; } +``` + +Full details on both sides are in [Server links](/docs/linking) and [Services](/docs/services). + +## WebSocket & STS + +If you run a `ws`/`wss` listener, tune it and (once TLS is solid) advertise STS to push plaintext +clients onto TLS: + +```ini +websocket { + ws_origin "https://webchat.example.net"; # allowed Origins (repeatable; empty = any) + ws_proxyranges "127.0.0.1"; # trusted reverse-proxy IPs +} + +# sts { +# sts_duration 2592000; # seconds clients should stick to TLS (0 = off) +# sts_port 6697; +# } +``` + +## Validate & apply + +Always check a config before deploying it, then reload in place: + +```sh +echoircd checkconfig echoircd.conf # parse + print every resolved key (catches typos) +echoircd rehash echoircd.conf # SIGHUP the running server — no restart, no disconnects +``` + +For every field and its default, see the [Configuration reference](/docs/config-reference).