Exploring the roots and future of Internet Relay Chat

Linux Server Hardening: A Sysadmin's Checklist for 2026

Every "server hardening guide" on the internet reads like it was written by a compliance consultant who's never actually administered a server under attack. Thirty pages of recommendations, half of which are irrelevant to your actual threat model, presented in no particular order of importance.

I've been hardening Linux servers since the late 1990s. Some of those servers have been targets — running IRC servers tends to attract attention. Here's what actually matters, in the order it matters, without the padding.

Hardening Philosophy

Three principles, in order of priority:

  1. Reduce attack surface. Every service listening on a port is a potential vulnerability. Every user account is a potential entry point. Every installed package is potential exploit code. Less is more.
  2. Detect compromise quickly. Prevention fails. When it does, you need to know — fast. Logging, monitoring, and alerting are not optional.
  3. Limit blast radius. When (not if) something gets compromised, limit what the attacker can do. Principle of least privilege, network segmentation, separate accounts for separate services.

SSH: The Front Door

SSH is the most critical service on your server. If SSH is compromised, everything else is irrelevant. Harden it first.

# /etc/ssh/sshd_config — the settings that actually matter:

# Disable password authentication (use keys only):
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes

# Disable root login:
PermitRootLogin no

# Restrict to specific users:
AllowUsers marco deploy

# Change the default port (reduces noise, not a security measure):
Port 2222

# Disable unused authentication methods:
KerberosAuthentication no
GSSAPIAuthentication no

# Session settings:
ClientAliveInterval 300
ClientAliveCountMax 2
MaxAuthTries 3
MaxSessions 3

# Key exchange and cipher restrictions (drop weak algorithms):
KexAlgorithms curve25519-sha256@libssh.org,curve25519-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com

After changing sshd_config:

# Test the config before restarting (NEVER restart without testing):
sudo sshd -t

# If no errors:
sudo systemctl restart sshd

# KEEP YOUR CURRENT SESSION OPEN and test a new connection in a separate terminal.
# If you lock yourself out with a config error, your existing session is your lifeline.

Firewall: Default Deny

The firewall philosophy is simple: deny everything by default, then allow only what's needed.

# Using nftables (the modern replacement for iptables):

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # Allow established connections:
        ct state established,related accept

        # Allow loopback:
        iif lo accept

        # Allow SSH (from specific IPs if possible):
        tcp dport 2222 accept
        # Or restrict to specific source: tcp dport 2222 ip saddr 203.0.113.0/24 accept

        # Allow IRC (if running an IRC server):
        tcp dport { 6667, 6697 } accept

        # Allow ICMP (ping — useful for diagnostics):
        icmp type echo-request accept
        icmpv6 type { echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } accept

        # Log and drop everything else:
        log prefix "nftables-drop: " counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Save and apply:

sudo nft -f /etc/nftables.conf
sudo systemctl enable nftables

If server administration isn't your primary skill, consider delegating the OS-level hardening to a specialized IT solutions provider. You handle the IRCd configuration, they handle the firewall rules and kernel parameters. Division of labor works.

Fail2ban: Automated Response

Fail2ban watches log files and automatically bans IPs that show malicious behavior. It's the automated response to the brute-force attacks that your firewall and SSH hardening didn't prevent.

sudo apt install fail2ban

Create /etc/fail2ban/jail.local (never edit jail.conf directly):

[DEFAULT]
bantime = 3600           # Ban for 1 hour
findtime = 600           # Within 10-minute window
maxretry = 3             # After 3 failures
banaction = nftables[type=allports]

