2026年11月12日

2026年11月12日

Restrict wp-admin by IP with .htaccess (Apache 2.4, keep admin-ajax)

This article is a localized edition of the Japanese original. Read the Japanese original

If you allow the WordPress admin area (/wp-admin/) to open only from specific IP addresses, login attempts from anywhere else are stopped at the web server before they reach WordPress. This article shows how to set up IP address restrictions with Apache's .htaccess, together with the exceptions you need so the public side of your site keeps working.

A mistake in the configuration can lock you out of the admin area too. Before you start, make sure you can edit .htaccess over FTP, SFTP or your hosting company's file manager.

Where this method works

  • Your web server is Apache (or LiteSpeed, which also reads .htaccess). Nginx does not read .htaccess, so this method has no effect there.
  • To use Require in .htaccess, the server must allow AllowOverride AuthConfig (or All). If it is not allowed, the directive causes a 500 error. Most shared hosting plans allow it.
  • Your connection's IP address does not change (a static IP, an office line, a VPN, and so on). On connections whose IP address changes, such as most home internet lines, you get locked out every time it changes (see below).

Step 1: Check your IP address

On the computer you use to open the admin area, run the following. You can also open a website that shows your IP address in the browser.

# IPv4 address
curl -s https://api.ipify.org

# Check for IPv6 (returns an IPv6 address if your connection supports IPv6)
curl -s https://api64.ipify.org

If your connection supports IPv6, you may reach the server over IPv6. In that case, you also need to allow your IPv6 address (or its prefix), or you will get a 403.

Step 2: Create wp-admin/.htaccess and restrict IP addresses

Create a .htaccess file inside the wp-admin folder. (WordPress core does not ship this file. If one already exists, check its contents before adding to it.) The Apache 2.4 syntax looks like this:

# wp-admin/.htaccess
# Allowed IP addresses (replace the example values with your own)
Require ip 203.0.113.10 198.51.100.0/24 2001:db8:1234::/48

# Files that the public side of the site also calls must stay open to everyone
<Files admin-ajax.php>
    Require all granted
</Files>
<Files admin-post.php>
    Require all granted
</Files>
  • List IP addresses after Require ip, separated by spaces. CIDR notation such as 198.51.100.0/24 and IPv6 addresses also work.
  • admin-ajax.php is also called by features on the public side of the site, such as contact form submissions, filtered search and WooCommerce cart updates. If you restrict it, those features stop working.
  • admin-post.php is sometimes used to receive form submissions from visitors who are not logged in (for example, plugins that use hooks starting with admin_post_nopriv_). Even if you do not use it, allowing it rarely causes problems.

The Order Deny,Allow, Deny from all and Allow from … syntax belongs to Apache 2.2. In Apache 2.4 it works only when the compatibility module (mod_access_compat) is enabled, and mixing it with Require easily leads to unexpected results, so use Require for new rules.

Step 3: Restrict wp-login.php as well

wp-login.php sits in the WordPress root, not in the wp-admin folder, so the rules from step 2 do not protect it. Add the following to the root .htaccess. Put it outside (above) the # BEGIN WordPress to # END WordPress block, which WordPress rewrites.

# Root .htaccess (place above # BEGIN WordPress)
<Files wp-login.php>
    Require ip 203.0.113.10 198.51.100.0/24 2001:db8:1234::/48
</Files>

wp-login.php also handles "forgot password" requests and the password form for password-protected pages. On sites that use user registration or password-protected pages, keep in mind that outside visitors will no longer be able to use these.

Step 4: Test the setup

From a connection that is not allowed (for example, a smartphone on mobile data), confirm the following results.

# Should return 403 Forbidden
curl -I https://example.com/wp-admin/
curl -I https://example.com/wp-login.php

# Should NOT return 403 (without parameters, WordPress returns 400)
curl -I https://example.com/wp-admin/admin-ajax.php

From an allowed connection, open /wp-admin/ in your browser and confirm that the login screen appears as usual. Also try the features on the public side that use admin-ajax.php, such as contact forms and search.

If you use Cloudflare or a reverse proxy

When traffic goes through Cloudflare or a load balancer, Apache sees the IP address of the proxy as the client. In that state, specifying your own IP address in Require ip never matches. You need Apache's mod_remoteip to restore the original client address from the header the proxy sends (CF-Connecting-IP for Cloudflare). On shared hosting, support for this differs between hosting companies, so check your control panel's documentation or support pages.

If you use Cloudflare, you can also restrict /wp-admin/ and /wp-login.php with Cloudflare's own access controls (WAF custom rules or Cloudflare Access).

If your IP address changes

If your connection's IP address changes, the following approaches suit you better than IP restrictions:

  • Add Basic authentication to the admin area (a second username and password that works regardless of IP address)
  • Set up a VPN and allow only the VPN's exit IP address
  • Limit login attempts or add two-factor authentication

Some hosting companies offer a control-panel feature such as "restrict admin access from outside the country". If you combine it with .htaccess rules, it becomes hard to tell which one blocked you, so keep a record of where you added restrictions.

How to recover if you lock yourself out

If your IP address changes or a typo causes a 403 or 500 error, do one of the following over FTP, SFTP or the file manager:

  • Rename wp-admin/.htaccess to something like htaccess-off (this removes the restriction)
  • Delete the <Files wp-login.php> block you added to the root .htaccess

Once you are back in the admin area, check your current IP address, update Require ip, and rename the file back.

Summary

  • In wp-admin/.htaccess, list the allowed IP addresses with Require ip, and exclude admin-ajax.php and admin-post.php with Require all granted
  • Restrict wp-login.php in the root .htaccess with a <Files wp-login.php> block placed outside # BEGIN WordPress
  • In Apache 2.4, write rules with Require, not Order, Allow and Deny
  • With IPv6, proxies such as Cloudflare, or connections whose IP address changes, review the values you allow or choose another method
  • If you get locked out, rename .htaccess over FTP or similar to lift the restriction

Related articles

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

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