You saw the simplicity of Ergo Chat.
Now you think about how to build a modern, modular IRC server – like in the old days.
- Inspircd is a modern IRC server.
- Anope is a services bot.
Together they form the base of a stable and reliable communications service.
In 2026 IRC may not be the primary comms channel, but it’s perfect for secondary/backup.
The Goal
The architecture:
IRC Client
|
TLS
|
Inspircd
|
local link
|
Anope (NickServ, ChanServ)
- Inspircd is the IRC server – the clients connect directly using TLS (port 6697).
- Anope connects to Inspircd locally – it provides services.
- TLS is served by
certbotthrough Let’s Encrypt. - SASL authentication is enabled for modern clients.
Prerequisites
- A Debian Linux or compatible server.
rootuser, orsudoaccess.- Open firewall ports (80 and 6697).
- Domain pointed to the server (e.g. irc.domain.tld).
- Certificates for the domain (Let’s Encrypt).
Install The Software
Inspircd and Anope are in the Debian repository.apt can install them:
sudo apt updatesudo apt install -y inspircd anope certbot
After the installation the configurations are in:
- etc/inspircd
- etc/anope
The example configurations:
- usr/share/doc/inspircd/examples
- usr/share/doc/anope/examples
Issue The Certificates
certbot is used to issue Let’s Encrypt certificates.
With the --standalone option certbot starts a temporary http server on port 80.
I use the irc.silentarchitect.org as an example. Change it to your own domain.
sudo certbot certonly --standalone \ -d irc.silentarchitect.org \ --non-interactive \ --agree-tos \ -m tom@tomsitcafe.com
The certificates are installed in the /etc/letsencrypt/ directory by default.
By default the irc user of Inspircd cannot read them.
Copy the certs to the Inspircd config directory.
Create the certs dir:
sudo mkdir -p /etc/inspircd/certssudo chown irc:irc /etc/inspircd/certs
Copy the certs:
sudo cp /etc/letsencrypt/live/irc.silentarchitect.org/fullchain.pem /etc/inspircd/certs/sudo cp /etc/letsencrypt/live/irc.silentarchitect.org/privkey.pem /etc/inspircd/certs/sudo chown -R irc:irc /etc/inspircd/certssudo chmod 600 /etc/inspircd/certs/privkey.pem
Don’t forget to create a deploy hook that copies the certs automatically when certbot renews them.
Configure The Inspircd
The Inspircd configuration is in the /etc/inspircd/ directory.
An example inspircd.conf file is pre-deployed.
More examples can be found in the /usr/share/doc/inspircd/examples/ directory.
Backup the original config.
sudo mv /etc/inspircd/inspircd.conf /etc/inspircd/inspircd.conf.orig
In the Inspircd configuration the order of some blocks matters.
Some modules and definitions must appear before they are referenced.
Set up the network name and domain.
This will be visible for the connecting clients.
The name field must match with the DNS record.
<server name="irc.silentarchitect.org" description="SilentArchitectNetwork IRC server" network="SilentArchitectNetwork">
Load the most important Inspircd modules.
<module name="ssl_gnutls"><module name="spanningtree"><module name="account"><module name="services"><module name="cloak"><module name="cloak_sha256">
| Module | Purpose |
|---|---|
| ssl_gnutls | TLS encryption |
| spanningtree | Required for services and server linking |
| account | IRC account handling |
| services | Enables the services support |
| cloak | Hides client IP/hostname |
| cloak_sha256 | Uses SHA256 for cloaking |
The TLS configuration points to the certs you already set up.
Create an sslprofile and use it in the port binding.
<sslprofile name="Clients" provider="gnutls" cafile="" certfile="/etc/inspircd/certs/fullchain.pem" crlfile="" hash="sha3-256" keyfile="/etc/inspircd/certs/privkey.pem" mindhbits="2048" outrecsize="2048" priority="NORMAL" requestclientcert="yes" strictpriority="no"><bind address="" port="6697" type="clients" sslprofile="Clients" defer="0" free="no">
Port 6697 is the standard TLS IRC port.
Connection classes allow you to define limits, flood protection, and different client tiers.
<connect name="main" allow="*" modes="+x">
For a full working configuration example see below.
Configure Anope Services
Backup the original config.
sudo mv /etc/anope/services.conf /etc/anope/services.conf.orig
Example config directory: /usr/share/doc/anope/examples
Edit the configuration file: /etc/anope/services.conf
The minimal configuration sets up the IRC server link and the services info.
uplink{ host = "127.0.0.1" ipv6 = no ssl = no port = 7000 password = "passwordforservices"}serverinfo{ name = "services.silentarchitect.org" description = "Services of The Silent Architect" pid = "/run/anope/anope.pid" motd = "services.motd"}module{ name = "inspircd3" use_server_side_mlock = yes use_server_side_topiclock = yes}networkinfo{ networkname = "SilentArchitectNetwork" nicklen = 31 userlen = 10 hostlen = 64 chanlen = 32 modelistsize = 100 vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-" allow_undotted_vhosts = false disallow_start_or_end = ".-"}
Traditionally IRC services use flat files as a database backend.
A flat file database can easily handle ~10k users / 50k accounts.
Load the enc_sha256 module to hash passwords.
module { name = "enc_sha256" }module { name = "db_flatfile" database = "anope.db" keepbackups = 3}
For a full working configuration see below.
Test The Server
After starting the services you should be able to connect with a client:
irc.silentarchitect.org:6697 (TLS)
Example with weechat:
/server add silent irc.silentarchitect.org/6697 -ssl/connect silent
Final Thoughts
Inspircd + Anope gives you a modular IRC architecture.
The IRC daemon handles connections and routing.
Services handle identity, channels, and network state.
This separation makes the system flexible, stable, and easy to extend.
For small private networks this stack can run comfortably on even a small VPS.
Full Inspircd Configuration
The following configurations are simplified examples of a working single-server IRC network.
<server
name="irc.silentarchitect.org"
description="SilentArchitectNetwork IRC server"
network="SilentArchitectNetwork">
<admin
name="Tom"
description="tom"
email="tom@tomsitcafe.com">
<module name="ssl_gnutls">
<module name="hidechans">
<module name="spanningtree">
<module name="account">
<module name="services">
<module name="conn_umodes">
<module name="sha2">
<module name="cloak">
<module name="cloak_sha256">
<cloak method="hmac-sha256"
key="lohshal0eemei3eiFeGhiv1aep8shi"
prefix="silent"
suffix="user">
<sslprofile name="Clients"
provider="gnutls"
cafile=""
certfile="/etc/inspircd/certs/fullchain.pem"
crlfile=""
hash="sha3-256"
keyfile="/etc/inspircd/certs/privkey.pem"
mindhbits="2048"
outrecsize="2048"
priority="NORMAL"
requestclientcert="yes"
strictpriority="no">
<bind
address=""
port="6697"
type="clients"
sslprofile="Clients"
defer="0"
free="no">
<files motd="inspircd.motd">
<connect
name="main"
allow="*"
maxchans="20"
timeout="20"
pingfreq="2m"
hardsendq="1M"
softsendq="64K"
recvq="64K"
threshold="10"
commandrate="20"
fakelag="yes"
localmax="10"
globalmax="10"
resolvehostnames="no"
useident="no"
limit="5000"
modes="+x">
<connect
name="opers"
allow="*"
maxchans="60"
timeout="20"
pingfreq="2m"
hardsendq="1M"
softsendq="256K"
recvq="128K"
threshold="50"
commandrate="100"
fakelag="no"
localmax="50"
globalmax="50"
resolvehostnames="no"
useident="no"
limit="5000"
modes="+x">
<dns timeout="5">
<maxlist chan="*" limit="100">
<options
prefixquit="Quit: "
suffixquit=""
prefixpart="""
suffixpart="""
syntaxhints="no"
cyclehostsfromuser="no"
announcets="yes"
allowmismatch="no"
defaultbind="auto"
maskinlist="yes"
maskintopic="yes"
pingwarning="15"
serverpingfreq="1m"
splitwhois="no"
defaultmodes="not"
xlinemessage="You're banned! Email tom@tomsitcafe.com with the ERROR line below for help."
xlinequit="%fulltype%: %reason%"
modesinlist="opers"
extbanformat="name"
exemptchanops="filter:o nickflood:o nonick:v regmoderated:o"
invitebypassmodes="yes"
nosnoticestack="no">
<performance
netbuffersize="10240"
somaxconn="128"
softlimit="12800"
clonesonconnect="yes"
timeskipwarn="2s"
quietbursts="yes">
<security
announceinvites="dynamic"
hideservices="no"
flatlinks="no"
hidekills=""
hideservicekills="yes"
hidesplits="no"
maxtargets="20"
customversion=""
restrictbannedusers="yes"
genericoper="no"
userstats="Pu">
<limits
maxaway="200"
maxchan="60"
maxhost="64"
maxuser="10"
maxkey="30"
maxkick="300"
maxmodes="20"
maxnick="30"
maxquit="300"
maxreal="130"
maxtopic="330">
<log method="file"
level="normal"
type="* -USERINPUT -USEROUTPUT"
target="/var/log/inspircd.log">
<whowas
groupsize="10"
maxgroups="10000"
maxkeep="7d"
nickupdate="yes">
<insane
hostmasks="no"
ipmasks="no"
nickmasks="no"
trigger="95.5">
<link name="services.silentarchitect.org"
ipaddr="127.0.0.1"
port="7000"
allowmask="127.0.0.0/8"
sendpass="passwordforservices"
recvpass="passwordforservices">
<uline server="services.silentarchitect.org" silent="yes">
<bind address="127.0.0.1" port="7000" type="servers">
<module name="cap">
<module name="sasl">
<sasl target="services.silentarchitect.org" requiressl="no">
<module name="alias">
<alias text="BOTSERV" replace="PRIVMSG $requirement :$2-" requires="BotServ" service="yes">
<alias text="CHANSERV" replace="PRIVMSG $requirement :$2-" requires="ChanServ" service="yes">
<alias text="GLOBAL" replace="PRIVMSG $requirement :$2-" requires="Global" service="yes" operonly="yes">
<alias text="HOSTSERV" replace="PRIVMSG $requirement :$2-" requires="HostServ" service="yes">
<alias text="MEMOSERV" replace="PRIVMSG $requirement :$2-" requires="MemoServ" service="yes">
<alias text="NICKSERV" replace="PRIVMSG $requirement :$2-" requires="NickServ" service="yes">
<alias text="OPERSERV" replace="PRIVMSG $requirement :$2-" requires="OperServ" service="yes" operonly="yes">
<alias text="STATSERV" replace="PRIVMSG $requirement :$2-" requires="StatServ" service="yes">
<alias text="BS" replace="PRIVMSG $requirement :$2-" requires="BotServ" service="yes">
<alias text="CS" replace="PRIVMSG $requirement :$2-" requires="ChanServ" service="yes">
<alias text="GL" replace="PRIVMSG $requirement :$2-" requires="Global" service="yes" operonly="yes">
<alias text="HS" replace="PRIVMSG $requirement :$2-" requires="HostServ" service="yes">
<alias text="MS" replace="PRIVMSG $requirement :$2-" requires="MemoServ" service="yes">
<alias text="NS" replace="PRIVMSG $requirement :$2-" requires="NickServ" service="yes">
<alias text="OS" replace="PRIVMSG $requirement :$2-" requires="OperServ" service="yes" operonly="yes">
<alias text="SS" replace="PRIVMSG $requirement :$2-" requires="StatServ" service="yes">
<alias text="ID" format="*" replace="PRIVMSG $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="IDENTIFY" format="*" replace="PRIVMSG $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="LOGIN" format="*" replace="PRIVMSG $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="LOGOUT" format="*" replace="PRIVMSG $requirement :LOGOUT" requires="NickServ" service="yes">
<badnick nick="BotServ" reason="Reserved for a network service">
<badnick nick="ChanServ" reason="Reserved for a network service">
<badnick nick="Global" reason="Reserved for a network service">
<badnick nick="HostServ" reason="Reserved for a network service">
<badnick nick="MemoServ" reason="Reserved for a network service">
<badnick nick="NickServ" reason="Reserved for a network service">
<badnick nick="OperServ" reason="Reserved for a network service">
<badnick nick="StatServ" reason="Reserved for a network service">
<exemptfromfilter target="BotServ">
<exemptfromfilter target="ChanServ">
<exemptfromfilter target="Global">
<exemptfromfilter target="HostServ">
<exemptfromfilter target="MemoServ">
<exemptfromfilter target="NickServ">
<exemptfromfilter target="OperServ">
<exemptfromfilter target="StatServ">
Full Anope Configuration
The following configurations are simplified examples of a working single-server IRC network.
Copy the different services’ configuration files into the config directory.
Configure the services hostname in them.
Services files to configure:
- nickserv.conf
- chanserv.conf
- operserv.conf
- hostserv.conf
- memoserv.conf
- global.conf
The main services.conf file should look like this:
uplink
{
host = "127.0.0.1"
ipv6 = no
ssl = no
port = 7000
password = "passwordforservices"
}
serverinfo
{
name = "services.silentarchitect.org"
description = "Services of The Silent Architect"
pid = "/run/anope/anope.pid"
motd = "services.motd"
}
module
{
name = "inspircd3"
use_server_side_mlock = yes
use_server_side_topiclock = yes
}
networkinfo
{
networkname = "SilentArchitectNetwork"
nicklen = 31
userlen = 10
hostlen = 64
chanlen = 32
modelistsize = 100
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
allow_undotted_vhosts = false
disallow_start_or_end = ".-"
}
options
{
casemap = "ascii"
strictpasswords = yes
badpasslimit = 5
badpasstimeout = 1h
updatetimeout = 5m
expiretimeout = 30m
readtimeout = 5s
timeoutcheck = 3s
retrywait = 60s
hideprivilegedcommands = yes
hideregisteredcommands = yes
languages = "ca_ES.UTF-8 de_DE.UTF-8 el_GR.UTF-8 es_ES.UTF-8 fr_FR.UTF-8 hu_HU.UTF-8 it_IT.UTF-8 nl_NL.UTF-8 pl_PL.UTF-8 pt_PT.UTF-8 ru_RU.UTF-8 tr_TR.UTF-8"
}
module { name = "enc_sha256" }
module {
name = "db_flatfile"
database = "anope.db"
keepbackups = 3
}
include {
type = "file"
name = "nickserv.conf"
}
include {
type = "file"
name = "chanserv.conf"
}
include {
type = "file"
name = "operserv.conf"
}
include {
type = "file"
name = "hostserv.conf"
}
include {
type = "file"
name = "memoserv.conf"
}
include {
type = "file"
name = "global.conf"
}
log
{
target = "services.log"
bot = "Global"
logage = 7
users = "connect disconnect nick"
rawio = no
debug = no
}
module { name = "help" }
module { name = "m_sasl" }
opertype {
name = "ServicesRoot"
commands = "*"
privileges = "*"
}
oper {
name = "tom"
type = "ServicesRoot"
}
Next Steps
Once the basic server is running you may want to add:
- IRC operators
- channel registration policies
- spam protection modules
- a Matrix or Discord bridge
Inspircd’s modular design makes these extensions easy to integrate.
Final Thoughts
The Silent Architect IRC network is a quiet place.
Discussion is slow.
Silence is normal.
People speak when they have something worth saying.
Idle minds are welcome.
Noise is not.
Server: irc.silentarchitect.org
Port: 6697 (TLS)
Channel: #ghostops
Discord invite link: https://discord.gg/nxvna45STM