Panellicense

CSF country blocking with CC_DENY and CC_ALLOW on cPanel

CC_DENY drops entire countries at the firewall — done right with ipset it costs almost nothing per packet, done wrong it bloats iptables and adds 20ms to every connection.

7 min readUpdated 2026-05-23csf · country-blocking · cc_deny · ipset
schema: HowToschema: FAQPage

ConfigServer CSF has shipped country-level blocking for over a decade, but most operators still configure it the way the wiki showed in 2014 — flat iptables rules, MaxMind lookups on every restart, and a CC_DENY list that grew until csf -r took six minutes. With ipset support and DB-IP as a free MaxMind alternative, modern CSF can drop traffic from any country with one ipset match per packet — single-digit microseconds, no rule explosion.

This article is for the operator who has already followed Install ConfigServer CSF on cPanel and tune the defaults and now wants to block half a dozen high-abuse countries from SSH and SMTP without breaking real visitors. It assumes CSF is running and you have root.

CC_DENY versus CC_ALLOW — pick the right mode first

The two settings are not symmetric. They behave very differently and most country-blocking disasters come from confusing them.

  • CC_DENY = "CN,RU,KP" — blocks all incoming traffic from listed countries on every port. Everything else is allowed (subject to your other rules). This is the right setting for a host that takes traffic from the whole world but wants a deny list.
  • CC_ALLOW = "US,GB,DE" — allows traffic from listed countries and blocks everything else. This is the right setting only if you are running a regional service and have a hard requirement for geo-restriction. It will silently break customers who travel.
  • CC_ALLOW_FILTER = "US,GB" — allows the listed countries only on the ports listed in CC_ALLOW_PORTS and CC_ALLOW_PORTS_UDP. This is what most operators actually want when they say "allow list": lock SSH and webmail to a country list while leaving HTTP and SMTP open to the world.

The combination of CC_DENY plus CC_ALLOW_FILTER covers 95% of real deployments — block egregious abuse globally, then restrict admin ports to known geographies. Don't use CC_ALLOW alone unless you've audited every port.

Enable ipset before turning any of this on

This is the single most important change. With the default IPSET = 0, CSF expands every country into thousands of individual iptables rules — China alone is about 10,000 CIDRs, and that's before you add Russia. A flat ruleset that large adds 10-30ms per new connection on a busy server and makes csf -r painfully slow.

With IPSET = 1, CSF stores the country blocklist in a kernel ipset hash table. Lookups are O(1), restart is instant, and the iptables rule count stays in single digits.

sed -i 's/^IPSET = .*/IPSET = "1"/' /etc/csf/csf.conf
csf -r

Verify after restart:

ipset list -n | grep -i cc_
# cc_deny
# cc_allow_filter

If those tables don't appear, ipset isn't loaded — yum install ipset on AlmaLinux/RHEL, apt install ipset on Debian/Ubuntu, then csf -r again.

Pick a country IP database

CSF has shipped MaxMind GeoLite2 as the default source, but MaxMind closed free public downloads in 2020 and now requires a free signup plus a licence key. Most operators have migrated to DB-IP, which CSF supports out of the box and which does not require credentials.

grep -E '^CC_SRC|^MM_LICENSE_KEY' /etc/csf/csf.conf
# CC_SRC = "2"   # 1 = MaxMind, 2 = DB-IP, 3 = ip2location

DB-IP refreshes monthly and is accurate enough for country-level blocking — it is not good enough for city-level analytics, but that is not what CSF is doing. Switch to it unless you already have a paid MaxMind subscription.

Configure CC_DENY for a global drop list

Edit /etc/csf/csf.conf and set the country codes you want to block. Use ISO 3166-1 alpha-2 codes, comma-separated, no spaces:

sed -i 's/^CC_DENY = .*/CC_DENY = "CN,RU,KP,IR"/' /etc/csf/csf.conf
sed -i 's/^CC_INTERVAL = .*/CC_INTERVAL = "7"/' /etc/csf/csf.conf
csf -r

CC_INTERVAL is how often (in days) CSF re-downloads the country IP database. The default is 7 — leave it. Lower than that wastes bandwidth; higher than 14 means new IP allocations slip through.

