# 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 # Write this server's PID here on boot so `echoircd rehash` (and `kill -HUP`) can # find and signal it to reload the config in place. Omit to disable the pidfile. pidfile = echoircd.pid # 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 = [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 = [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 = [level] [fp=] [type=] # The password may be positional (as below) or a named password= token; # both accept plaintext, sha256:, pbkdf2:… or a bcrypt $2b$ hash. Generate a # bcrypt hash with: printf '%s' 'yourpassword' | ./echoircd mkpasswd oper = admin CHANGE_THIS_PASSWORD # oper = admin password=$2b$11$…hash… fp= type=netadmin # Oper types (optional). An oper with no type= keeps full access. A type is a # named role (the WHOIS "is a ") built from reusable capability classes; # five ship built-in: helpop, globop, admin, servadmin, netadmin. Override or add # your own — see docs/operators.md. Running a command your type doesn't grant is # refused; the type's modes/snomasks/vhost are set automatically on oper-up. # class = <id> commands=<A,B|*> [privs=<x,y|*>] [snomasks=<letters|*>] # opertype = <id> classes=<a,b|*> [commands=..] [modes=+iw] [snomasks=+cg] \ # [vhost=host.name] [title=Nice_Title] [level=N] # class = helpdesk commands=CHECK snomasks=c # opertype = helpdesk classes=helpdesk modes=+ih title=Help_Desk level=15 # oper = alice sha256:<hex> type=netadmin # 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 ban (dnsbl_duration) 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 # # Per-blocklist form: attributes on one line override the globals above (unset # ones fall back to them). name= is the label in the DNSBL notice; reason= is the # ban reason and may contain %ip% (the client address). Values may be "quoted". # dnsbl = domain=torexit.dan.me.uk name="Tor exit node" action=zline duration=1w reason="Tor exit nodes are not allowed on this network. See https://metrics.torproject.org/rs.html#search/%ip% for more information." # The pattern engine oper /FILTER rules are compiled with: glob (wildcards, the # default) or regex (a full regular expression). Applies to filters added after it. # filter_engine = glob # 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). # Add snomask category letters after the channel to log only those categories # (x x-lines, d dnsbl, c connects, o oper, q quit, k kill, …); no letters logs # everything. Repeatable, so different snomasks can go to different channels: # chanlog = #snotices # everything # chanlog = #bans xdk # only x-lines, dnsbl hits, and kills # chanlog = #conns cq # only connects and quits # --- 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: