nginx: auth_basic for everything except a specific location - nginx

How can I enable HTTP Basic Auth for everything except for a certain file?
Here is my current server block configuration for the location:
location / {
auth_basic "The password, you must enter.";
auth_basic_user_file /etc/nginx/htpasswd;
}
location /README {
auth_basic off;
}
However, on /README, it is still prompting for a password.
How can we fix this?
Thanks!
Mark

Try to use sign = , that helps you:
location = /README {
auth_basic off;
allow all; # Allow all to see content
}

I am doing something similar using "map" instead of "if" to assign the auth_basic realm variable and htpasswd file:
map $http_host $siteenv {
default dev;
~^(?<subdomain>.+)\.dev dev;
~^(?<subdomain>.+)\.devprofile devprofile;
~^(?<subdomain>.+)\.devdebug devdebug;
~^(?<subdomain>.+)\.test test;
~^(?<subdomain>.+)\.demo demo;
~^(?<subdomain>.+)\.stage stage;
# Live
~^(?<subdomain>.+)\.live live;
~^.*\.(?P<subdomain>.+)\.[a-zA-Z]* live;
}
map $http_host $auth_type {
default "Restricted";
~^(?<subdomain>.+)\.dev "Development";
~^(?<subdomain>.+)\.devprofile "Development";
~^(?<subdomain>.+)\.devdebug "Development";
~^(?<subdomain>.+)\.test "Testing";
~^(?<subdomain>.+)\.stage "Stage";
~^(?<subdomain>.+)\.demo "Demo";
# Live
~^(?<subdomain>.+)\.live "off";
~^.*\.(?P<subdomain>.+)\.[a-zA-Z]* "off";
}
server {
.. etc ..
auth_basic $auth_type;
auth_basic_user_file /etc/nginx/conf.d/htpasswd-$siteenv;
}

I'm doing the following:
location = /hc.php {
auth_basic "off";
}
location / {
try_files $uri $uri/ =404;
}
The narrow match:location = /somefile.txt {} comes first, so location / {} can capture the remaining requests
auth_basic "off" requires the quotes around it as far as I know
I also use the exact (full, if you like) match, in order to stop iteration over the other locations defined in the config (read below quote for more info on what it does)
Probably this would work in different orders, and/or without the double quotes also, but why not try to do things as correct and complete as possible, if possible.
The most important modifiers are:
(none) No modifier at all means that the location is interpreted as a prefix. To determine a match, the location will now be matched against the beginning of the URI.
=: The equal sign can be used if the location needs to match the exact request URI. When this modifier is matched, the search stops right here.
~: Tilde means that this location will be interpreted as a case-sensitive RE match.
~*: Tilde followed by an asterisk modifier means that the location will be processed as a case-insensitive RE match.
^~: Assuming this block is the best non-RE match, a carat followed by a tilde modifier means that RE matching will not take place.
quoted from here: https://www.keycdn.com/support/nginx-location-directive

Only auth_basic off didn't work for me
If we have to skip auth for ALL uri's under our url
location ^~ /some/location/to_skip/ {
auth_basic off;
try_files $uri $uri/ /index.html;
}

Related

nginx proxy_pass with new URI does not work if host is varaible

I am trying to use variable to set the hostname in a proxy_pass, but once I try that, the path after the location is ignored.
If I try and get localhost:8001/dirA/x/y/z.html. The following returns the file from http://server1:8888/dirB/dirC/x/y/z.html. This is what I expect to happen.
location ^~ /dirA/ {
proxy_pass http://server1:8888/dirB/dirC/;
But if I try the following config which is just using a variable for hostname... and try and get localhost:8001/dirA/x/y/z.html
location ^~ /dirA/ {
set $endpoint server1;
proxy_pass http://$endpoint:8888/dirB/dirC/;
I get http://server1:8888/dirB/dirC/index.html returned instead.
That's just how proxy_pass works. If you use a variable in the value, you need to provide the entire URI. See this document for details;
You could use a regular expression location. For example:
location ~ ^/dirA/(.*)$ {
set $endpoint server1;
proxy_pass http://$endpoint:8888/dirB/dirC/$1;
}
Note that the order of regular expression locations is significant. See this document for details.
Alternatively, a rewrite...break should also work.
location ^~ /dirA/ {
set $endpoint server1;
rewrite ^/dirA/(.*)$ /dirB/dirC/$1 break;
proxy_pass http://$endpoint:8888;
}

How to set the proxy_pass to get the desired address?

I have been struggling with setting up Nginx for our use case.
When I set up Nginx with the following config:
location /dep-core {
proxy_pass http://node-server:7070/;
}
and call the server with following endpoint:
<END-POINT>/dep-core/api/login
the call is redirected to
<ADDRESS-AFTER-RESOLUTION>//api/login
with two leading //s.
and when I remove the trailing / in proxy_pass after 7070:
location /dep-core {
proxy_pass http://node-server:7070;
}
the call is redirected to
<ADDRESS-AFTER-RESOLUTION>/dep-core/api/login
with leading /dep-core appended.
I want my call to redirect my call to:
<ADDRESS-AFTER-RESOLUTION>/api/login
What would be the standard way to achieve this??
For correct translation from /dep-core/foo to /foo, the location directive requires a trailing /.
For example:
location /dep-core/ {
proxy_pass http://node-server:7070/;
}
See this document for details.
To translate /dep-core to /, you can use a rewrite...break with a clever regular expression in the second block of your question. But a simple solution is to add an exact match location for that single edge case.
For example:
location = /dep-core {
rewrite ^ $uri/ last;
}
location /dep-core/ {
proxy_pass http://node-server:7070/;
}

Allow access to certain locations via IP whitelist only in NGINX

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
}
}
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
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.
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>

