JIRCd is a lightweight, P10-compatible IRC server written in Java. It targets small-to-medium private networks and lab setups, providing Undernet/snirc-style configuration, optional TLS for client and server links, host cloaking, logging, and a simple SASL flow (local or forwarded to a dedicated service node).
This manual focuses on practical setup and day-to-day operation.
- Overview
- Requirements
- Installation & Build
- Quick Start
- Configuration Guide
- Running & Process Management
- Using the Server (User Guide)
- Operator Guide
- Server Linking (P10)
- TLS/SSL Setup
- SASL Authentication
- WebIRC Gateways
- Host Cloaking
- Logs & Monitoring
- Troubleshooting
- Security Hardening
- FAQ
- Directory Layout
- Language: Java
- Build: Maven
- Main class:
net.midiandmore.jircd.JIRCd - Artifacts: fat-jar via Maven Assembly (
jar-with-dependencies) - Protocols: IRC client protocol + P10 server-to-server
- Configuration: single file, Undernet-style blocks
- Java 21+ runtime
- Maven 3.8+ for building
mvn clean packageArtifacts created under target/:
JIRCd-1.0.jar— normal jarJIRCd-1.0-jar-with-dependencies.jar— fat jar (recommended for running)
- Copy a configuration file:
- Use the provided example.conf as a base.
- Default path JIRCd uses:
~/lib/jircd.conf.
- Edit the
GeneralandPortblocks minimally:- Set a unique server
nameandnumeric. - Ensure at least one client
Port { port = 6667; }exists.
- Set a unique server
- Start the server:
java -jar target/JIRCd-1.0-jar-with-dependencies.jarUseful options:
# Verbose debug and raw protocol logging
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -v -r
# Use a specific config file
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -f /path/to/jircd.conf
# Test config syntax and exit
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -t -f /path/to/jircd.conf
# Start detached in background (daemon)
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -dJIRCd uses block configuration similar to Undernet IRCd. See example.conf for a full reference.
General {
name = "jircd.local";
description = "JIRCd IRC Server";
numeric = 1;
default_user_modes = "+i";
};
Port { port = 6667; } # plaintext client port
Client {
class = "Users";
ip = "*@*"; # fallback (place specific rules above this)
maxlinks = 2;
};
- General: identity and global options (name, description, numeric, flags, TLS cert/key, destructive command passwords).
- Admin: information shown by
/ADMIN. - Class: connection classes with limits (referenced by Client/Connect).
- Client: authorization rules by
username@hostorusername@ipmask. - Port: listener configuration, per-port flags for
server,tls,webirc,cloak,hidden,vhost,mask. - Operator: IRCops with login name, host mask, password, class, local/global.
- WebIRC: gateways authorized to provide real client IP/host.
- features: toggles for logging, cloaking, TLS versions, limits, etc.
- Connect: outbound server links (P10) with host/port/password/class.
- SASL: local SASL accounts or forwarding to a dedicated SASL server.
- Trustcheck: allow rules evaluated on a designated trustserver to optionally bypass
Client.maxlinks(clone protection) based on(ip, ident). - Pseudo: define service command aliases like CHANSERV/NICKSERV.
If Client.maxlinks would block a user, JIRCd can ask a dedicated trustserver whether the tuple (ip, ident) is trusted.
Protocol details: see TRUSTCHECK_README.md.
- Configure the trustserver name on all nodes:
General { trustserver = "trust.example.net"; trustcheck_timeout_ms = 2000; }
- On the trustserver node (where
General.name == General.trustserver), add allow rules:Trustcheck { mask = "trustedident@203.0.113.*"; };- or
Trustcheck { ident = "vpn*"; ip = "2001:db8:*"; };
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -t -f /path/to/jircd.confDisplays parsed block counts and key values. Fix any reported errors before going live.
Run in foreground:
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -f /path/to/jircd.confRun detached (daemon mode):
java -jar target/JIRCd-1.0-jar-with-dependencies.jar -d -f /path/to/jircd.conf- PID saved to
~/lib/jircd.pid. - Stdout/stderr appended to
~/lib/jircd.outand~/lib/jircd.err. - Stop:
kill $(cat ~/lib/jircd.pid).
Typical client session (plaintext port):
- Connect with your IRC client to
server:6667. - Register: client sends
NICK+USER. - Join channels, chat:
/JOIN #lobby/PRIVMSG #lobby :hello/TOPIC #lobby :Welcome/AWAY I'm busy(and/AWAYto clear)
Common commands:
/LIST,/NAMES #chan,/WHO #chan,/WHOIS nick./QUIT :reason.
Become an oper:
/OPER <opername> <password>
Recommended oper actions:
- Kick user:
/KICK #chan <nick> <reason> - Kill user:
/KILL <nick> <reason> - Global ban:
/GLINE <mask> <duration> <reason> - Broadcast notices:
/WALLOPS <message> - Reload config:
/REHASH - Safe restart:
/RESTART [password](protect via General.restart_password) - Shutdown:
/DIE [password](protect via General.die_password) - Channel modes:
/MODE #chan +m,/OPMODEhelpers when available
Caution: /DIE and /RESTART are destructive — always protect with strong passwords in General.
Linking steps (two servers A and B):
- Assign unique
General.numericper server; set meaningfulGeneral.name(FQDN). - On each server, add a
Connect { name=<peer>; host=<peer host>; port=4400; password=<shared>; autoconnect=yes; class=<HubServer/LeafServer/Services>; }. - For inbound-only acceptance, add a server
Port { server = yes; port = 4400; hidden = yes; }with optionaltls = yes. - Start both; check logs and
/STATS pfor link status. - Use
/SQUIT <server>to sever a link if needed.
On successful handshake, JIRCd performs an initial P10-style burst and establishes synchronization:
- Handshake: for incoming links, JIRCd replies with
PASSthenSERVER(including flags). - Netjoin batch: a
BATCH +NJ... NJwrapper groups the burst for client UX. - S-lines: topology of known servers is sent before channel/user data.
- N-lines: all local users, then known remote users, are introduced with
N. - B-lines (channels): for each channel, JIRCd sends
B <#chan> <TS> [<modes>] <users> [ :<lists>].- Users are grouped and ordered: no prefix,
+vonly,@oonly,@o+v. - Each user entry is
TOKEN[:modes]with explicit mode letters derived from prefixes:!~&@%+→S q a o h v. - Long lists are split into multiple
Blines; only the first line carries channel modes. - Ban/exception lists are appended once at the end as
:%ban ... ~except ...(space-separated).
- Users are grouped and ordered: no prefix,
- T-lines (topics): if a channel has a topic, JIRCd sends
T <#chan> <topic_set_time> :<topic>. - EB/EA: end of burst is marked with
EB;EAis sent to acknowledge the peer’sEBand proactively after ourEB.
Timestamp (TS) handling:
- When a remote channel TS is older (wins), local prefix modes may be cleared and list modes normalized.
- Continuation
Blines without<modes>do not overwrite already set channel modes.
Incoming propagation:
- BURST parsing accepts bans/exceptions with
:%(bans) and~(exceptions) markers. - Server-originated
Ttopic lines are forwarded to other servers while updating local state.
Provide PEM cert/key in General:
General {
tls_certfile = "irc.crt";
tls_keyfile = "irc.key";
};
Enable a TLS client port:
Port { port = 6697; tls = yes; }
Generate a self-signed cert quickly (development):
openssl req -newkey rsa:4096 -nodes -keyout irc.key -x509 -days 365 -out irc.crt \
-subj "/CN=jircd.local/O=JIRCd/OU=Dev"Place files under ~/lib/ or use absolute paths. In features, prefer enabling only TLS 1.2/1.3.
Note: SNI is disabled globally in code to avoid issues with IP-literal connections.
Modes:
- Local service:
SASL { service = yes; ACCOUNT_alice = "password"; ... } - Forwarded:
SASL { forward_server = "sasl.jircd.local"; service = no; }and configure aConnectto that server.
Client flow:
CAP REQ :saslAUTHENTICATE PLAINAUTHENTICATE <base64("username\0username\0password")>- Server replies
900on success or904on failure; client completes registration.
Enable on a port and authorize gateways:
Port { port = 6669; webirc = yes; }
WebIRC {
ip = "203.0.113.50";
password = "strong_shared_secret";
description = "WebChat Gateway";
hidden = yes;
};
Gateways must send WEBIRC <password> <gateway-name> <client-ip> <client-host> before NICK/USER.
Security: Only authorize trusted gateways; use strong unique secrets; restrict by IP tightly.
Style 2 cloaking (cryptographic) is recommended:
features {
"HOST_HIDING_STYLE" = "2";
"HOST_HIDING_KEY1" = "...";
"HOST_HIDING_KEY2" = "...";
"HOST_HIDING_KEY3" = "...";
"HOST_HIDING_PREFIX" = "user";
}
- Users may set
+xafter authentication to hide their host. - Operators can use
SETHOST/CHGHOSTdepending on policy. - Changing keys re-cloaks hosts differently; avoid frequent rotation.
- System log:
~/lib/jircd.log(always on) - Raw IRC:
~/lib/irc-raw.log(enable with-r) - Console mirrors info/debug when not in daemon mode
- Stats:
/LUSERS,/STATS p,/STATS W
- Validate config:
-tmode prints summary and errors. - Increase verbosity: run with
-vand optionally-r. - Check files under
~/lib/:jircd.log,irc-raw.log,jircd.out,jircd.err. - Common issues:
- Connection refused: firewall/port binding; check
Portblocks andvhost. - TLS handshake failures: certificate/key paths; protocol version settings in
features. - Link password mismatch: ensure same
passwordon both ends ofConnect. - Duplicate numeric: ensure unique
General.numericper server in the network. - WEBIRC not working: port must have
webirc = yes; block must authorize gateway IP and secret.
- Connection refused: firewall/port binding; check
- Use strong, unique
passwordvalues inConnectandOperatorblocks. - Restrict client acceptance: specific
Clientmasks first, wildcards last. - Prefer TLS-only client ports; restrict protocol versions to TLS 1.2/1.3.
- Configure
die_passwordandrestart_passwordfor destructive commands. - Limit
MAX_CONNECTIONSinfeaturesto prevent overload. - Bind server ports with
vhostand restrictmaskto trusted ranges.
- Where is the config? Default:
~/lib/jircd.conf. Override with-f. - How to stop the daemon?
kill $(cat ~/lib/jircd.pid). - Where are logs? Under
~/lib/(jircd.log,irc-raw.log,jircd.out,jircd.err). - How to change the client port? Edit
Port { port = 6667; }blocks. - How to test the config?
-t -f /path/to/jircd.conf. - Does SNI matter? SNI is disabled to avoid issues with IP-literal connections.
- Config:
~/lib/jircd.conf - MOTD:
~/lib/motd.txt - Logs:
~/lib/jircd.log,~/lib/irc-raw.log,~/lib/jircd.out,~/lib/jircd.err - TLS:
~/lib/irc.crt,~/lib/irc.key
This project is licensed under the MIT License. See LICENSE for details.
- Undernet IRCd configuration style inspiration (snircd/ircu).
- Bouncy Castle libraries for TLS/SSL.