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 as 198.51.100.0/24 and 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 write Require 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 all and Allow from … are Apache 2.2 syntax. On Apache 2.4 they only work when the compatibility module is enabled, and mixing them with Require easily produces unexpected results, so use Require for anything new.
  • To use Require in .htaccess, the server must allow AllowOverride AuthConfig (or All). 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;
}
  • allow and deny are checked from top to bottom, and the first matching line wins. Put deny all; last.
  • Match the fastcgi_pass value (socket path and PHP version) to what is in the location ~ \.php$ block of the same file. If you forget the PHP settings, wp-login.php may 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-IP and list Cloudflare's IP ranges with RemoteIPTrustedProxy
  • Nginx: list Cloudflare's IP ranges with set_real_ip_from and add real_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.

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 .htaccess via 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.php block you added, run sudo nginx -t and then sudo 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> with Require ip to the root .htaccess (no comments at the end of lines, no <Directory>)
  • On Nginx, add allow/deny and the PHP settings to location = /wp-login.php, test with nginx -t, then reload
  • xmlrpc.php is 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)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