echoIRCd/echoircd.conf.example

520 lines
29 KiB
Text
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# echoIRCd config — simple key = value (repeat `motd` for extra lines).
# Copy this file to `echoircd.conf` and fill in your own values.
# NOTE: echoircd.conf is gitignored because it holds secrets (oper password,
# cloak key, link password). Never commit your real config.
servername = irc.example.net
network = ExampleNet
# Listener addresses. `bind`, `bind_tls` and `bind_server` are all REPEATABLE — add a
# line per address/port. A bare `[::]` binds IPv4 and IPv6 at once (dual-stack), and an
# IPv4 client on it is normalized back to its real v4 address (not ::ffff:...). So a
# single `[::]` line serves both families; use explicit lines to pin specific IPs/ports.
bind = 0.0.0.0:6667
# bind = [::]:6667 # dual-stack (IPv4 + IPv6) on one line
# bind = 0.0.0.0:6668 # an extra plaintext port
# TLS listener. Generate a cert/key first, e.g.:
# openssl req -x509 -newkey rsa:2048 -keyout tls/key.pem -out tls/cert.pem \
# -days 3650 -nodes -subj "/CN=irc.example.net"
bind_tls = 0.0.0.0:6697
tls_cert = ./tls/cert.pem
tls_key = ./tls/key.pem
# The cert is re-read on REHASH, so a renewed cert applies without a restart.
# SNI: serve a different cert for a given hostname. Repeatable.
# tls_sni = irc.example.net ./tls/example.crt ./tls/example.key
# TLS backend: openssl (default) or rustls (pure-Rust, no system OpenSSL needed).
# tls_backend = rustls
# STS (Strict Transport Security): tell CAP 302 clients on the plaintext port to
# upgrade to TLS and pin it. Off unless sts_duration > 0. Set sts_port to your TLS
# port. Only enable once TLS is solid — clients will refuse plaintext for the pin.
# sts_duration = 2592000 # seconds clients should stick to TLS (0 = off)
# sts_port = 6697 # the TLS port to upgrade to
# sts_preload = no # advertise preload eligibility
motd = Welcome to echoIRCd.
motd = Edit the MOTD in your echoircd.conf.
# --- server-to-server linking ---
sid = 0AA
serverdesc = echoIRCd server
bind_server = 0.0.0.0:7000
# link = <name> <ip> <port> <password> [autoconnect] (the password is a shared secret)
# link = peer.example.net 203.0.113.5 7000 CHANGE_THIS_LINK_SECRET autoconnect
# services: the linked server that handles SASL (client AUTHENTICATE is relayed to
# it). Leave unset to disable SASL. SASL EXTERNAL additionally needs the client on
# TLS with a client certificate (its fingerprint is sent to services).
# sasl_server = services.example.net
# trusted web gateways (CGI:IRC / kiwiirc-style): they send WEBIRC to declare the
# real client's host+ip. webirc = <password> [gateway-name] [ip-mask]; the ip-mask
# restricts which source IP may use the password (recommended). Repeat for more.
# webirc = CHANGE_THIS_WEBIRC_SECRET mygateway 203.0.113.9
# IRC operators — oper = <name> <password>
oper = admin CHANGE_THIS_PASSWORD
# host-cloaking secret (+x). Use a long random hex string; keep it private.
# Changing it re-cloaks everyone.
cloak_key = CHANGE_THIS_TO_A_LONG_RANDOM_HEX_STRING
# cloak_method — how +x cloaks are built. Repeatable/ordered: the first method
# that applies to a user wins. Default (unset) = hmac-sha256. Methods:
# hmac-sha256 keyed, subnet-preserving host hash (the default)
# account logged-in users show <cloak_account_prefix>/<account>
# fingerprint TLS clients show <cloak_cert_prefix>/<hash of their cert>
# static everyone shows the fixed cloak_static_host
# e.g. account cloak for logged-in users, host hash for everyone else:
# cloak_method = account
# cloak_method = hmac-sha256
# cloak_account_prefix = account # default: account
# cloak_cert_prefix = cert # default: cert
# cloak_static_host = users.example.net
# reverse-DNS clients on connect (the "*** Looking up your hostname..." notices).
# on (default) performs the lookup and reports the result; off skips it (bare IP).
resolve_hosts = on
# whether a resolved hostname is used in the hostmask (nick!user@host). on (default)
# shows the domain; off keeps the IP in the mask even though the lookup still runs
# and reports "Found your hostname". Only matters when resolve_hosts = on.
use_resolved_host = on
# allow a unique command prefix to resolve to its full command (e.g. WHOI -> WHOIS)
# abbreviation = yes
# customprefix — reconfigure built-in prefix tiers, or define brand-new ones.
# Built-in tiers (oper founder admin op halfop voice): a bare token = the sigil;
# ranktoset / ranktounset = min rank to grant / revoke it (a number or a tier name);
# depriv=no forbids removing it from yourself.
# customprefix = op * ranktoset=admin ranktounset=admin depriv=no
# customprefix = voice -
# New prefix (name is anything that isn't a built-in tier): letter + prefix required;
# rank (default 1), ranktoset/ranktounset (default rank), depriv (default yes).
# Ranks: voice=10 halfop=20 op=30 admin=40 founder=50 oper=60 (room to slot between).
# customprefix = helper letter=V prefix=? rank=25 ranktoset=op ranktounset=op
# DNS blocklist (DNSBL) checks on connect. Repeat `dnsbl`
# for multiple zones. On a listing, `dnsbl_action` decides what happens:
# mark = just show the "*** ... LISTED" notice, let them in (default, safe)
# kill = disconnect them (no persistent ban)
# kline / gline / zline = add a 1-day ban and disconnect
# (leave commented to disable DNSBL entirely)
# dnsbl = dnsbl.dronebl.org
# dnsbl = rbl.efnetrbl.org
# dnsbl_action = mark
# dnsbl_reason = Your host is listed in a DNS blocklist
# antimixedutf8 — block spam that mixes look-alike scripts within words.
# action = block | kill | gline | kline | zline ; target = both | channel | private
antimixedutf8 = off
amu_threshold = 8
amu_minlen = 10
amu_action = block
amu_target = both
# +G censor words: `badword = <find> [replacement]` (omit replacement to block).
# badword = examplebadword ***
# --- OPERMOTD: message shown to opers via /OPERMOTD (one line per entry) ---
# opermotd = Welcome to the staff team.
# --- self-service vhosts: /VHOST <user> <pass> sets your displayed host ---
# vhost = alice s3cret alice.staff.example
# --- command aliases: /NS ... -> PRIVMSG <target> :... (services shortcuts) ---
# alias = NS NickServ
# alias = CS ChanServ
# --- connflood: refuse >max connections per <secs> from a single IP ---
# connflood = 5 10
# --- connectclass: per-class connection policy. Each line matches connecting
# clients by IP/host mask (glob OR CIDR) and optional TLS/port; the first match
# wins, else the global limits apply. Masks are tested against the IP at connect
# and re-tested against the resolved host at registration. Keys:
# allow=<mask[,mask]> IP/host globs or CIDR (e.g. 10.0.0.0/8); any match hits
# deny=yes reject clients matching this class
# parent=<name> inherit this class's other settings (not allow/deny)
# requiressl=yes|trusted require TLS; "trusted" also requires a client cert
# password=<pw> client must send it via PASS; may be hashed
# hash=<algo> names the hash of a hashed password (md5/sha256/…)
# port=<p[,p]> only clients that connected to these listener ports
# localmax=<n> max connections per IP in this class (local server)
# globalmax=<n> max connections per IP across the whole network
# limit=<n> max total local users in this class
# maxchans=<n> max channels a member may join
# pingfreq=<secs> ping frequency; timeout=<secs> registration timeout
# modes=<+modes> usermodes set on connect
# recvq=<bytes> receive-queue cap; hardsendq=<bytes> send-queue cap
# softsendq=<bytes> send-queue level above which reads pause (backpressure)
# fakelag=no disconnect flooders instead of rate-limiting them
# penaltythreshold=<n> flood message cap; commandrate=<secs> flood window
# useident=yes do an ident (RFC1413) lookup for this class
# requireident=yes refuse clients whose ident can't be confirmed
# resolvehostnames=no skip reverse-DNS for this class
# maxconnwarn=yes snotice opers when a limit refuses a client
# (recvq/hardsendq/softsendq apply to plaintext clients; TLS clients and links
# use the global max_line/max_sendq below.)
# connectclass = trusted allow=10.0.0.0/8 maxchans=200 pingfreq=120 fakelag=no
# connectclass = secure allow=* requiressl=yes password=sha256:<hex> hash=sha256
# 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 that match no allow class (default no)
# --- global connection limits (per-class recvq/hardsendq/softsendq override these) ---
# --- core-thread health (single-threaded core: nothing slow may run inline) ---
# slow_command_ms = 200 # snotice when one event takes at least this long (0 = off)
# watchdog_ms = 5000 # a thread warns to the log if the core is stuck this long (0 = off)
# max_line = 16384 # max bytes in one line / receive queue (default 16 KiB)
# max_sendq = 1048576 # max queued output before a slow client is dropped (1 MiB)
# --- I/O scaling ---
# Client connections (plaintext and direct TLS) are served by a pool of reactor
# threads that frame lines / run TLS crypto off the single state core. One acceptor
# round-robins connections across the pool; the core stays single-threaded and lock-free.
# io_threads = 0 # reactor workers; 0 = auto (one per core, capped at 4)
# tls_handshake_timeout = 15 # drop a TLS conn that stalls mid-handshake (secs; 0 = off)
# Per-IP accept-rate limit: drop connection-churn floods at the accept edge, before any
# per-connection state is allocated (complements the connclass concurrent clone caps).
# Off by default; a generous value never affects real clients but stops a flooder
# opening/closing connections in a loop. Trusted proxies and server links are exempt.
# accept_rate = 0 # max NEW connections/sec per source IP (0 = off)
# accept_burst = 0 # instantaneous burst allowed per IP (0 = same as accept_rate)
# --- ident (RFC1413): off by default; a connection class can also enable it ---
# useident = yes # look up every client's ident (adds connect latency)
# requireident = yes # refuse clients whose ident can't be confirmed
# ident_timeout = 5 # seconds to wait for the ident reply
# --- RLINE: the /RLINE <regex> [<duration>] :<reason> oper command bans users whose
# "nick!user@host realname" matches a regex (native engine; no config to enable).
# rline_matchonnickchange = yes # also re-check the R-lines when a user changes nick
# --- syslog: mirror the server-notice / log stream to the system logger ---
# syslog = yes
# syslog_target = /dev/log # a Unix socket path, or host:port for UDP
# syslog_facility = daemon # kern user mail daemon auth ... local0..local7
# syslog_tag = echoircd
# --- log_json: append the server-notice / log stream to a file as JSONL ---
# log_json = /var/log/echoircd/events.jsonl
# --- metrics: OpenMetrics/Prometheus scrape endpoint (plaintext HTTP GET). Off
# unless bound; expose it only on a private/loopback address or behind a proxy. ---
# metrics_bind = 127.0.0.1:9109
# --- rpc: token-authenticated JSON-RPC control plane over HTTP (admin tooling).
# Off unless rpc = yes AND rpc_bind is set. Bind privately; the token is a
# shared secret sent as HTTP Basic (rpc_user:rpc_token) or Bearer. ---
# rpc = yes
# rpc_bind = 127.0.0.1:8080
# rpc_user = admin
# rpc_token = CHANGE_THIS_RPC_TOKEN
# --- PROXY protocol: trust the HAProxy/nginx PROXY header (v1 or v2) from these
# sources (glob or CIDR, repeatable), so the real client IP is used instead of
# the proxy's. A connection from a trusted proxy MUST lead with a PROXY header.
# Applies to the plaintext and TLS client listeners (WebSocket uses XFF instead).
# proxy = 127.0.0.1
# proxy = 10.0.0.0/8
# --- WebSocket transport (browser IRC clients connect straight to echoIRCd) ---
# bind_ws = 127.0.0.1:8097 # ws:// listener
# bind_wss = 0.0.0.0:7799 # wss:// listener (uses tls_cert/tls_key)
# ws_origin = https://x.example # (repeatable) allowed Origin globs; empty = any
# ws_defaultmode = text # frame mode with no subprotocol: text|binary|reject
# ws_proxyranges = 127.0.0.1 # (repeatable) glob/CIDR of proxies whose
# # X-Real-IP / X-Forwarded-For we trust (scoped)
# ws_trust_proxy = no # trust those headers from ANY peer (simpler but
# # allows IP spoofing; prefer ws_proxyranges)
# ws_allowmissingorigin = yes # allow clients that send no Origin header
# ws_nativeping = yes # liveness via WebSocket pings (no = IRC PING)
# ws_handshake_timeout = 10 # seconds to complete the HTTP Upgrade
# ws_ping_interval = 60 # seconds between WebSocket keepalive pings
# ws_timeout = 120 # drop after this many seconds of silence
# --- security groups: securitygroup = <name> [criteria...]
# criteria: public tls insecure account unregistered oper exclude-oper
# bot exclude-bot webirc exclude-webirc mask=<glob> exclude=<glob>
# scoremin=<n> scoremax=<n> — use as an extban: MODE #c +b g:<name>
# securitygroup = trusted account tls public
# securitygroup = newbies scoremax=10 public
# --- reputation: per-address scoring + y: score extban ---
# reputation_database = reputation.db # default: <conf>.reputation
# reputation_ipv4prefix = 32 # CIDR bits used to key IPv4 scores
# reputation_ipv6prefix = 64 # CIDR bits used to key IPv6 scores
# reputation_bumpinterval = 5m # how often a score bumps (+1, +2 if logged in)
# reputation_expireinterval = 605 # how often decay rules run
# reputation_saveinterval = 902 # how often the db is written
# reputation_minchanmembers = 3 # only bump if in a channel this big
# reputation_scorecap = 10000 # max score
# reputation_whois = all # all | opers | self | none
# reputationexpire = 2 1h # score<=2 decays after 1h (repeatable; * = any)
# reputationexpire = * 90d # any score decays after 90d
# extban usage: MODE #chan +b y:<100 (ban score below 100) +b y:>500 (above 500)
# --- permanent channels (+P): oper-only mode; the channel survives an empty
# member list AND a restart (its modes, topic, TS and ban lists are saved). ---
# permchannels_database = permchannels.db # default: <conf>.permchannels
# --- read markers (IRCv3 draft/read-marker): account-keyed "last read" positions
# are persisted so they survive a restart, not just reconnects. ---
# markread_database = markread.db # default: <conf>.markread
# --- whoisport: opers see the target's listener port in WHOIS (always on) ---
# --- ircv3_network_icon: advertise a network icon via draft/ICON ISUPPORT ---
# network_icon = https://example.org/icon.png
# --- profileLink: a profile URL in WHOIS for logged-in users ---
# profilelink_baseurl = https://example.org/profile/
# --- hidewhois: hide sensitive WHOIS lines from ordinary users ---
# hidewhois = yes
# hidewhois_opers = yes # opers still see everything
# hidewhois_selfview = yes # a user sees their own full WHOIS
# hidewhois_hide_server = yes # hide 312
# hidewhois_hide_idle = yes # hide 317
# hidewhois_hide_secure = yes # hide 671
# --- chanlog: mirror the oper server-notice stream into a channel so
# staff can watch it in a normal window. Set the channel (create/keep it opped):
# chanlog = #snotices
# --- extbanbanlist: no config — adds the matching extban
# `b:<#channel>`, so `+b b:#staff` catches everyone banned in #staff (shares a
# ban list between channels).
# --- relaymsg (draft/relaymsg): an OPERATOR whose client negotiated the capability
# and who is in the channel can /RELAYMSG <#chan> <nick> <text> to speak under a spoofed relay
# nick (for bridges). The nick must contain a separator and not collide.
# relaymsg_separators = /
# relaymsg_ident = relay
# relaymsg_host = relay.example.com # default: the server name
# --- operprefix: give every oper a `!` prefix (mode y, above owner)
# in all their channels — visible staff, and ops can't kick/deop them. Applied
# on oper-up/join, removed on de-oper.
# operprefix = yes
# --- ojoin: the /OJOIN <#chan> oper command — join as network staff with
# the `!` prefix (and channel op unless ojoin_op = no).
# ojoin = yes
# ojoin_op = yes
# --- helpmode: no config — adds oper-settable user mode +h (helpop),
# which shows "is available for help" in the user's WHOIS.
# --- globops: no config — adds the oper command /GLOBOPS <message>,
# broadcasting to all opers (like the server-notice stream).
# --- autodrop: silently drop a not-yet-registered client that sends
# any of these commands (HTTP scanners blurt GET/POST before NICK/USER):
# autodrop_commands = GET POST HEAD CONNECT PUT DELETE OPTIONS TRACE PATCH
# --- hidemode: hide changes to a mode from members below a rank
# (the setter, opers and links always see it). Repeatable,
# `hidemode = <modechar> <rank>` (owner|admin|op|halfop|voice). e.g. hide bans:
# hidemode = b op
# --- hidelist: list modes (+b/+e/+I/…) are viewable by members by
# default; this restricts a given list to a minimum rank. Repeatable,
# `hidelist = <modechar> <rank>` (rank: owner|admin|op|halfop|voice). Opers see
# everything. e.g. only ops may view the ban list:
# hidelist = b op
# --- autoop: no config needed — it's the channel list mode +w. Grant a
# status prefix to matching users on join, `+w <prefix>:<hostmask>`, e.g.
# /MODE #chan +w o:*!*@trusted.host (auto-op)
# /MODE #chan +w v:*!*@*.friend.net (auto-voice)
# /MODE #chan +w lists the entries.
# --- banredirect: no config needed — it extends ban syntax. A
# ban `+b <mask>$<#channel>` bounces a matching user into #channel instead of
# refusing them, e.g. /MODE #main +b *!*@*.spammer.net$#quarantine
# The redirect fires at most once (never loops).
# --- solvemsg: an un-vouched user must answer one arithmetic
# question before their private messages are delivered (opers & logged-in
# accounts are exempt). Cheap anti-spam-bot gate.
# solvemsg = yes
# --- dccallow: block unwanted DCC transfers unless the recipient
# ran /DCCALLOW +<nick>. Blocked file globs are repeatable; blockchat also
# gates DCC CHAT. Recipients manage their allow-list with DCCALLOW +/-/LIST.
# dccallow_blockfile = *.exe
# dccallow_blockfile = *.scr
# dccallow_blockchat = yes
# dccallow_maxentries = 20
# --- conn_waitpong: hold registration until the client answers
# a server PING with the exact cookie — filters bots that never PONG. Real
# clients auto-reply, so it's transparent to them.
# conn_waitpong = yes
# conn_waitpong_killonbadreply = yes # drop on a wrong pong (default: keep waiting)
# --- showfile: serve a text file as its own command. One line per
# file: `showfile = <COMMAND> <path>`. The file is read fresh each use, so
# edits show without a rehash. e.g. make /RULES stream a rules file:
# showfile = RULES /etc/echoircd/rules.txt
# --- geoip: native MaxMind .mmdb country lookup. Enables the
# G:<cc> ban extban (e.g. +b G:CN,RU), the oper GEOIP <nick|ip> command and
# a country line in WHOIS (opers). Point at a GeoLite2-Country.mmdb file:
# geoip_database = /etc/echoircd/GeoLite2-Country.mmdb
# --- tunable limits & timeouts (every one shown with its built-in default; set a
# line only to override it). None of these are hardcoded — all read at runtime.
# flood: allow this many messages per this many seconds before dropping (opers exempt)
# flood_messages = 8
# flood_seconds = 4
# dnsbl: ban length in seconds when dnsbl_action is kline/gline/zline (default 1 day)
# dnsbl_duration = 86400
# draft/multiline: the max-bytes / max-lines advertised in the cap AND enforced
# multiline_maxbytes = 4096
# multiline_maxlines = 24
# CHATHISTORY: messages kept per conversation (also the ceiling a client may request)
# chathistory_limit = 256
# EXTJWT: token line-chunk size (bytes) when splitting a long token across lines
# extjwt_chunk = 200
# per-user list sizes (advertised in ISUPPORT WATCH/MONITOR/SILENCE where applicable)
# maxwatch = 128
# maxmonitor = 128
# maxsilence = 32
# maxaccept = 64
# WHOWAS: number of historical nick records retained
# whowas_maxentries = 256
# nick / channel name length limits (advertised as NICKLEN / CHANNELLEN)
# maxnick = 30
# maxchannel = 50
# connection timeouts, in seconds
# registration_timeout = 60 # drop clients that never register (NICK+USER) in time
# ping_frequency = 90 # send a PING after this much idle time
# ping_timeout = 60 # then drop if no PONG within this much longer
# =============================================================================
# on-connect behaviour
# =============================================================================
# connbanner: a NOTICE line sent to every connecting client (repeatable).
# connbanner = This network is for authorized users only.
# conn_umodes (alias autoumodes): user modes auto-set on every client at connect.
# conn_umodes = +ix
# autojoin (alias conn_join): channels every client auto-joins on connect
# (comma/space separated; repeatable).
# autojoin = #lobby,#help
# seenicks: snotice opers every time a user changes nick (off by default).
# seenicks = yes
# chancreate (alias announce_channels): snotice opers when a brand-new channel
# is created (off by default).
# chancreate = yes
# --- oper on-connect (applied on successful OPER) ---
# opermodes (alias oper_umodes): extra user modes set when a user opers up.
# opermodes = +ws
# operjoin: channels an oper auto-joins on oper-up (comma/space separated, repeatable).
# operjoin = #opers
# =============================================================================
# account registration (IRCv3 draft/account-registration -> HTTP accounts API)
# =============================================================================
# Bridges REGISTER / VERIFY to an HTTP backend (POST form-encoded + X-API-Key).
# account_registration = yes # master switch (default no)
# acctregister_registerurl = https://accounts.example/register # required
# acctregister_verifyurl = https://accounts.example/verify # required for VERIFY
# acctregister_apikey = CHANGE_THIS_API_KEY # sent as X-API-Key
# acctregister_autologin = yes # log the user in on successful register (default yes)
# acctregister_beforeconnect = yes # allow REGISTER before registration completes (default yes)
# acctregister_emailrequired = yes # require an email address (default yes)
# acctregister_requiretls = yes # only over TLS (default yes)
# acctregister_ratecount = 3 # max register attempts per IP ...
# acctregister_ratetime = 3600 # ... per this many seconds
# =============================================================================
# human-verification gates at registration (anti-bot)
# =============================================================================
# --- recaptcha: hand an unverified user a token + URL; they solve it and send
# CAPTCHA <token>. JWT-only by default (no backend call needed). ---
# recaptcha = yes
# recaptcha_secret = CHANGE_THIS_HS256_SECRET # signs the IP-bound token
# recaptcha_url = https://example.org/captcha?token= # where to solve it
# recaptcha_issuer = echoIRCd # JWT issuer (default echoIRCd)
# recaptcha_ttl = 1800 # token lifetime, secs (default 1800)
# recaptcha_message = Please verify you are human:
# recaptcha_whitelistports = 6697 # listener ports exempt (repeatable)
# --- cloudflare_challenge: same idea via VERIFYCHALLENGE <token> ---
# cloudflare_challenge = yes
# cloudflare_secret = CHANGE_THIS_HS256_SECRET
# cloudflare_url = https://example.org/challenge?token=
# cloudflare_issuer = echoIRCd
# cloudflare_ttl = 1800
# cloudflare_message = Solve the challenge:
# cloudflare_whitelistports = 6697 # (repeatable)
# =============================================================================
# anti-spam / anti-drone
# =============================================================================
# --- antirandom: score random-looking nick/ident/realname (spam drones) ---
# antirandom = yes
# antirandom_threshold = 10 # score at/above this acts (default 10)
# antirandom_checkfull = yes # also score ident + realname (default yes)
# antirandom_action = kill # block | kill | gline | kline | zline
# antirandom_duration = 86400 # ban seconds for a *line action
# antirandom_reason = Random-looking connection rejected
# antirandom_showfailed = no # snotice opers on a hit (default no)
# --- blockamsg: block mass /amsg and /ame (advertise/flood vector) ---
# blockamsg = yes
# blockamsg_delay = 3 # secs; same text to a different target list = block (default 3)
# blockamsg_action = block # block | kill | gline | kline | zline
# blockamsg_duration = 900 # ban seconds for a *line action (default 900)
# --- connectban: z-line an IP range that opens too many connections ---
# connectban = yes
# connectban_threshold = 10 # connections from a range before it's banned (default 10)
# connectban_duration = 21600 # ban seconds (default 6h)
# connectban_bootwait = 120 # grace secs after startup (reconnect storm) (default 120)
# connectban_gcinterval = 3600 # wipe the tally this often (default 3600)
# connectban_ipv4cidr = 32 # range width for IPv4 counting (default /32)
# connectban_ipv6cidr = 128 # range width for IPv6 counting (default /128)
# connectban_banmessage = Too many connections from your address
# connectban_exempt = 10.0.0.0/8 # never ban this glob/CIDR (repeatable);
# # loopback (127.0.0.0/8, ::1) is always exempt
# --- hashident: replace ident with a stable opaque token per IP ---
# hashident = yes
# hashident_key = CHANGE_THIS_SECRET # HMAC key; makes the mapping unforgeable
# =============================================================================
# access restrictions
# =============================================================================
# --- restrictmsg: only opers/services may be PM'd by ordinary users ---
# restrictmsg = yes
# --- restrictchans: only opers may CREATE channels (all may still join) ---
# restrictchans = yes
# restrictchan = #public-* # glob whitelist ordinary users may create (repeatable)
# --- restrictcommand: hold a command back from new/unregistered users ---
# restrictcommand = LIST connectdelay=60 exemptidentified=yes exemptwebirc=yes exempttls=no exemptscore=24 reason="Please wait a bit."
# --- disable: refuse commands to ordinary users (opers bypass); reply 421 ---
# disabled_commands = KNOCK # space-separated; repeatable
# --- denychans: forbid joining channels matching a glob ---
# badchan = #evil* reason="Off-limits." redirect=#lobby allowopers=yes
# goodchan = #evilgenius # whitelist back out of a broad badchan (repeatable)
# --- channames: forbid characters in NEW channel names ---
# channames_deny =   # e.g. control codes / unwanted Unicode
# --- maphide: hide LINKS / MAP from non-opers ---
# maphide = yes
# --- securelist: delay /LIST for new connections (defeats list-spam bots) ---
# securelist = yes
# securelist_waittime = 60 # seconds connected before /LIST works (default 60)
# securelist_exemptregistered = yes # logged-in users are exempt (default yes)
# securelist_exception = *!*@trusted.example # exempt host glob (repeatable)
# securelist_showmsg = yes # tell the early lister to wait (default yes)
# securelist_fakechans = 5 # size of the throwaway fake list shown (default 5)
# securelist_fakechanprefix = # # prefix for the fake channels
# securelist_fakechantopic = ... # topic shown on the fake channels
# =============================================================================
# extra features
# =============================================================================
# --- customtitle: /TITLE <name> <pass> grants a WHOIS title (+ optional vhost) ---
# customtitle = staff s3cret staff.example.net Network Staff
# --- randquote: greet each connecting user with a random line (repeatable) ---
# randquote = "The best way out is always through." — Robert Frost
# --- extjwt: /EXTJWT issues a signed token proving IRC identity to a service ---
# extjwt_secret = CHANGE_THIS_HS256_SECRET # required to enable
# extjwt_duration = 30 # token lifetime, seconds
# extjwt_service = myservice CHANGE_THIS_SERVICE_SECRET # per-service key (repeatable)
# --- filehost: advertise a file-upload service + hand logged-in users a token ---
# filehost_website = https://files.example.net
# filehost_jwt_secret = CHANGE_THIS_HS256_SECRET
# filehost_jwt_issuer = echoIRCd
# filehost_requiressl = yes # only issue upload tokens to TLS users (default yes)
# filehost_token_expiry = 3600 # upload-token lifetime, secs (default 3600)
# filehost_auth_message = Upload here: