How to Block IP Addresses in Apache

How to block IP addresses in Apache

Every time I check the access logs on a server I manage, I find at least a few IPs hammering the site with malicious requests — brute-force login attempts, vulnerability scanners, or plain old spam bots. Blocking those IPs at the Apache level is one of the simplest, most direct defenses I use. Here’s exactly how I do it.

Why I Block IPs at the Web Server Level

  • Stops abuse before it reaches your application — blocking at Apache is more efficient than letting a malicious request hit your PHP or database layer.
  • Reduces server load from bots and scrapers.
  • Prevents brute-force attacks on login pages.
  • Complements a firewall — Apache-level blocking is useful when you need per-site or per-directory rules that a general firewall can’t easily express.

Prerequisites

  • Root or sudo access to the server
  • Apache 2.4+ (I’ll use the modern Require syntax, not the deprecated Order/Allow/Deny from 2.2)
  • Knowledge of the specific IP address or range you want to block (found via your access logs)

Step 1: Identify the Offending IP

I usually find abusive IPs by scanning the access log:

sudo tail -1000 /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -20

This shows me the top 20 IPs by request count in the last 1000 log lines — a quick way to spot obvious abuse.

Step 2: Block a Single IP Address

Using the modern Apache 2.4 syntax, I add this inside the relevant <Directory>, <VirtualHost>, or global config block:

<RequireAll>
    Require all granted
    Require not ip 203.0.113.45
</RequireAll>

This grants access to everyone except the specified IP.

Step 3: Block Multiple IP Addresses

<RequireAll>
    Require all granted
    Require not ip 203.0.113.45
    Require not ip 198.51.100.22
    Require not ip 192.0.2.10
</RequireAll>

Step 4: Block an Entire IP Range (CIDR Notation)

If an attacker is rotating through IPs within a known subnet, I block the whole range:

<RequireAll>
    Require all granted
    Require not ip 203.0.113.0/24
</RequireAll>

That blocks the entire 203.0.113.0 through 203.0.113.255 range.

Step 5: Blocking IPs for a Specific Directory

Sometimes I only need to block an IP from a specific area, like the admin login page, rather than the whole site:

<Directory /var/www/example.com/wp-admin>
    <RequireAll>
        Require all granted
        Require not ip 203.0.113.45
    </RequireAll>
</Directory>

Step 6: Using .htaccess (When You Don’t Have Access to the Main Config)

On shared hosting, or when AllowOverride is enabled, I use .htaccess in the target directory:

<RequireAll>
    Require all granted
    Require not ip 203.0.113.45
</RequireAll>

Keep in mind .htaccess is read on every request, so it’s slightly less efficient than main config changes — I only use it when I have no other choice.

Step 7: Whitelisting Instead of Blacklisting

For sensitive areas like an admin panel, I often flip the logic entirely and only allow specific trusted IPs:

<Directory /var/www/example.com/admin>
    <RequireAll>
        Require ip 203.0.113.100
        Require ip 198.51.100.50
    </RequireAll>
</Directory>

This denies everyone except the listed IPs — much stronger than trying to blacklist every possible attacker.

Step 8: Restart Apache and Test

sudo apachectl configtest
sudo systemctl restart apache2

I always test the block from the actual blocked IP (using a VPN, proxy, or asking a colleague) to confirm it returns a 403 Forbidden response rather than just assuming it worked.

Step 9: Automating IP Blocking With Fail2Ban

For repeated offenders, manually editing config files doesn’t scale. I set up Fail2Ban to automatically detect and block abusive IPs based on log patterns:

sudo apt install fail2ban

I configure a jail specifically for Apache auth failures in /etc/fail2ban/jail.local:

[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/error.log
maxretry = 5
bantime = 3600

This automatically bans an IP for one hour after 5 failed authentication attempts, without me needing to manually intervene.

Real-World Use Case

On a client’s WordPress site experiencing constant brute-force attempts against wp-login.php, I combined a directory-level IP whitelist for the admin area (limited to their office and home IPs) with Fail2Ban monitoring general login attempts. Failed login attempts dropped to zero within a day since the attacker’s requests were rejected before ever reaching WordPress.

Common Mistakes to Avoid

  • Using the deprecated Apache 2.2 syntax (Order Deny,Allow) on a 2.4 server — it still works in compatibility mode but isn’t the modern approach and can behave unexpectedly.
  • Blocking your own IP by accident — always double-check the IP before applying, especially with dynamic home IPs that can change.
  • Relying solely on IP blocking for serious threats — sophisticated attackers rotate IPs, so combine this with rate limiting and a WAF.
  • Forgetting to restart Apache after editing the main config (not needed for .htaccess changes, which apply immediately).

Troubleshooting Tips

If a block doesn’t seem to be working, check for conflicting rules elsewhere in your configuration — a <Directory> block lower in the file, or a .htaccess file, might be overriding your intended rule. Also confirm AllowOverride All (or at least AllowOverride Limit) is set if you’re relying on .htaccess for access control.

Security and Performance Best Practices

  • Combine IP blocking with rate limiting (mod_ratelimit or mod_evasive) for a stronger defense against automated abuse.
  • Use Fail2Ban for dynamic, automated blocking rather than manually maintaining a static list.
  • Regularly review and prune your blocklist — permanently blocking every offending IP forever leads to a bloated, hard-to-maintain configuration.
  • Consider blocking at the firewall level (iptables/ufw) for very high-volume attacks, since that’s more efficient than making Apache process the request at all.

Frequently Asked Questions

What’s the difference between blocking at the Apache level versus the firewall level? Firewall blocking (iptables/ufw) rejects traffic before it even reaches Apache, which is more efficient for high-volume attacks. Apache-level blocking is useful for per-directory or per-site rules that a general firewall can’t easily express.

Can I block a country instead of individual IPs? Yes, using mod_geoip or mod_geoip2, you can block traffic by country, though this requires installing and configuring a GeoIP database.

Will blocking an IP address affect SEO? No, as long as you’re not accidentally blocking legitimate search engine crawler IPs. Always double-check the IP you’re blocking isn’t a known search engine bot.

Is Fail2Ban better than manually blocking IPs? For ongoing, automated protection against brute-force attempts, yes. Manual blocking is better suited for specific known offenders you’ve identified through log analysis.

Summary and Key Takeaways

Blocking IP addresses in Apache is a quick, effective way to stop known abusive traffic, whether through a single Require not ip rule, a CIDR range block, or a full IP whitelist for sensitive directories. For ongoing protection, pair manual blocking with Fail2Ban to automatically catch and ban repeat offenders without constant manual intervention.

References

Total
1
Shares
Leave a Reply
Previous Post
How to enable mod_security for Apache

How to Enable mod_security for Apache

Next Post
How to set up HTTPS and SSL certificates for Apache

How to Set Up HTTPS and SSL Certificates for Apache

Related Posts