Allow access to certain locations via IP whitelist only in NGINX
Asked Answered
T

3

5

I am using Sucuri Scanner to notify me of failed login attempts and I am currently getting about 50+ emails a day. I've tried several different ways to block access to wp-login.php and wp-admin without any luck, because I think these rules possibly don't work with subdomains (or generally just suck).

server {
    # Primary domain, secondary domain and subdomains are explicitly 
    # declared so that I can generate certs using CertBot
    server_name primarydomain.com
                secondarydomain.com
                subdomain1.primarydomain.com
                subdomain2.primarydomain.com
                subdomain3.primarydomain.com;

    client_max_body_size 20M;
    root /home/username/www/primarydomain.com/public_html;
    index index.php;
    error_log /home/username/www/primarydomain.com/logs/error.log error;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi.conf;
    }

    # This doesn't seem to block access
    location /wp-login.php {
        allow XXX.XXX.XXX.XXX;    # this is my ipaddress
        deny all;
    }

    # This doesn't seem to block access    
    location /wp-admin/ {
        deny all;
        allow XXX.XXX.XXX.XXX;    # this is my ipaddress
    }

    # This doesn't seem to block access
    location ~ ^/(wp-admin|wp-login\.php) {
        deny all;
        allow XXX.XXX.XXX.XXX;    # this is my ipaddress
    }
}
Titan answered 5/3, 2018 at 6:10 Comment(2)
Blocking wp-admin/ will break your site Ajax, which uses wp-admin/admin-ajax.phpRubbery
@Rubbery I only want to block IPs which do not belong to me. I've successfully done it via Apache .htaccess on another server.Titan
N
10

It's not working because regexps have higher priority than prefixes in nginx

https://nginx.ru/en/docs/http/ngx_http_core_module.html#location

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered.

And here's the point:

Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used

So this expression would handle all the requests

location ~ \.php$

One of the solutions might be to transform your prefix locations into regexps and move them upwards in the config files

Or use = modifier for urls you'd like to restrict access to

Also, using the “=” modifier it is possible to define an exact match of URI and location. If an exact match is found, the search terminates

More examples from the docs:

location = / {
    [ configuration A ]
}

location / {
    [ configuration B ]
}

location /documents/ {
    [ configuration C ]
}

location ^~ /images/ {
    [ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
    [ configuration E ]
}

The “/” request will match configuration A, the “/index.html” request will match configuration B, the “/documents/document.html” request will match configuration C, the “/images/1.gif” request will match configuration D, and the “/documents/1.jpg” request will match configuration E

Northernmost answered 7/3, 2018 at 8:1 Comment(0)
C
3

Do try iTheme security plugin with custom login URL and google recaptcha plugin. It reduces the attack up to an extent. A month ago we were getting so many attacks on our site but now it's fine, it got reduced to 2 /week to none.

Cougar answered 9/3, 2018 at 6:22 Comment(1)
Please don't link to your website unless absolutely necessary. It might be perceived as spam.Substage
C
2

The easiest fix would be to use nested location

http{
server {

        server_name *.domain.com;
        listen 80;

        location ~ \.php$ {
           location ~ /wp-login\.php$ {
                deny all;
           }
           location ~ ^/wp-admin/ {
                deny all;
           }
           return 200 "OK";
        }
}

And the test results are as below

$ curl vm/testing.php
OK%                                                                                                                                                                                         

$ curl vm/wp-login.php
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.11.2.2</center>
</body>
</html>

 $ curl vm/wp-admin/index.php
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.11.2.2</center>
</body>
</html>
Cinerator answered 9/3, 2018 at 7:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.