Using nginx $http_referer to use different static assets

I'm trying to deploy two different versions of same app on the same nginx-based server. If the URL starts with /v2, then "v2" should be used, otherwise use v1. Example:
http://example.com/v2/x/y/z * runs v2 app
http://example.com/anything/else * runs v1 app
The two different versions of the app are proxied through nginx, and that piece works well.
The issue is that I have two directories of static assets, /static and /cachedassets, that are common to both versions (and both rooted from /home/v1|2/www/public. So, even though a request to http://example.com/v2/x/y/z will initially use the right app, the page that loads will contain references to /static and /cachedassets, without the /v2 prefix, that will incorrectly load from /home/v1/www/public.
I know referer is an imperfect solution. As a temporary stopgap, until I have a chance to craft a more robust solution, I'm trying to use nginx's $http_referer to point to the correct location for these assets. Here's the nginx file:
server {
listen 1.2.3.4
server_name example.com
...
location /v2 {
root /home/v2/www/public;
try_files $uri #proxyv2;
access_log off;
expires max;
}
location ^/(static|cachedassets) {
root /home/v1/www/public;
if ($http_referer ~* "/v2/") {
root /home/v2/www/public;
}
}
location / {
root /home/v1/www/public;
try_files $uri #proxyv1;
access_log off;
expires max;
}
location #proxyv1 {
include uwsgi_params;
uwsgi_pass unix:///tmp/v1-www.sock;
uwsgi_modifier1 5;
}
location #proxyv2 {
include uwsgi_params;
uwsgi_pass unix:///tmp/v2-www.sock;
uwsgi_modifier1 5;
}
...
}
Any thoughts?
Bonus points for a solution where I can easily specify several "v2" prefixes. For example, here I might specify v2, versiontwo, and vtwo, and the following URLs would all invoke the v2 app:
http://www.example.com/v2/something
http://www.example.com/versiontwo/abc
http://www.example.com/vtwo/abc/def/ghi
and of course, http://www.example.com/somethingelse would run v1.
I'm also open to other ideas that don't use http_referer to accomplish this.
Thanks!
Rather than if blocks, use a map variable to set the root. The map can contain a number of arbitrarily complex regular expressions. See this document for more.
For example:
map $http_referer $root {
default "/home/v1/www/public";
~*/v2/ "/home/v2/www/public";
}
server {
...
location ~ ^/(static|cachedassets) {
root $root;
}
...
}

Nginx locations - case insensitive with spaces

My question is about nginx "location" configuration blocks:
If I want to make a location with a space character (well, %20) in the URL I can do it like so:
location ^~ "/Style Library/" {
}
If I want to make a case-insensitive location, I can do it like so:
location ~* ^/StyleLibrary/ {
}
However, I can't find a way of getting case-insensitive locations with space characters working. None of these appear to work:
location ~* "^/Style Library/" {
}
location ~* ^/Style[^_]Library/ {
}
location ~* ^/Style\sLibrary/ {
}
location ~* ^/Style.Library/ {
}
Can anyone help?
Do you have other regex locations that may be handling the request earlier in the server block? I just ran a test locally and was able to make the following location work:
location ~* "^/Style Library/" {
rewrite ^ /dump.php;
}
where /dump.php is just a simple script that does a var_export($_SERVER);
I tested this with
curl -i "dev/StYlE LiBrArY/"
I'd guess that some other location is handling the request instead of that regex location.

Resources