ConfigServer Security & Firewall (CSF) is still the default packet-filter on most cPanel servers — free, scriptable, and integrated into WHM as a plugin. The install is five commands; the part that matters is the dozen csf.conf defaults that ship wrong for any production shared host.
This guide takes a fresh cPanel/AlmaLinux 9 box from iptables -F to a tuned, running CSF + LFD in about ten minutes. It assumes you already have WHM open and root SSH.
Before you install
CSF replaces firewalld and any direct iptables/nftables rules — they conflict. Stop and disable firewalld first:
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld
CSF will detect and remove conflicting kernel modules at install. If you already run cPHulk, leave it on — CSF's LFD (Login Failure Daemon) and cPHulk watch different log streams and don't fight unless you forward the same auth source to both.
Confirm the kernel has the modules CSF needs:
lsmod | grep -E 'ip_tables|nf_conntrack'
If those are absent on a minimal VPS image (rare on AlmaLinux 9, common on stripped LXC containers), check with your provider before going further — CSF can't filter what the kernel won't load.
Install CSF
cd /usr/src
wget https://download.configserver.com/csf.tgz
tar -xzf csf.tgz
cd csf
sh install.sh
The installer writes the cPanel plugin into /usr/local/cpanel/whostmgr/docroot/cgi/configserver/ and registers itself with chkservd so a crashed LFD restarts automatically. When it finishes, run the compatibility check:
perl /usr/local/csf/bin/csftest.pl
You want to see RESULT: csf should function on this server. Any FATAL line means a missing iptables module — fix that before continuing.
CSF starts in TESTING mode by default. LFD does not run, and iptables rules are flushed every five minutes by a cron job so a bad config can't lock you out. Don't disable TESTING until the rest of this guide is done.
Open the right ports
Edit /etc/csf/csf.conf and find the port lists. The cPanel defaults are too permissive — they include ports for services most hosts don't run (Webmail SSL on 2096 only matters if you actually use the cPanel webmail, daily-process-log ports, etc.). A sane shared-hosting baseline:
TCP_IN = "20,21,22,25,53,80,110,143,443,465,587,993,995,2078,2083,2087,2096"
TCP_OUT = "20,21,22,25,53,80,110,113,443,465,587,873,993,995,2087,2089,2703"
UDP_IN = "53,80,443"
UDP_OUT = "20,21,53,113,123,873,6277,24441"
Notes:
- 22 stays in
TCP_IN. If you've moved SSH to a non-standard port, replace it — don't just add the new one. - 80, 443 UDP are required for HTTP/3. Leave them in if you've enabled HTTP/3 on LiteSpeed or have any plans to.
- 2083 / 2087 / 2096 are the cPanel and WHM SSL ports. The non-SSL twins (2082 / 2086 / 2095) are intentionally absent — there is no reason to expose unencrypted cPanel in 2026.
- 53 stays in both
TCP_INandUDP_INonly if this host is a DNS server (a real authoritative name server or a member of a DNS-only cluster). Remove it on pure-web boxes.
The csf.conf settings that matter
Search inside csf.conf for each key and change it.
Stop ICMP floods
ICMP_IN_RATE = "1/s"
ICMP_IN_LIMIT = "1"
Permit ping for monitoring, but rate-limit so a single host can't ping-flood you. Set ICMP_IN = "1" if you want to allow ICMP at all; 0 blocks it entirely and breaks PMTU discovery.
Connection-tracking limits
CT_LIMIT = "300"
CT_INTERVAL = "30"
CT_BLOCK_TIME = "1800"
CT_PORTS = "80,443"
Bans an IP that holds more than 300 concurrent connections to ports 80/443 — catches both bad scrapers and broken WordPress plugins that open connections without closing them. Tune CT_LIMIT up if you serve genuinely high-fan-in traffic (large API responses, video streaming).
LFD thresholds
LF_TRIGGER = "5"
LF_TRIGGER_PERM = "3600"
LF_SSHD = "5"
LF_SSHD_PERM = "1"
LF_FTPD = "10"
LF_SMTPAUTH = "5"
LF_POP3D = "10"
LF_IMAPD = "10"
LF_CPANEL = "5"
LF_WEBMIN = "0"
The shape: five SSH auth failures → permanent ban; ten POP/IMAP failures (mail clients retry aggressively after a password change) → one-hour ban. LF_WEBMIN = "0" because Webmin isn't installed on cPanel — leaving it active wastes a log tail.
If you also run Imunify360, turn off the overlapping LFD counters per the CSF + Imunify360 coexistence guide before this step actively double-bans IPs.
SYN flood protection
SYNFLOOD = "0"
SYNFLOOD_RATE = "100/s"
SYNFLOOD_BURST = "150"
Leave SYNFLOOD off unless you're actively being attacked. The rule adds a per-packet check to every new connection and measurably hurts throughput at scale — turning it on by default is one of the most common reasons a "tuned" CSF box runs slower than an untuned one.
Country blocks (optional)
CC_DENY = "CN,RU,KP,IR"
CC_DENY_PORTS = "22,2083,2087"
Country blocks belong on management ports, not on public web ports. Blocking China and Russia on port 22 cuts SSH brute-force log volume by 80%+ on most hosts; blocking them on port 80 just stops their customers from reaching your customers' sites.
CSF downloads MaxMind GeoLite2 data — set CC_SRC = "1" and provide a free MaxMind license key in MM_LICENSE_KEY or country lookups will silently stop working when the old hardcoded list goes stale.
Switch off TESTING and start LFD
After the config is sane, set the safety switch off:
TESTING = "0"
Then restart both daemons:
csf -r
systemctl restart lfd
systemctl enable lfd
csf -r rebuilds and reloads the iptables ruleset; the lfd restart picks up the new thresholds. Verify both are alive:
csf -l | head
systemctl status lfd --no-pager
You should see the INPUT chain populated and lfd running with no errors in /var/log/lfd.log.
Day-to-day operations
The commands you'll use weekly:
csf -d 1.2.3.4 "scraping wp-login" # permanent deny with comment
csf -dr 1.2.3.4 # remove a deny
csf -tf 1.2.3.4 # remove from temp ban (the common one)
csf -a 1.2.3.4 "office IP" # permanent allow
csf -g 1.2.3.4 # show every rule and log line for this IP
csf -t # list temporary bans with time remaining
csf -g is the one to remember during support tickets — it returns every reason CSF has logged about an IP, which usually answers "why was my customer blocked?" in one command.
When CSF is behind Cloudflare
If your sites front through Cloudflare or another reverse proxy, CSF sees the proxy IP for every request — LFD will ban the proxy after a single attacker hits your wp-login enough times. The fix is the same as for Imunify360 behind Cloudflare: install mod_remoteip and restore the real client IP at the Apache layer before LFD reads the logs.
For pure-CSF setups, also add Cloudflare's published IP ranges to /etc/csf/csf.allow so even an accidental ban can't take your sites offline.
FAQ
Is ConfigServer CSF free?+
Does CSF work on AlmaLinux 9 and Ubuntu 24.04?+
Can I run CSF and firewalld at the same time?+
How do I stop CSF locking me out during the first boot?+
Should I disable cPHulk if I install CSF?+
Does CSF replace Imunify360?+
Next steps
- Layer in application-level protection: Install Imunify360 on cPanel
- Stop CSF and Imunify double-banning the same IP: Imunify360 + CSF coexistence
- Tune the other auth-failure layer: WHM cPHulk tuning
If you're standing CSF up on a new box, the cPanel VPS install guide covers the prerequisites that make all of the above behave predictably — and the cPanel license page handles same-day activation if you haven't sorted the WHM licence yet.