How to do this without using if? - nginx

I have a list of blacklisted URLs that I would like to check to see if they are the http_referer for a particular request. If they are I am trying to set a cookie. I had tried doing it with the code below:
set $blackListUrls "www.somesite.com,www.anothersite.com,www.yetanother.com";
location / {
if($blackListUrls ~* $http_referer){...}
}
But while reading more about the if statement in nginx it sounds like I shouldn't use it. How can I do what I am talking about above without using an if statement?
Also - I have no experience with nginx so if you see a different way I should be checking this feel free to point it out.

If you want to add a cookie based on Referer, something like this should work:
map $http_referer $setcookie {
default "";
http://some.exact.url "cookiename=cookievalue";
~*example\.com "cookiename=cookievalue";
...
}
server {
...
location / {
add_header Set-Cookie $setcookie;
...
}
}
It will map the $http_referer variable (i.e. Referer header) into the $setcookie variable, empty by default (and not empty if referer is listed in the map). The add_header directive is used to add Set-Cookie header with the $setcookie value. The header will not be added if $addcookie evaluates to an empty string.
In the map you may use exact strings or regular expressions (with "~" or "~*" prefix).
See here for docs:
http://nginx.org/en/docs/http/ngx_http_map_module.html
http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header
You may also want take a look at nginx referer module. It is designed to do a whitelisting of referrers though, not blacklisting, and approach using map would be easier for a blacklist.

If you read http://wiki.nginx.org/IfIsEvil carefully you'll notice that:
if's directly in the server block are OK
if's in a location block on the other hand are unsave unless they hold only a return or rewrite directive
So to following would actually be perfectly save:
server {
location / {
set blackListUrls "www.somesite.com,www.anothersite.com,www.yetanother.com";
if($blackListUrls ~* $http_referer){return 403;}
}
}
In other words you don't need to get rid of all ifs

Please note: nginx has referer module.

Related

nginx proxy_pass doesn't work right when concatenating to variable

I have an NGINX server running as a reverse proxy for a service I host. I tried configuring it with this:
set $upstream_nzbget http://nzbget:6789;
location /nzbget/api/ {
proxy_pass $upstream_nzbget/;
}
But the proxy_pass doesn't work properly when I try to add the slash / to the end of $upstream_nzbget. If I change it to this, it works properly:
location /nzbget/api/ {
proxy_pass http://nzbget:6789/;
}
So I think it has something to do with variables in proxy_pass. In the first case (the one that isn't working), I'm not really sure what the URL ends up being. I haven't found a way to log the final URI that gets used by proxy_pass.
Can someone explain why the first case isn't working? What is the proper solution? Note that I need to keep the variable in proxy_pass so it uses the resolver.
Side note: I use a trailing slash in my location block because otherwise I get a 404 when I use this URL:
domain.com/nzbget/api/api:password/xmlrpc
This is why I use /nzbget/api/ instead of /nzbget/api.
EDIT 1
I played around with this some more, and I found that this also doesn't work:
location /nzbget/api/ {
set $upstream_nzbget http://nzbget:6789/;
proxy_pass $upstream_nzbget;
}
This one is really strange. It's the same string, the only difference is using a variable vs a string literal. I'm not doing any string concatenation here. I'm not sure why there's a behavioral difference.
EDIT 2
This SO question might be the same issue, but it has no helpful answers.
You need to pass $request_uri when using it with variable. It's there in the docs somewhere.
It'll be something like:
location /nzbget/api/ {
set $upstream_nzbget http://nzbget:6789$request_uri;
proxy_pass $upstream_nzbget;
}

How to conditionally set cookie in location section depending on certain query parameter

Requests to various locations may contain a query parameter like ?ide_theme=dark. Depending on its presence, I need to set a cookie user_ide_theme to the parameter value in Nginx. It's important to keep existing cookie if the parameter is absent in request.
The most intuitive way:
location ~ / {
# ...
if ($arg_ide_theme) {
add_header Set-Cookie 'user_ide_theme=$arg_ide_theme;Path=/;HttpOnly';
}
# other locations
}
But it doesn't work and Nginx docs have more or less clear explanation why if shouldn't be used here.
The only 100% safe things which may be done inside if in a location context are:
return ...;
rewrite ... last;
How can I add this header conditionally depending on a query parameter?
a cookie shouldn't be cleared if a user already has it, but there is no such query parameter in request
a cookie should be updated, if something new comes in the query parameter
it's not necessary to keep this parameter in the request
The only workaround I found so far is to use redirect inside if to the same address, but without query parameter after setting a cookie - then it would work
Use map directive for this:
map $arg_ide_theme $user_ide_theme {
"~^(.+)$" "user_ide_theme=$1;Path=/;HttpOnly";
default "";
}
server {
...
add_header Set-Cookie $user_ide_theme;
...
}

How to block a specific URL in NGINX webserver

I want to block a specific URL but I am not able to do this.
The URL that should be blocked is example.com/clientarea/?dxx_g=dddd.
But the following url should still work - example.com/clientarea.
I tried the following:
location ^~ /clientarea/ {
return 444;
}
But if I do this it will block all connections to /clientarea.
I hope you can help me or advise me how to make this possible.
The location and rewrite statements test a normalized URI which does not include the ? and anything following it.
The $request_uri variable contains the entire URI. Test this variable using an if or map directive.
For example:
if ($request_uri = /clientarea/?dxx_g=dddd) {
return 444;
}
You can also use regular expressions. See this document for more. See this caution on the use of if.
If you have a number of URIs to block, you should consider using a map instead.

nginx case insensitive equals operator

I'm trying to manually redirect a couple of links from my old blog to my new blog like this:
location = /blog-article-url {
return 301 https://blog.example.com/blog-article-url
}
And this works when i visit https://www.example.com/blog-article-url, i get properly redirected. However it IS case sensitive, if i visit https://www.example.com/BLOG-ARTICLE-URL it will NOT work.
What should i replace the = sign in the nginx config block to make it case insensitive?
You can do a case insensitive location block with regular expressions.
For example:
location ~* ^/blog-article-url$ { ... }
Note that the evaluation order of regular expression locations is significant - so you may need to move this location block towards the top of your server block. See this document for more.

Nginx Rewrite Issue to External link

I'm trying to set up a permanent redirect from
http://domain.com/member/blog_post_view.php?postId=1
to
http://blog.domain.com/friendly-url-here
The source URL contains both a ? and an = which I think might be the cause but am unsure.
I've tried all sorts of nginx suggestiosn including the one below but can't seem to get the redirection to work and hoped someone can point me in the right direction.
location /blog_post_view.php?postId=1 {
rewrite "/blog_post_view.php\?postId\=1" http://blog.domain.com/friendly-url-here permanent;
}
That part of request line starting from the question mark is called query string, while the location directive matches only path part of URI.
You should use $arg_* variable instead:
location =/blog_post_view.php {
if ($arg_postId = 1) {
return 301 http://blog.domain.com/friendly-url-here;
}
}
Reference:
http://nginx.org/r/location
http://nginx.org/r/if
Embedded Variables

Resources