2026年11月13日
2026年11月13日
Restrict the WordPress Login Page (wp-login.php) by IP Address
This article is a localized edition of the Japanese original. Read the Japanese original
The WordPress login page (wp-login.php) is open to anyone, which makes it a target for attacks that try passwords by brute force. If you allow it only from specific IP addresses, login attempts from anywhere else are stopped at the web server, before WordPress even runs.
This article shows how to restrict wp-login.php by IP address on Apache (.htaccess) and Nginx. A mistake can lock you out too, so before you start, make sure you can restore the configuration file through FTP/SFTP, SSH or your hosting company's file manager.
When this works well
- The people who log in to the admin connect from fixed IP addresses (an office static IP, a VPN exit, etc.)
- Only the site operators log in; outside people don't log in to register as members or to comment
Besides logging in, wp-login.php handles logging out, password resets, user registration and entering the password for password-protected pages. Once restricted, none of these work from addresses you haven't allowed.
Step 1: Find your IP address
Run the following on the computer you use for the admin. You can also check with a website that shows your IP address in the browser.
# IPv4 address
curl -s https://api.ipify.org
# Address when connecting over IPv6 (returns IPv6 on IPv6-capable connections)
curl -s https://api64.ipify.org
If your connection supports IPv6, you may reach the server over IPv6. In that case, allow your IPv6 address (or prefix) as well.
Step 2 (Apache): Restrict wp-login.php in .htaccess
Add the following to the .htaccess file in the WordPress root (where wp-login.php is). Put it outside (above) the # BEGIN WordPress ... # END WordPress block that WordPress rewrites.
# Allow wp-login.php only from the allowed IP addresses (Apache 2.4)
<Files wp-login.php>
Require ip 203.0.113.10 198.51.100.0/24 2001:db8:1234::/48
</Files>
- List IP addresses after
Require ip, separated by spaces. CIDR notation such as198.51.100.0/24and IPv6 addresses also work. Replace the sample values with your own. - In
.htaccess, you cannot put a comment at the end of a line. If you writeRequire ip 203.0.113.10 # home, everything after#is read as values too and you get a 500 error. Put comments on their own line starting with#. <Directory>cannot be used inside.htaccess(it is for the main server configuration). Using it causes a 500 error.Order Deny,Allow,Deny from allandAllow from …are Apache 2.2 syntax. On Apache 2.4 they only work when the compatibility module is enabled, and mixing them withRequireeasily produces unexpected results, so useRequirefor anything new.- To use
Requirein.htaccess, the server must allowAllowOverride AuthConfig(orAll). Otherwise you get a 500 error.
To restrict the admin area (/wp-admin/) as well, put a separate .htaccess in the wp-admin folder. You need to exclude admin-ajax.php and admin-post.php, which front-end features use; how to write that is covered in "How to restrict wp-admin by IP with .htaccess".
Step 2 (Nginx): Restrict wp-login.php with a location block
Nginx doesn't read .htaccess, so write this in the server configuration (on Ubuntu, the site's file in /etc/nginx/sites-available/). location = /wp-login.php is an exact match, so requests matching it never reach the usual location ~ \.php$ block that handles PHP. That is why you also need the PHP handling inside this block.
location = /wp-login.php {
allow 203.0.113.10;
allow 198.51.100.0/24;
allow 2001:db8:1234::/48;
deny all;
# Use the same PHP settings as your existing location ~ \.php$ (example: PHP 8.3 on Ubuntu)
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
allowanddenyare checked from top to bottom, and the first matching line wins. Putdeny all;last.- Match the
fastcgi_passvalue (socket path and PHP version) to what is in thelocation ~ \.php$block of the same file. If you forget the PHP settings,wp-login.phpmay be downloaded as a file instead of being executed.
After editing, test the syntax and then reload.
sudo nginx -t
sudo systemctl reload nginx
Combining this with Basic authentication on Nginx is covered in "How to combine Basic authentication and IP restriction in Nginx".
Step 3: Check that it works
Open the page from a connection you haven't allowed (such as a phone on mobile data) and confirm you get 403 Forbidden.
# Run from a non-allowed connection: should return 403
curl -I https://example.com/wp-login.php
From an allowed connection, confirm in the browser that the login screen appears as usual and that you can log in.
Check xmlrpc.php too
WordPress has xmlrpc.php, which accepts a username and password without going through wp-login.php. Restricting only wp-login.php does not stop password attempts against it.
If you don't use XML-RPC, block it as shown below. If you use Jetpack or an external app that posts via XML-RPC, don't block it, because they would stop working.
# .htaccess (Apache 2.4)
<Files xmlrpc.php>
Require all denied
</Files>
# Nginx
location = /xmlrpc.php {
deny all;
}
If you use Cloudflare or another proxy
With Cloudflare or a load balancer in front, the web server sees the proxy's IP address as the client. Allowing your own IP address then never matches. You need to restore the original client IP address from the header the proxy sends.
- Apache: use mod_remoteip and, in the server configuration, set
RemoteIPHeader CF-Connecting-IPand list Cloudflare's IP ranges withRemoteIPTrustedProxy - Nginx: list Cloudflare's IP ranges with
set_real_ip_fromand addreal_ip_header CF-Connecting-IP;
Cloudflare publishes its IP ranges on its official page. On shared hosting you usually can't change these settings yourself, so restricting /wp-login.php with Cloudflare's own access controls (such as WAF custom rules) is the practical option.
If your IP address changes
Home and mobile connections change IP addresses. You would be locked out every time it changes, so IP restriction is a poor fit. Consider these instead.
- Put Basic authentication on the login page (a second ID and password, independent of IP address). See "How to double-protect the WordPress admin with Basic authentication"
- Set up a VPN and allow only the VPN exit's IP address
- Limit login attempts. See "How to limit login attempts in WordPress"
- Add two-factor authentication
Undoing a lockout
If your IP address changed or a typo causes a 403 or 500, undo the change as follows. Changing your WordPress password won't help, because the request is stopped at the web server.
- Apache: open
.htaccessvia FTP/SFTP or the file manager and delete the<Files wp-login.php>...</Files>block you added - Nginx: log in to the server over SSH, delete the
location = /wp-login.phpblock you added, runsudo nginx -tand thensudo systemctl reload nginx
Once you can log in, check your current IP address, fix the allowed values and put the restriction back.
Summary
- On Apache 2.4, add
<Files wp-login.php>withRequire ipto the root.htaccess(no comments at the end of lines, no<Directory>) - On Nginx, add
allow/denyand the PHP settings tolocation = /wp-login.php, test withnginx -t, then reload xmlrpc.phpis a separate entry point; block it if you don't use it- Behind Cloudflare or another proxy, you must restore the original client IP address
- If you get locked out, remove the added settings via FTP or SSH
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)