I've compiled more IRC daemons than I can count. UnrealIRCd with its interactive configure script. InspIRCd with its Perl-based system. ircu with its hand-tuned Makefile. Charybdis with its autotools chain. Every time, it's the same ritual: install dependencies, run configure, fix whatever broke, make, make install, then spend an hour editing a config file that's 800 lines long. Ergo changed that. I downloaded a single binary, edited a YAML file, and had a working IRC server with integrated services in under five minutes. That's not a typo. Five minutes.
Why Ergo Exists
Ergo — originally named Oragono — was started by Daniel Oaks (prawnsalad) around 2016. The motivation was straightforward: every existing IRC daemon was written in C or C++, required a separate services package (Anope, Atheme), needed manual integration between components, and carried decades of backward-compatible complexity. The question was: what would an IRC daemon look like if you started from scratch in 2016 with modern language tools and modern protocol requirements?
The answer: it would be written in Go, it would have services built in, it would implement IRCv3 natively, and it would store chat history by default. Ergo is that answer.
Go was chosen deliberately. It compiles to a single static binary — no shared library dependencies, no runtime to install. Its goroutine model maps naturally to IRC's per-connection concurrency pattern. Its standard library includes production-quality TLS, HTTP, and networking packages. And Go's garbage collector, while not as low-latency as manual memory management in C, is good enough for IRC workloads where individual messages are small and short-lived.
The project was renamed from Oragono to Ergo in 2021. The rename reflected the project's maturity: it was no longer an experiment but a production-ready IRC daemon used by real networks.
Architecture: Go, Goroutines, and Built-In Services
Traditional IRC setups involve at least two separate processes: the IRC daemon (UnrealIRCd, InspIRCd) and the services package (Anope, Atheme). These communicate over a specialized protocol — usually a server-to-server link where the services package masquerades as a pseudo-server. The integration is functional but fragile. Configuration must be synchronized. Authentication databases are separate. Upgrades must be coordinated.
Ergo collapses this into a single process. NickServ, ChanServ, and HostServ functionality is built into the daemon. Account registration, channel registration, nickname enforcement, and virtual host management all happen within the same binary, using the same configuration file and the same database.
# Ergo's internal architecture (simplified)
#
# ┌─────────────────────────────────────────┐
# │ Ergo Binary │
# │ │
# │ ┌──────────┐ ┌──────────────────────┐ │
# │ │ Listener │ │ IRC Protocol Core │ │
# │ │ (TCP/TLS)│──│ (message parsing, │ │
# │ └──────────┘ │ command dispatch) │ │
# │ └──────────┬───────────┘ │
# │ │ │
# │ ┌────────────┬───────────┼──────────┐ │
# │ │ NickServ │ ChanServ │ HostServ │ │
# │ │ (accounts) │ (channels)│ (vhosts) │ │
# │ └────────┬───┴─────┬─────┴──────────┘ │
# │ │ │ │
# │ ┌────────┴─────────┴────────────────┐ │
# │ │ BuntDB / SQLite │ │
# │ │ (embedded key-value store) │ │
# │ └──────────────────────────────────┘ │
# │ │
# │ ┌──────────────────────────────────┐ │
# │ │ Chat History Store │ │
# │ │ (in-memory, MySQL, or SQLite) │ │
# │ └──────────────────────────────────┘ │
# └─────────────────────────────────────────┘
#
# Each client connection gets its own goroutine.
# Channel operations are serialized per-channel.
# The database is accessed through a transaction layer.
The database backend is BuntDB by default — an embedded, in-process key-value store written in Go. For larger deployments, MySQL and PostgreSQL are supported for the history backend. The main account/channel database remains BuntDB because the access patterns (mostly reads, infrequent writes) suit an embedded store perfectly.
Goroutines handle concurrency. Each client connection runs in its own goroutine. Channel message broadcasting uses goroutine fan-out. The Go runtime's scheduler multiplexes these goroutines across OS threads automatically. For an IRC server handling a few thousand connections, this works without any manual tuning.
Installation and Basic Configuration
Installation on Linux:
# Download the latest release (check github.com/ergochat/ergo/releases)
wget https://github.com/ergochat/ergo/releases/download/v2.13.1/ergo-2.13.1-linux-x86_64.tar.gz
tar xzf ergo-2.13.1-linux-x86_64.tar.gz
cd ergo-2.13.1-linux-x86_64
# The directory contains:
# ergo — the binary
# default.yaml — default configuration
# languages/ — translation files
# docs/ — documentation
# Copy and edit the configuration
cp default.yaml ircd.yaml
# Generate TLS certificate (or use Let's Encrypt)
./ergo mkcerts
# Start the server
./ergo run --conf ircd.yaml
The configuration file is YAML — a significant departure from the custom configuration formats used by UnrealIRCd and InspIRCd. YAML is polarizing, but it's readable and every text editor understands it. Here's a minimal production configuration:
# ircd.yaml — Ergo configuration (key sections)
network:
name: MyNetwork
server:
name: irc.example.com
listeners:
":6667":
":6697":
tls:
cert: certs/fullchain.pem
key: certs/privkey.pem
":8097":
websocket: true
tls:
cert: certs/fullchain.pem
key: certs/privkey.pem
# WebSocket support built in — no need for external proxy
# for basic WebSocket IRC clients
accounts:
registration:
enabled: true
# Allow open registration (or require approval)
allow-before-connect: true
authentication-enabled: true
# Require accounts to join channels (optional, anti-spam)
require-sasl:
enabled: false
# NickServ enforcement
nick-reservation:
enabled: true
method: strict # strict = only account owner can use the nick
force-nick-equals-account: true
channels:
registration:
enabled: true
default-modes: +ntC
# +n = no external messages
# +t = only ops can change topic
# +C = no CTCP to channel
history:
enabled: true
channel-length: 2048 # messages per channel
client-length: 256 # messages per DM conversation
chathistory-maxmessages: 100 # max returned per CHATHISTORY request
retention:
allow-individual-delete: false
enabled: true
duration: 7d # keep history for 7 days
limits:
nicklen: 32
channellen: 64
topiclen: 390
awaylen: 390
linelen:
tags: 4096
rest: 2048 # Much more than RFC 1459's 512
That's it. One file. One binary. The server starts with NickServ, ChanServ, and chat history all working. No separate services package to install, configure, and link.
default.yaml is extensively commented — every option is explained inline. Read it before writing your own config. Most of the defaults are sensible for small to mid-size networks. You'll mostly change the network name, server name, TLS paths, and history settings.IRCv3 Features: Chat History and Modern Capabilities
Ergo was designed for IRCv3 from the ground up. It doesn't bolt IRCv3 extensions onto a legacy protocol implementation — the extensions are first-class features.
The most transformative feature is chat history. Traditional IRC is ephemeral: if you're not connected, you miss everything. Bouncers (ZNC) solve this by maintaining a persistent connection on your behalf, but they're an extra component to install and maintain. Ergo stores history server-side and delivers it to clients that support the IRCv3 draft/chathistory specification.
# IRCv3 capabilities supported by Ergo (partial list)
# Negotiated during connection via CAP command
CAP LS 302
:irc.example.com CAP * LS :account-notify account-tag away-notify \
batch cap-notify draft/channel-rename draft/chathistory \
draft/event-playback draft/relaymsg echo-message extended-join \
extended-monitor invite-notify labeled-response message-tags \
multi-prefix sasl=PLAIN,EXTERNAL server-time setname \
standard-replies userhost-in-names
# Requesting chat history after connecting:
# CHATHISTORY LATEST #channel * 50
# → Server responds with the last 50 messages from #channel
#
# CHATHISTORY BEFORE #channel msgref=abc123 100
# → Server responds with 100 messages before the referenced message
#
# This works with clients like:
# - Gamja (web client)
# - The Lounge (web client)
# - Goguma (Android)
# - Senpai (terminal)
# - Any client implementing draft/chathistory
Other notable IRCv3 features in Ergo:
- SASL authentication — PLAIN and EXTERNAL (client certificate) mechanisms. Authentication happens during the connection handshake, before the user is visible on the network.
- Message IDs — Every message gets a unique server-assigned identifier, enabling reliable history navigation and message referencing.
- Server-side timestamps — Messages carry server-assigned timestamps, solving clock synchronization issues between clients.
- Account tags — Every message from an authenticated user carries their account name, enabling clients to display stable identities regardless of nickname changes.
- Always-on clients — Ergo can maintain a virtual presence for users who disconnect, delivering messages to them when they reconnect. This effectively replaces ZNC for many use cases.
The always-on feature deserves emphasis. With Ergo, you can configure your account to remain "connected" even when your client disconnects. Messages sent to you or to channels you're in are stored and delivered when you reconnect. Your nickname stays reserved. Your channel memberships persist. It's a bouncer built into the server.
# Enable always-on for your account (as a user)
/msg NickServ SET ALWAYS-ON true
# Configure auto-away message
/msg NickServ SET AUTO-AWAY-MESSAGE "Not here right now, messages are saved."
# When you reconnect, history is delivered automatically
# (if your client supports draft/chathistory)
# or you can request it manually:
/msg HistServ PLAY #channel 2024-11-01T00:00:00Z
Comparison to C-Based IRC Daemons
The honest comparison. Ergo is not universally better. It's better for some use cases and worse for others.
Where Ergo wins:
- Setup time. Minutes versus hours.
- Integrated services. No Anope/Atheme to install and configure.
- Chat history out of the box.
- WebSocket support built in.
- IRCv3 support is native and complete.
- Single binary deployment — no dependency management.
- YAML config is more readable than custom formats.
Where C-based daemons win:
- Raw performance at scale. UnrealIRCd and InspIRCd have been optimized for 20+ years for maximum connections per server. A busy hub handling 50,000+ connections will perform better on a C daemon.
- Module ecosystem. InspIRCd's module system is extensive. Custom modules for specific network needs are well-supported.
- Multi-server linking. Ergo supports server linking but it's less mature than the battle-tested S2S protocols of UnrealIRCd or InspIRCd.
- Community size. More operators have experience with UnrealIRCd/InspIRCd. More documentation exists. More forum threads cover edge cases.
- Memory footprint. Go's garbage collector and goroutine overhead mean Ergo uses more memory per connection than a C daemon. For most deployments this doesn't matter. For a network hub handling tens of thousands of connections, it might.
# Rough resource comparison (approximate, varies by workload)
#
# Ergo UnrealIRCd InspIRCd
# Base RAM ~30 MB ~5 MB ~8 MB
# Per connection ~15 KB ~3 KB ~4 KB
# 1000 users ~45 MB ~8 MB ~12 MB
# 10000 users ~180 MB ~35 MB ~48 MB
# Build deps Go compiler C compiler, C++ compiler,
# libssl, etc. cmake, libssl
# Binary size ~25 MB ~2 MB ~3 MB
# Config format YAML Custom XML-like
# Services Built-in Anope/Atheme Anope/Atheme
# Chat history Built-in No (ZNC) No (ZNC)
Running Ergo in Production
For production deployment, a few additional considerations:
# systemd service file for Ergo
[Unit]
Description=Ergo IRC Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ergo
Group=ergo
WorkingDirectory=/opt/ergo
ExecStart=/opt/ergo/ergo run --conf /opt/ergo/ircd.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
LimitNOFILE=65536
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/ergo/data /opt/ergo/logs
ReadOnlyPaths=/opt/ergo/certs
[Install]
WantedBy=multi-user.target
Backups: the critical data is in Ergo's database file (default: ircd.db in the data directory). This is a BuntDB file. Back it up regularly. For history stored in MySQL/PostgreSQL, use standard database backup procedures.
TLS certificate renewal: Ergo reloads TLS certificates on SIGHUP. Add a certbot renewal hook that sends SIGHUP to the Ergo process after renewing certificates. ExecReload in the systemd service file handles this cleanly with systemctl reload ergo.
Monitoring: Ergo exposes basic statistics through the IRC protocol (/LUSERS, /STATS). For external monitoring, write a simple probe that connects, sends LUSERS, and checks the response. Prometheus exporters for IRC are not common, but the probe approach works well enough for alerting on downtime.
I've been running Ergo for a small private network since 2022. Twelve users. Three channels. Always-on enabled for everyone. The server runs on a $5/month VPS and uses about 60 MB of RAM. It has not crashed once. The upgrade process is: download new binary, replace old binary, restart. The entire operation takes 30 seconds. After decades of compiling C daemons and wrangling Anope configurations, this feels like cheating.
FAQ
Can Ergo link with UnrealIRCd or InspIRCd servers?
No. Ergo uses its own server-to-server protocol, which is not compatible with UnrealIRCd's or InspIRCd's S2S protocols. You can only link Ergo servers with other Ergo servers. If you need to interconnect with an existing UnrealIRCd/InspIRCd network, Ergo is not the right choice for that specific server.
Does Ergo support all the channel modes I'm used to?
Ergo supports standard channel modes (+i, +k, +l, +m, +n, +s, +t, +C, +R, etc.) and adds some of its own. However, some modes specific to UnrealIRCd or InspIRCd (like UnrealIRCd's +f flood protection syntax) have different implementations or don't exist. Check Ergo's documentation for the complete mode list. For most channels, the available modes are sufficient.
Is Ergo suitable for a large public network?
It depends on the scale. For a network with up to a few thousand simultaneous users, Ergo handles the load well. For networks with tens of thousands of users, the higher per-connection memory overhead compared to C daemons may require larger servers. Ergo's server linking is functional but less battle-tested than UnrealIRCd's at very large scales. For a new public network starting from zero, Ergo is a reasonable choice. For an established large network, migration would require careful testing.
How do I migrate from UnrealIRCd + Anope to Ergo?
There is no automated migration tool. The general approach: export user accounts and channel registrations from Anope's database, convert them to Ergo's import format (JSON), and use Ergo's data import command. Nickname and channel registrations can be migrated. Chat history cannot (it didn't exist server-side on the old setup). Plan for a transition period where both servers run simultaneously and users migrate manually.