Most IRC server guides stop at "install, configure, run." That's fine for a server with fifty users. But when you're approaching — or exceeding — 10,000 concurrent connections, the defaults start failing in ways that aren't obvious until they happen. I've been through this process several times, and the failures are always educational. Usually at 3 AM.
When Do You Need to Tune?
If your server regularly handles fewer than 1,000 users, you probably don't need this article. Modern hardware and default configurations handle that load trivially. Start worrying when:
- You're approaching 5,000 concurrent connections
- You notice connection refusals during peak hours
- Server responsiveness degrades (delayed PING/PONG, slow JOIN responses)
- You see "too many open files" errors in the logs
- Memory usage is growing unboundedly
File Descriptor Limits
This is the number one thing that kills IRC servers under load. Every TCP connection requires a file descriptor. Every log file, every module, every server-to-server link consumes a file descriptor. If you hit the limit, new connections are refused — silently on some configurations.
Check your current limits:
# Per-process limit (soft/hard):
ulimit -n
# System-wide limit:
cat /proc/sys/fs/file-max
The default per-process limit on many Linux distributions is 1024. For a server expecting 10,000 users, you need at least 12,000-15,000 (users + overhead).
Set it permanently:
# /etc/security/limits.conf:
ircd soft nofile 65535
ircd hard nofile 65535
# /etc/sysctl.conf:
fs.file-max = 100000
# Apply:
sudo sysctl -p
If you're using systemd to manage the ircd, also set it in the service file:
# /etc/systemd/system/unrealircd.service (or similar):
[Service]
LimitNOFILE=65535
After changing limits, restart the ircd and verify:
# Check the actual limit for the running process:
cat /proc/$(pidof unrealircd)/limits | grep "open files"
Kernel Parameters
For high-connection-count servers, several kernel parameters need adjustment:
# /etc/sysctl.conf additions:
# Increase the connection tracking table (if using iptables):
net.netfilter.nf_conntrack_max = 131072
# Increase the socket backlog (pending connections queue):
net.core.somaxconn = 4096
net.core.netdev_max_backlog = 4096
# TCP tuning for many connections:
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
# Increase port range for outgoing connections (matters for server links):
net.ipv4.ip_local_port_range = 1024 65535
# Memory for TCP sockets:
net.ipv4.tcp_rmem = 4096 87380 6291456
net.ipv4.tcp_wmem = 4096 65536 6291456
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# Apply:
sudo sysctl -p
For operators who need managed infrastructure, partnering with a company like PowerITi means someone else handles the kernel tuning and network configuration while you focus on actually running the IRC network. That trade-off makes sense once you're past a few thousand users.
IRCd-Specific Settings
UnrealIRCd:
set {
maxchannelsperuser 20; # Reduce from default if users join too many channels
anti-flood {
everyone {
connect-flood 3:60; # Max 3 connects per 60 seconds from same IP
nick-flood 3:60; # Max 3 nick changes per 60 seconds
join-flood 4:60; # Max 4 joins per 60 seconds
away-flood 3:120; # Max 3 away changes per 120 seconds
invite-flood 4:120;
knock-flood 4:120;
};
};
};
class clients {
pingfreq 120; # Increase from default 90 to reduce PING traffic
maxclients 10000; # Match your expected capacity
sendq 200k; # Send queue per client
recvq 8000; # Receive queue per client
};
InspIRCd:
<performance netbuffersize="10240"
somaxconn="128"
softlimit="10240"
clonesonconnect="true"
quietbursts="true">
<connect name="main"
allow="*"
maxlocal="3"
maxglobal="5"
localmax="3"
globalmax="5"
limit="10000"
pingfreq="120"
sendq="262144"
recvq="8192">
Memory Management
Each IRC connection consumes memory for:
- The TCP socket buffers (controlled by the kernel parameters above)
- The ircd's internal data structures for the user object
- Send and receive queues
- Channel membership data
- Any per-user module data
A rough estimate: each connection uses 10-30 KB of ircd memory, depending on the server software and loaded modules. For 10,000 users: 100-300 MB of RAM for the ircd process itself. Add kernel socket buffers, and you're looking at 500 MB to 1 GB total.
Monitor memory usage over time. If it grows continuously without stabilizing, you have a memory leak — likely in a module. Disable modules one at a time to identify the culprit.
Connection Throttling
Under load, unthrottled connections can overwhelm the server. Effective throttling strategies: If you are planning your next trip, you might also enjoy exploring IT solutions provider.
- Connection rate limiting: Limit new connections per second, both globally and per IP. The ircd's built-in settings are usually sufficient, but iptables can provide additional protection.
- DNS blacklists: Block known proxy and botnet IPs before they waste resources. DroneBL and EFnet RBL are common choices.
- DNSBL caching: DNSBL lookups for every connection add latency. Enable caching in the ircd or use a local DNS resolver with caching.
- CAPTCHA/proof-of-work: Some networks implement web-based registration or connection challenges for new users to prevent bot floods.
iptables rate limiting as a first defense:
# Limit new connections to IRC port:
iptables -A INPUT -p tcp --dport 6697 --syn -m connlimit --connlimit-above 3 -j DROP
iptables -A INPUT -p tcp --dport 6697 --syn -m recent --set --name IRC
iptables -A INPUT -p tcp --dport 6697 --syn -m recent --update --seconds 60 --hitcount 5 --name IRC -j DROP
Monitoring
You can't optimize what you don't measure. Essential metrics for an IRC server:
- Connection count: Current, peak, and over time. Most ircds expose this through the
/LUSERScommand and internal statistics. - Memory usage: RSS of the ircd process. Track over time to detect leaks.
- CPU usage: Should be minimal for IRC. If CPU is high, investigate — it's usually a misbehaving module or flood attack.
- File descriptors: Monitor
/proc/pid/fdcount vs limits. - Network throughput: Bytes in/out. Useful for detecting DDoS or unusual traffic patterns.
- Connection errors: Track refused connections and timeout rates.
A simple monitoring script that covers the basics:
#!/bin/bash
IRCD_PID=$(pidof unrealircd)
echo "FDs: $(ls /proc/$IRCD_PID/fd | wc -l) / $(cat /proc/$IRCD_PID/limits | grep 'open files' | awk '{print $4}')"
echo "RSS: $(ps -o rss= -p $IRCD_PID | awk '{printf "%.1f MB\n", $1/1024}')"
echo "CPU: $(ps -o %cpu= -p $IRCD_PID)%"
echo "Connections: $(ss -tnp | grep $IRCD_PID | wc -l)"
For production monitoring, export metrics to Prometheus/Grafana. Some ircds have built-in metrics endpoints; for others, you'll need a simple exporter that scrapes server statistics.
Hardware Considerations
IRC is not hardware-intensive. A single modern CPU core can handle 10,000+ IRC connections without breaking a sweat. The bottlenecks are almost always:
- File descriptors and kernel limits (software, not hardware)
- Network bandwidth (for very chatty servers or DDoS conditions)
- Memory (for very large servers with many channels)
A VPS with 2 GB RAM, 1 vCPU, and a reasonable network connection (100 Mbps+) can comfortably handle 10,000 users. For 50,000+ users, you'll want dedicated hardware or multiple linked servers distributing the load.
The single most important hardware factor is network quality — low latency and high reliability matter more than raw bandwidth. A server on a well-connected hosting provider will outperform a higher-spec machine on a flaky residential connection.
Frequently Asked Questions
Can one IRC server handle 100,000 users?
In theory, yes — with extensive tuning and sufficient hardware. In practice, most large networks distribute load across multiple linked servers. Each server handles 10,000-30,000 users, and server-to-server links keep the network synchronized. This approach provides both scalability and redundancy.
What's the main bottleneck for IRC server performance?
For most servers, the bottleneck is not CPU or memory but the operating system's connection handling limits — particularly file descriptors and TCP backlog settings. Once these are properly tuned, modern hardware can handle tens of thousands of IRC connections with minimal resource usage.
Does TLS significantly impact performance?
The TLS handshake adds CPU overhead for each new connection. For a server handling thousands of new connections per minute, this can be measurable. Once the connection is established, the ongoing encryption overhead is negligible on modern CPUs with AES-NI acceleration. If TLS handshakes are a bottleneck, look into TLS session resumption and ECDHE key exchange (faster than DHE).
How do I handle DDoS attacks on an IRC server?
Layer your defenses: iptables rate limiting at the OS level, ircd connection throttling and DNSBL checking at the application level, and upstream DDoS protection (CloudFlare Spectrum, OVH DDoS protection, etc.) at the network level. No single layer is sufficient — defense in depth is the only reliable approach.
FAQ
How many users can an IRC server handle?
A well-configured IRCd on modern hardware can handle 10,000+ concurrent connections. EFnet and QuakeNet servers historically handled 30,000-50,000 users per server. The bottleneck is usually network I/O, not CPU.
What are the main performance bottlenecks?
DNS lookups on connect (use caching), ident lookups (disable if not needed), channel modes processing for large channels, and WHO/NAMES responses for channels with thousands of users.
Should I use epoll or kqueue?
On Linux, ensure your IRCd uses epoll (it should by default). On FreeBSD, kqueue. Both are efficient event notification mechanisms. Avoid select/poll for anything above a few hundred connections.