After restart, check the ipset is populated:

ipset list cc_deny | head -5
# Name: cc_deny
# Type: hash:net
# Header: family inet hashsize 32768 maxelem 65536
# Size in memory: 1234567
# References: 1

The size in memory is roughly 50MB for a full CN+RU+KP+IR drop — trivial on any modern server.

Lock SSH and webmail to known countries

Use CC_ALLOW_FILTER for the allow-list-on-specific-ports pattern. Add SSH (22), Webmail (2096), and WHM (2087) to the allow ports, then list the countries that can reach those ports:

sed -i 's/^CC_ALLOW_FILTER = .*/CC_ALLOW_FILTER = "US,GB,DE,NL"/' /etc/csf/csf.conf
sed -i 's/^CC_ALLOW_PORTS = .*/CC_ALLOW_PORTS = "22,2087,2096,2083"/' /etc/csf/csf.conf
csf -r

Now port 80 and 25 stay open to the world (minus CC_DENY), but a Chinese IP cannot even open a TCP connection to SSH. This is significantly stronger than fail2ban or cphulkd tuning, because the packet never reaches sshd.

Allow specific IPs through the country block

Country blocks are coarse. You will inevitably need to let specific IPs through — a vendor in a blocked country, a CDN PoP, a monitoring probe. Use csf.allow for whitelists that override CC_DENY:

echo "tcp|in|d=22|s=203.0.113.42 # vendor jumpbox in HK" >> /etc/csf/csf.allow
csf -r

The advanced syntax (tcp|in|d=22|s=...) restricts the allow to a specific protocol, direction, and port — without it, you'd open the entire vendor IP to every service on the box.

Watch what gets blocked before tightening

CSF logs every country drop to /var/log/lfd.log. Tail it for a few hours after enabling CC_DENY to confirm you're not blocking legitimate traffic — particularly transactional email senders and customer support contacts.

grep -i "country code" /var/log/lfd.log | tail -50

You will see entries like (CN/China) detected, blocked port 80 dport=80. If you see traffic from a country you didn't intend to block, narrow the list — country blocking is a coarse tool and a single misconfigured ISP can route through a country you wouldn't expect.

For application-layer protection that complements packet drops, pair this with Imunify360 behind Cloudflare so HTTP traffic is also filtered after Cloudflare hands off the real client IP. The two layers do not overlap — CSF blocks at L3/L4, Imunify360 at L7.

Next steps

Does CC_DENY block outgoing traffic to those countries?+
No, CC_DENY only filters incoming connections. To block outgoing traffic to a country, use CC_DENY_PORTS or set CC_DROP_LOOKUP_OUT. Most operators leave outbound alone — blocking it breaks legitimate updates and DNS lookups.
How often does CSF refresh the country IP database?+
Every CC_INTERVAL days, default 7. The download runs in the background via lfd's regular cron and does not interrupt traffic. If you're seeing stale blocks, check lfd.log for the last successful update.
Can I use CC_DENY without ipset enabled?+
Technically yes, but you shouldn't. Without IPSET = 1, CSF expands every country into thousands of iptables rules, which slows down every new connection and makes csf -r take minutes. Always enable ipset before adding more than one country to CC_DENY.
Why is my country blocklist not working after csf -r?+
Check three things in order: ipset list cc_deny is populated, /etc/csf/csf.conf has the correct CC_SRC for your country database, and /var/log/lfd.log shows a successful country file download. If the ipset is empty, the database download failed — usually a DNS or outbound HTTPS problem.
Does CC_DENY work with IPv6?+
Yes if IPV6 = 1 and the country source includes IPv6 ranges. DB-IP includes IPv6, MaxMind GeoLite2 includes IPv6. CSF maintains separate ipsets cc_deny and cc_deny6, both populated automatically on restart.
Switch in an afternoon

Switch from your current reseller — free.

We migrate active cPanel, Plesk, LiteSpeed and CloudLinux licenses from any reseller. We prorate the first month so you never pay twice, and your customers see zero downtime during the swap.