Restricting WordPress access by IP address means only approved addresses can load wp-admin and wp-login.php, while everyone else gets a 403 before PHP ever runs. On Apache you do it with an .htaccess file; on Nginx you do it with allow and deny directives inside a location block. Both take about five minutes, and both can lock you out of your own site if you skip the details below.
What IP Restriction Blocks and What It Leaves Open
An IP rule at the web server level rejects the request before WordPress loads, so brute-force bots burn zero PHP workers and zero database queries. On a site under a sustained login attack, that alone can cut CPU usage dramatically.
What it does not do is protect the rest of your site. Your XML-RPC endpoint, REST API routes, and any public form remain reachable unless you restrict those separately. Think of an IP allowlist as one layer inside a broader WordPress hosting security setup, not a replacement for strong passwords or two-factor authentication.
Find Your Real IP Address First
Before you edit anything, confirm the address you are allowlisting. Search Google for “what is my IP” or open a service like WhatIsMyIP and note the result. Two things worth checking:
- IPv4 vs IPv6: many home connections hand out both, and your browser may use the IPv6 address even though you only allowlisted the IPv4 one.
- Static vs dynamic: residential ISPs rotate addresses on reboot, sometimes every few days.
- Office ranges: business connections often use a block such as 198.51.100.0/24, which you can allow in one line.
If you are behind a VPN or a corporate proxy, the address you see is the exit node, and it changes whenever you switch servers.
Restricting wp-admin Using .htaccess on Apache
Apache reads .htaccess files per directory, so you have two natural places to add rules: a new file inside /wp-admin/, and the root .htaccess for the login page. Apache 2.4 (what nearly every host runs in 2026) uses the Require syntax documented in the Apache access control guide.
Apache 2.4 Syntax
Create /wp-admin/.htaccess and add:
<RequireAny>
Require ip 203.0.113.45
Require ip 198.51.100.0/24
</RequireAny>
Then protect the login file from the root .htaccess, above the WordPress rewrite block:
<Files "wp-login.php">
Require ip 203.0.113.45
</Files>
Older Apache 2.2 Syntax
Some legacy servers still expect the old directives. If Require throws a 500 error, use this instead:
Order deny,allow
Deny from all
Allow from 203.0.113.45
Mixing both syntaxes in one file is what usually causes that 500, so pick one and stay consistent.
Leave admin-ajax.php Reachable
Plenty of front-end features (add-to-cart, search filters, form submissions) call /wp-admin/admin-ajax.php from logged-out visitors. Blocking the whole directory breaks them silently. Add this exception inside the wp-admin .htaccess file:
For a closer look at this topic, see our guide: Optimizing the WordPress REST API for Headless Applications.
<Files "admin-ajax.php">
Require all granted
</Files>
The same applies to admin-post.php if any plugin uses it for public form handling.
Blocking Access by IP in Nginx
Nginx ignores .htaccess entirely, so the rules live in your server block and need a config reload to take effect. The ngx_http_access_module handles this with two directives, evaluated in order:
location ^~ /wp-admin/ {
allow 203.0.113.45;
allow 198.51.100.0/24;
deny all;
try_files $uri $uri/ /index.php?$args;
}
location = /wp-admin/admin-ajax.php {
allow all;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location = /wp-login.php {
allow 203.0.113.45;
deny all;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
Test with nginx -t before you reload. A typo in a location block takes the entire server down, not just one site, which is why I keep a second SSH session open while editing.
Blocking One Attacker Instead of Allowlisting Everyone
Sometimes you do not want an allowlist, you just want one abusive address gone. In Nginx, drop a single line in the server block: deny 203.0.113.99;. In an .htaccess file on Apache 2.4:
<RequireAll>
Require all granted
Require not ip 203.0.113.99
</RequireAll>
Be realistic about the payoff. Credential-stuffing botnets rotate through thousands of residential proxies, so blocking individual addresses is cleanup work, not defense. An allowlist on the admin path holds up far better.
The Proxy Problem That Blocks Everyone
This is the part most tutorials skip. If your site sits behind Cloudflare, a load balancer, or any CDN edge network, the server sees the proxy’s IP on every request, not the visitor’s. Your allowlist matches nobody and you get a 403 on your own login page.
The fix is restoring the real client IP before the access rules run:
- Nginx: use
set_real_ip_fromwith the proxy ranges plusreal_ip_header CF-Connecting-IP;. - Apache: enable
mod_remoteipand setRemoteIPHeader CF-Connecting-IP. - Either: apply the IP rule at the CDN’s own firewall instead of the origin server.
Managed platforms usually handle this at the stack level, and you can confirm which address is actually arriving by checking the access log or your hosting analytics dashboard.
When Your IP Changes Every Few Days
A hard allowlist is impractical on a dynamic residential connection, and it is worse for teams. Editorial sites with a dozen contributors, like the ones we host on WordPress magazine hosting, or course platforms where instructors log in from anywhere, need something more forgiving. Practical alternatives:
- Allow a small static VPN exit IP and route admin sessions through it, which costs a few dollars a month.
- Layer HTTP basic auth on wp-login.php as a second password prompt instead of a hard IP block.
- Use a security plugin’s rate limiting so repeated failures get throttled rather than everyone being blocked by default.
- Allow a whole ISP range such as a /24, which is looser but survives address rotation.
For membership and WordPress course hosting setups, remember that students often hold a subscriber role and hit /wp-admin/profile.php. Blocking the directory outright can break their account pages.
Testing Without Locking Yourself Out
Save a copy of the original file before you touch it, and keep SFTP or SSH access ready so you can revert in seconds. Load the login page in a private window and from a phone on mobile data: you should see the 403 on the phone and normal access from your allowlisted network.
If you get an unexpected 500 rather than a 403, the syntax is wrong, and the details land in your server log. Our walkthrough on monitoring WordPress error logs on the server covers where to look. Teams running a Bedrock-style stack should keep these rules in version control with the rest of the server config, so a deploy never quietly wipes them.
Frequently Asked Questions
How Do I Restrict Website Access to Specific IP Addresses?
Add an allow rule for your address and a deny-all rule beneath it, either in an .htaccess file on Apache or a location block on Nginx. Apache 2.4 uses Require ip 203.0.113.45, while Nginx uses allow 203.0.113.45; followed by deny all;. Everyone outside the list receives a 403 Forbidden response.
How Do I Block an IP Address Using .htaccess?
One line does it on Apache 2.4: Require not ip 203.0.113.99 wrapped in a RequireAll block alongside Require all granted. On Apache 2.2 the equivalent is Deny from 203.0.113.99 after Order allow,deny. Changes apply immediately with no restart, since Apache reads the .htaccess file on every request.
How Do I Block an IP Address From My WordPress Website?
You have three options: a server-level rule, a firewall plugin such as Wordfence, or a block at your CDN. Server-level rules are fastest because the request never reaches PHP, but plugin blocks are easier to manage if you are blocking dozens of addresses and want a log of what was stopped.
How Do I Block an IP in Nginx?
Put deny 203.0.113.99; inside the relevant server or location block, then run nginx -t and reload with systemctl reload nginx. Nginx evaluates allow and deny directives top to bottom and stops at the first match, so order matters more than it does in Apache.
Get WordPress Hosting That Handles the Hard Parts
Server-level access rules, real client IP forwarding, and a managed firewall come configured on every WebVibo plan, so you are not editing config files at midnight after a lockout. Start a plan or ask our WordPress specialists to review your current login hardening.
[…] rules, server-level denies or admin allowlists, work at the prefix level. Our walkthrough on restricting WordPress access by IP in .htaccess or Nginx covers the syntax, and the same logic applies to IPv6 ranges written in CIDR […]
[…] at wp-origin.example.net. Blocking everything except the proxy IPs, as described in our guide to restricting WordPress access by IP address, is the clean […]