2026年11月14日

2026年11月14日

Protect WordPress wp-admin: IP Restriction with .htaccess and Nginx

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

The WordPress admin area (/wp-admin/) and login screen (/wp-login.php) live at the same location on every site, which makes them a common target for brute-force login attacks. If you always do admin work from known places, limiting these two locations to specific IP addresses lets the web server refuse access from everywhere else.

This article shows how to put an IP restriction on the admin area and login screen with Apache's .htaccess and with Nginx. If you only want to refuse specific IP addresses, see "How to block specific IP addresses in WordPress".

When this method fits and when it doesn’t

Good fit Poor fit
Admin work happens only from fixed places such as the office or home You log in to the admin from many places, on the go or from a smartphone
You have a static IP address or a VPN with a fixed exit IP address Your only connection gets a new IP address every time
Only the site operators log in Visitors also register and log in (for example, a membership site)

If your IP address changes, you can instead add a second password layer to the admin area with Basic authentication. See "How to add Basic authentication to the WordPress admin".

Before you start

  1. Check your IP address: Find the IP address of the connection you use for admin work, for example by searching "what is my IP" in your browser. This article uses 203.0.113.10 as an example.
  2. Have a way back: If a mistake locks you out, you undo the settings over FTP/SFTP, SSH or your host's file manager. Make sure beforehand that you can edit WordPress files with one of these.
  3. Copy the original files: Save the .htaccess or configuration file you are about to edit as it is now.

On Apache

In Apache 2.4, you write access conditions with the Require directive. The old Order / Allow / Deny directives are Apache 2.2 syntax and only work in Apache 2.4 when the compatibility module (mod_access_compat) is loaded. Use Require for new rules.

Step 1: Restrict the login screen (wp-login.php)

Open the .htaccess file in the WordPress root (the directory that contains wp-config.php) and add the following at the top (above the # BEGIN WordPress line).

<Files "wp-login.php">
    Require ip 203.0.113.10
</Files>

To allow more than one IP address, add more Require ip lines (access is allowed if any one matches). You can also give a range such as 198.51.100.0/24.

WordPress may rewrite everything between # BEGIN WordPress and # END WordPress, so do not put your rules in that section.

Step 2: Restrict the admin area (wp-admin)

Create a new .htaccess file inside the wp-admin directory with the following content.

Require ip 203.0.113.10

# Allow everyone to reach admin-ajax.php, which front-end features use
<Files "admin-ajax.php">
    Require all granted
</Files>

wp-admin/admin-ajax.php is called not only from the admin but also by plugin and theme features on the public side of the site, such as form submissions and "load more" buttons. If you restrict it too, features that visitors use may stop working, so this one file stays open.

If a plugin sends forms to wp-admin/admin-post.php, that file needs to be allowed as well. In that case, replace the <Files> part with the following.

<FilesMatch "^(admin-ajax|admin-post)\.php$">
    Require all granted
</FilesMatch>

If Require in .htaccess has no effect

To use Require in .htaccess, the server configuration must include AuthConfig (or All) in AllowOverride. If it doesn't, you get a 500 error or the rules are ignored. If you run Apache yourself, for example on a VPS, you can put the same rules in the virtual host configuration with <Directory>. <Directory> is for server configuration files and cannot be used inside .htaccess.

On Nginx

Nginx has no .htaccess, so the rules go in the site's configuration file (the server block). The example below assumes a typical PHP-FPM setup on Ubuntu. Match the fastcgi_pass value and the file you include to your existing location ~ \.php$ settings.

# Login screen: allowed IP addresses only
location = /wp-login.php {
    allow 203.0.113.10;
    deny all;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

# Allow everyone to reach admin-ajax.php
location = /wp-admin/admin-ajax.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

# The rest of wp-admin: allowed IP addresses only
location ^~ /wp-admin/ {
    allow 203.0.113.10;
    deny all;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}
  • location = … is an exact match and takes priority over other location blocks.
  • ^~ is added to /wp-admin/ so that the location ~ \.php$ in the server block cannot match first and bypass the restriction. That is why the PHP handling is repeated inside it.
  • Nginx evaluates allow / deny from the top and uses the first one that matches.

After editing, check the syntax and then reload.

sudo nginx -t
sudo systemctl reload nginx

Step 3: Check that it works

Test from both an allowed connection and a connection that is not allowed (such as your phone's mobile data).

  1. From the allowed connection, confirm you can open the login screen and the admin area
  2. From a connection that is not allowed, open https://example.com/wp-login.php and https://example.com/wp-admin/ and confirm you get 403 Forbidden
  3. From a connection that is not allowed, open the public site and confirm features such as the contact form work as usual

To check from the command line (run this from a connection that is not allowed):

curl -sI https://example.com/wp-login.php | head -1
curl -sI https://example.com/wp-admin/ | head -1

If both return 403, the restriction is working.

Things to keep in mind

Effect on password-protected pages

On posts and pages protected with WordPress's "Password protected" option, the password a visitor enters is sent to wp-login.php?action=postpass. If you restrict the login screen by IP address, visitors who are not allowed cannot open password-protected pages. If you publish password-protected pages, restrict only the admin area and not the login screen, or consider another method such as Basic authentication.

For the same reason, an IP restriction on the login screen doesn't suit sites where visitors register or reset their passwords (such as membership sites).

If you use a CDN or proxy

When traffic goes through a CDN such as Cloudflare or a load balancer, the web server sees the CDN's or proxy's IP address as the client. In that state, you may be locked out even after allowing your own IP address, or the restriction may not work as intended. You need to configure the server to use the real client address, for example with mod_remoteip on Apache or real_ip_header on Nginx.

How to undo it if you are locked out

If you can no longer get into the admin, for example because your allowed IP address changed, undo the settings over FTP/SFTP or a file manager as follows.

  • Apache: Rename or delete wp-admin/.htaccess, and remove the <Files "wp-login.php"> part you added to the root .htaccess in step 1
  • Nginx: Remove the location blocks you added and reload the configuration (this is done over SSH)

For how to track down the cause of 403 errors, also see "How to fix a 403 error in the WordPress admin".

Don’t rely on IP restriction alone

IP restriction is one way to cut down attacks from places you haven't allowed. Combine it with strong administrator passwords, two-factor authentication, and keeping WordPress and plugins up to date.

Summary

  • If you always work from known places and IP addresses, you can limit which IP addresses reach wp-login.php and /wp-admin/.
  • On Apache 2.4, use Require ip. The login screen goes in a <Files> section in the root .htaccess, and the admin area in wp-admin/.htaccess.
  • Leave admin-ajax.php (and admin-post.php if needed) open to everyone, because public-facing features use it.
  • On Nginx, put allow / deny in location = /wp-login.php and location ^~ /wp-admin/, and include the PHP handling.
  • If you have password-protected pages or membership features, or use a CDN, check the impact before you set this up.

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

お気軽にご相談ください

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