[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 86400          # 24 hours for SSH brutes

# If running an IRC server:
[unrealircd]
enabled = true
port = 6667,6697
filter = unrealircd
logpath = /home/ircd/unrealircd/logs/ircd.log
maxretry = 5

Verify it's working:

sudo fail2ban-client status
sudo fail2ban-client status sshd

Updates: The Boring Essential

Unpatched software is the number one cause of server compromise. Not weak passwords, not misconfiguration — unpatched vulnerabilities.

# Enable automatic security updates (Debian/Ubuntu):
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

# Or manually with a cron job:
0 4 * * * apt update && apt upgrade -y -o Dpkg::Options::="--force-confold" >> /var/log/auto-update.log 2>&1

For production servers where automatic updates feel too risky, at minimum:

  • Subscribe to your distribution's security mailing list
  • Check for updates daily
  • Apply security updates within 24 hours of release
  • Have a tested rollback plan

User Management

  • One service, one user: Run each service as its own user. IRCd as ircd, web server as www-data, database as mysql. Never run services as root.
  • No shared accounts: Each human administrator gets their own account. Shared accounts make audit logs useless.
  • Sudo, not root: Use sudo for privileged operations. Configure sudo to log all commands.
  • Remove unused accounts: Audit /etc/passwd regularly. Lock accounts that shouldn't be logging in: usermod -L accountname.

Audit Logging

Logs are useless if nobody reads them. Logs are also useless if the attacker can delete them. Send logs to a remote syslog server that the compromised machine can't modify.

# /etc/rsyslog.d/remote.conf:
*.* @@logserver.example.com:514    # TCP to remote syslog

# Or use journald forwarding to a remote system

Key logs to monitor:

  • /var/log/auth.log — SSH logins, sudo usage, authentication events
  • /var/log/syslog — System events, service starts/stops
  • Application-specific logs (ircd.log, etc.)

Consider auditd for detailed system call logging on high-security servers:

sudo apt install auditd
# Log all execve calls (command execution):
sudo auditctl -a always,exit -F arch=b64 -S execve -k command_exec

Kernel Parameters

Security-relevant sysctl settings:

# /etc/sysctl.d/90-security.conf:

# Prevent IP spoofing:
net.ipv4.conf.all.rp_filter = 1

# Disable source routing:
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Disable ICMP redirects:
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# Enable SYN cookies (SYN flood protection):
net.ipv4.tcp_syncookies = 1

# Log martians (packets with impossible source addresses):
net.ipv4.conf.all.log_martians = 1

# Disable core dumps (prevent information leakage):
fs.suid_dumpable = 0

# Randomize memory layout (ASLR):
kernel.randomize_va_space = 2

Apply: sudo sysctl --system

That's the checklist. SSH, firewall, fail2ban, updates, users, logs, kernel. In that order. Do all of these before you start worrying about SELinux, AppArmor, rootkit scanners, or any of the other things that hardening guides love to recommend. The basics done well are worth more than advanced techniques done poorly.

Frequently Asked Questions

Should I change the SSH port?

Changing the SSH port from 22 to something else reduces log noise from automated scanners. It does NOT provide meaningful security — any targeted attacker will find your SSH port in seconds with a port scan. It's a convenience measure, not a security measure. Do it if the log noise bothers you; don't count on it for protection.

Is SELinux worth the complexity?

For high-security environments, yes. SELinux provides mandatory access control that limits what each process can do, even if it's running as root. For most sysadmins, the learning curve is steep and the debugging experience is frustrating. Start with the basics in this guide. Add SELinux when you've mastered everything else and have a specific threat model that requires it.

How often should I audit my server security?

Review firewall rules and user accounts monthly. Check for available security updates daily. Run a comprehensive security audit (including reviewing logs for anomalies) quarterly. After any security incident, conduct a full review immediately.

What's the first thing an attacker does after gaining access?

Typically: establish persistence (add a backdoor user, install a cron job, or modify an existing service), escalate privileges (if they didn't start as root), and cover tracks (clear or modify logs). Your defenses should detect each of these activities — the audit logging and remote log shipping in this guide are specifically designed to make track-covering difficult.

FAQ

What Linux distro should I use for IRC?

Debian Stable or Ubuntu LTS are the most common choices. They offer long support cycles, wide package availability, and well-tested security updates. Some operators prefer FreeBSD for its network stack performance.

Should I run IRCd as root?

Never. Always run your IRCd as a dedicated unprivileged user. Use systemd unit files or a supervisor to manage the process. If you need to bind to port 6667 (below 1024), use setcap or a reverse proxy.

What firewall rules do I need?

Allow inbound TCP on your IRC ports (typically 6667, 6697, and your server-to-server port). Block everything else. Use fail2ban or similar for brute-force protection on SSH. Rate-limit new connections to prevent floods.