How to block an IP with .htaccess?

The .htaccess file is one of the most powerful tools available to web server administrators on Apache servers. It allows fine-grained control over access to your site without touching the main server configuration. Among its most common uses: blocking unwanted IP addresses — malicious bots, scrapers, attackers, or simply visitors you want to restrict. Here are all the available methods, from the simplest to the most advanced.

Prerequisites: enabling mod_authz_host

IP access control directives in .htaccess require the Apache mod_authz_host module to be enabled on your server. This is the default on virtually all shared hosting environments and modern Apache servers. If you manage your own server, check with:

apache2ctl -M | grep authz

Also note that the syntax differs slightly between Apache 2.2 and Apache 2.4 (the current version). Both syntaxes are shown below.

Blocking a single IP

This is the simplest case. Add these lines to your .htaccess file at the root of your site:

Apache 2.4 (current syntax):

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

Apache 2.2 (legacy syntax):

Order Allow,Deny
Allow from all
Deny from 123.456.789.0

Replace 123.456.789.0 with the IP address you want to block. The visitor will receive a 403 Forbidden error.

Blocking multiple IPs simultaneously

You can add as many addresses as needed, listed on the same line or on separate lines:

Apache 2.4:

<RequireAll>
  Require all granted
  Require not ip 123.456.789.0
  Require not ip 98.76.54.32
  Require not ip 11.22.33.44
</RequireAll>

Apache 2.2:

Order Allow,Deny
Allow from all
Deny from 123.456.789.0 98.76.54.32 11.22.33.44

Blocking an IP range (subnet)

If you need to block an entire block of addresses — for example all IPs from an ISP or a data centre — you can use CIDR notation or the subnet prefix:

By prefix (all IPs starting with 123.456.789):

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

By CIDR notation (/24 block, i.e. 256 addresses):

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

Other common mask examples:

  • /32 — a single IP
  • /24 — 256 addresses (e.g. 123.456.789.0 to 123.456.789.255)
  • /16 — 65,536 addresses (e.g. 123.456.0.0 to 123.456.255.255)
  • /8 — 16 million addresses (e.g. 123.0.0.0 to 123.255.255.255)

Blocking an IP on a specific directory

If you want to block an IP's access only to a subdirectory of your site (for example your admin area), place a .htaccess file in that specific directory with the blocking rule:

<RequireAll>
  Require all granted
  Require not ip 123.456.789.0
</RequireAll>
Good to know: you can also use <Directory>, <Files> or <Location> blocks directly in the httpd.conf or apache2.conf file for even more precise control — for example blocking an IP on a specific file only. This approach is more performant than .htaccess because it does not require Apache to read the file on every request.

Whitelisting: allowing only certain IPs

The reverse operation is also possible: only allowing access to one or more specific IPs and blocking everything else. This is particularly useful for protecting an admin interface:

Apache 2.4:

Require ip 123.456.789.0
Require ip 98.76.54.32

Apache 2.2:

Order Deny,Allow
Deny from all
Allow from 123.456.789.0
Allow from 98.76.54.32

Any unlisted IP will receive a 403 error. Note that if your IP is dynamic (it changes with each connection), this approach may lock you out — prefer a whitelist by subnet range instead.

Redirecting a blocked IP instead of returning a 403

Instead of displaying a raw 403 error, you can redirect blocked IPs to another page — a custom error page or even another URL:

RewriteEngine On
RewriteCond %{REMOTE_ADDR} ^123.456.789.0$
RewriteRule ^ /access-denied.html [R=302,L]

Note the escaping of dots with . in the RewriteCond condition — dots have special meaning in regular expressions (they match any character), so they must be escaped to match a literal dot only.

Blocking by User-Agent instead of IP

Some malicious bots or scrapers regularly change their IP but keep the same User-Agent. In this case, blocking by User-Agent is more effective:

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} ^(BadBot|EvilScraper|MaliciousSpider) [NC]
RewriteRule .* - [F,L]

The [F] flag returns a 403 error, [NC] makes the comparison case-insensitive. You can add as many User-Agents as needed by separating them with |.

Use caseRecommended methodKey syntax
Block a single IPRequire not ipRequire not ip 1.2.3.4
Block multiple IPsRequire not ip (multiple)Require not ip 1.2.3.4 (repeated)
Block a /24 rangeCIDR notationRequire not ip 1.2.3.0/24
Whitelist specific IPsWhitelistRequire ip 1.2.3.4
Redirect instead of blockingRewriteRuleRewriteCond %{REMOTE_ADDR}
Block by User-AgentRewriteRule + HTTP_USER_AGENTRewriteCond %{HTTP_USER_AGENT}
Good to know: changes made to the .htaccess file take effect immediately in Apache, without a server restart. However, a malformed .htaccess file can make your site entirely inaccessible with a 500 error. Always test your changes in a development environment or back up the original file before any production changes. If your site returns a 500 error after modification, immediately restore the previous version of the file.