Nginx: protect all but one url - nginx

I have try a few examples but all return almost the same, I want to password protect everything after .com/, problem is there are no "static" files, the server is Tomcat with nginx, the app is build on play framework.
The whole idea is that everything has to be password protected except for one url.
.com/service/contact {has to be protected}
.com/categories/service/contact {protected}
.com/service/jp/ {protected}
.com/service/jp/allo {Public not protected}
server {
...
auth_basic "Restricted Access"
auth_basic_user_file path_to_basic/password_protection
location ~^/service/jp/allo/ {
auth_basic off;
allow all;
satisfy all;
try_files $uri $uri/ =404;
}
}
With that the first part is working which is to protect everything, but not the second part which to leave one url as public, in my case is returning a 404 error, not a custom 404 but an internal default 404.The url's are "virtal" no actual folder exist, the server is using rewrite for seo url.

Related

Prevent NGINX from serving local index.html instead of passing to proxied server

Found other similar questions, but none seem to work in my circumstance.
I am attempting to proxy from NGINX to an IIS server which is hosting an archived website in its entirety. The site is coded with some hard index.html links and I don't want to go in and modify the site at all.
Any time the site is called with the /index.html in the URL directly it appears that NGINX is not proxying the location, but instead serving out a local index.html page.
Additionally, I am trying to default instead of to the index.html page when no page is entered (i.e. domain only) instead to pass to a default.htm page (set as default in IIS) which provides a disclaimer page that will require reading before continuing on to the original index.html of the website.
This is my nginx configuration file for the site. I do not want to change my overall structure around because it is what multiple sites use. I need a solution that I can add in.
upstream my_backend {
server 10.10.10.102:1011;
include snippets/shared_upstream_settings.conf;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name server.mydomain.com;
include snippets/shared_server_proxy_settings.conf;
location #proxy {
proxy_pass http://my_backend;
}
location / {
satisfy any;
allow 10.16.0.0/24;
deny all;
auth_basic "Authorized Users Only";
auth_basic_user_file secure/.htpasswd;
auth_request /auth-1;
try_files $uri #proxy;
}
(I don't believe any of the includes should matter for this particular issue)
This configuration works for about 15 other sites I have, but none of them apparently have a hardcoded index.html. Until today I never realized that NGINX will not proxy a direct link to index.html. So I need to either disable or work around that "feature" as well as direct no indicated pages to the disclaimer page.
thanks
The $uri argument in your try_files statement instructs Nginx to test for the existence of a file before branching to the #proxy block. There exists a local index.html file that satisfies that test.
You have two options:
Replace the try_files $uri #proxy; line with proxy_pass http://my_backend; as there is no need for a separate location #proxy block.
Or:
If you want to keep the second location block, change the try_files statement to:
try_files __nonexistent__ #proxy;
try_files requires a minimum of two arguments. All arguments before the final argument are filenames to be tested. __nonexistent__ is just one such name that probably does not exist on your file system (and also helps to document the author's intent).

best method to require passwords for some pages in a web site

I have a site with most material publicly available but about 10% should be password protected. The site is published using NGINX on a Debian system.
What is the best approach to protect the few directories and single pages with a password (or some other form of authentication) ?
I think that NGINX would allow me to protect some directories, but this seems coarse and I am not sure if just ordering and listing all the directories to protect in the site configuration is a good idea.
I am obviously not an expert on NGINX configuration and thus my suspicion that there is a better way?
I have tried to use the advice given, but do not succeed. I have now:
map $uri $realm {
/Reserved "Username and Password required";
default off;
}
server {
server_name a.b.c;
root /var/www/html/homepage;
auth_basic $realm;
auth_basic_user_file /etc/nginx/.htpasswd;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
location /homepage {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/heiden.log;
...
}
What must go into the map, when the URI is a.b.c/Reserved/index.html and all other files in Reserved/* should be protected? I have tried a.b.c/Reserved/* but it did not trigger the password request (or is the firefox saved passwords playing tricks with me?).
I don't see any way except the list of URI's you need to protect. Here is the example to protect them using the basic auth and the map block with the list of URIs to protect:
map $uri $realm {
/uri/to/protect/1 "Protected area";
/uri/to/protect/2 "Protected area";
...
default off;
}
server {
...
auth_basic $realm;
auth_basic_user_file /path/to/.htpasswd;
...
}
You can also use PRCE (or PCRE2 for nginx 1.21.5 or later) regex patterns inside the map block using the ~ (for case-sensitive matching) or ~* (for case-insensitive matching) string prefix if your list can be somehow simplified that way. For example, to protect every URI starting with /path/to/protected/area you can use the following map block:
map $uri $realm {
# every URI starting with the following prefix will require basic authorization
~^/path/to/protected/area "Protected area";
...
}

Nginx redirect with and without port

we have 2 environments (test and prod) both with nginx.
To access test we use directly the host name: https://myhost:29000
To access prod we have an external LoadBalancer: https://mysite that redirects to https://myprodhost1:29000 and https://myprodhost2:29000
We have the following nginx configuration
location / {
try_files $uri $uri/ =404;
}
location /error-page {
port_in_redirect off;
return 301 /;
}
the /error-page is handled on client side (by React), therefore it does not exists in the backend.
What we want to achieve is: if a user navigate to the error-page and press F5 it should be redirected to / (root)
The problems is that the previous configuration works for prod since the port 29000 will be omitted.
For test it is not working since we need the port:29000
I tried several configuration but I didn't succeeded.
I solved it just using:
absolute_redirect off;

How to prevent rewrite after deny

I have a website inside "/directory/", and a special variation of the website inside "/directory/subdirectory/" which should only be accessible by a few specific IP addresses. The subdirectory, however is a virtual URL, the website code is still in the parent directory called "directory" in this example. So I need rewrites.
This is the relevant part of my current nginx config file:
location /directory {
# here are various rewrites for my website
location /directory/subdirectory/ {
allow 10.0.0.0/8; # example range of IP addresses allowed
deny all; # disable access for others
rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last; # the website location is still in the parent folder but the PHP code knows this specific version is to be used when the user surfs into subdirectory, which is why there is this rewrite
}
try_files $uri $uri/ /directory/index.php?q=$uri&$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_read_timeout 43200;
}
The problem I'm facing: I don't know how to stop the execution as soon as the "deny all" hits. If you're surfing into the subdirectory, the rewrite always executes, no matter if your IP is allowed or not by the directives above it. So someone surfing to the subdirectory with an IP address which is not allowed can see the website inside subdirectory, which is of course not what I want. If I comment out the rewrite, then the allow/deny directives work as they are supposed to.
So: how can I specify this rewrite is ONLY to be executed if the visitor is not denied?
Tried adding "error_page 403 /403.html;" to that location after the "deny all;" directive but it only changes the 403 page (and can only be seen again when commenting the rewrite rule in the subdirectory). Been searching the net for days already with various search terms to make this happen, and been fiddling with variations of the config, but to no avail.
Also: the "deny all" doesn't work anymore as soon as I surf to an URL inside subdirectory, ending with ".php". I assume it is because of the "location ~ .php$" directive, getting priority for some reason over the nested location directives above. I could get around this by doing:
location ^~ /directory/subdirectory/ {
allow 10.0.0.0/8; # example range of IP addresses allowed
deny all; # disable access for others
rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last;
}
location /directory {
# here are various rewrites for my website
try_files $uri $uri/ /directory/index.php?q=$uri&$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_read_timeout 43200;
}
Now the "location ^~ /directory/subdirectory/" directive gets priority over the "location ~ .php$" directive which makes the "deny all" work but I don't know if that's the way to go since it doesn't seem like the most "clear to read" solution because I move something from within the "directory/" location out of that location block. And also, that still doesn't solve my main problem (only making the "rewrite ^/directory/subdirectory/(.*)$ /directory/$1 last;" execute for allowed IP addresses and not those getting denied by the "deny all".
Thank you.
The issue you are facing is related to the precedence/order in which nginx handles it's directives. A detailed explanation can be found here (hats off to the author!):
In their execution order the phases are post-read, server-rewrite,
find-config, rewrite, post-rewrite, preaccess, access, post-access,
try-files, content, and finally log
Since "rewrite" comes before "access", the "rewrite" directive is handled first.
Since "if" is handled in "rewrite"-phase as well, one could write:
location ~ \.php$ {
if ($remote_addr != "172.17.0.1") {
return 403;
}
rewrite ^ /your-redirect last;
}

nginx redirect and basic auth woes

I have a service (Plack) which listens on http://myhost.com:5000
I want to password protect access to it with Basic Auth
When I set a server directive in the nginx conf file I get a conflict with Plack (can't bind to 0.0.0.0:5000 because it is use by Plack, and vice versa). So this brings me nowhere.
Then I enabled Basic Auth in the conf file with the location directive as :
server {
location / {
proxy_pass http://localhost:5000;
auth_basic "Restricted";
auth_basic_user_file /home/userx/.htpasswd;
}
}
which when nginx "/" is hit it redirects it to port 5000 and asks for username/password. But my app relies on the url including the port (http://myhost.com:5000/) to find the resources and the port is stripped off from the request, so what it ends up is a http://myhost.com and I get a 404 on all resources/css/images/javascripts etc. Tried various directives like port_redirection etc.
I tried URL rewriting with :
location / {
auth_basic "Restricted";
auth_basic_user_file /home/userx/.htpasswd;
rewrite ^/(.*) https://example.com/$1 permanent;
}
which gets the desired result (http://myhost.com:5000) and all resources are found but basic auth never kicks off so I never get a prompt asking for a username /password
As a final attempt it tried to protect the url with a direct
location http://localhost:5000 {
auth_basic "Restricted";
auth_basic_user_file /home/userx/.htpasswd;
}
but that did not work either.
Can someone help?

Resources