NGINX if condition have and condition - if-statement

i want to make a condition if it fulfills
abc.com/abc.m3u8?token=abcd
if conditions are met then allow
otherwise return 403
I'm a little confused because I can't use nested if in nginx
`
if ($uri !~* "^(.*)/(abc.m3u8)(.*)" && $arg_token !~* "abcd"){
return 403;
}
`

You can use request_uri to check if the URL matches abc.com/abc.m3u8?token=abcd :
if ($request_uri !~* "^/abc\.m3u8\?token=abcd$") {
# Return a 403 Forbidden status if the URL does not match the pattern
return 403;
}

Related

How to deny all the URIs except one in Nginx?

I've a domain where I need to accept only one url and all the other URLs should be blocked. I need to accept only /page?param=something. I'm using Nginx. Any help would be appreciated.
map $query_string $is_param {
~ param=.+ 1;
}
location ~* /page {
if ($is_param) {
allow all;
}
return 403;
}

Nginx 301 redirect a url with query string

I have page with pagination which google marked as duplicate content, basically I have this page /asl/candidates/ and /asl/candidates/?page=1 is the same page. What I want to do is to 301 redirect /asl/candidates/?page=1 to /asl/candidates/
I tried
location = /asl/candidates/?page=1{
return 301 /asl/candidates/;
}
But it seems it does not work with query strings.
Use $args or $arg_name if you need to get the argument(s) in the request line.
For example:
if ($args ~ "page=1") {
rewrite ^/asl/candidates/$ /asl/candidates/? permanent;
}
Source: http://nginx.org/en/docs/http/ngx_http_core_module.html#variables

Nginx : to show an error page for all the paths excluding a few , for 400 status code

I have a requirement for pattern matching in url which excludes some files and show an error page on getting an error code 400
Eg: I have URL /test/v1/ and /test/v2/. I need to show a custom error page (for status 400) for all /test/x where x can be anything, except /test/v1/ and /test/v2/.
so what should be my regular expression in location directive in nginx.conf file i tried below but failed.
location ~* /test(?!\/(v1|v2)) {
proxy_intercept_errors on;
}
error_page 400 /400.html;
Here is a suggestion:
\/test\/(v1|v2)\/?
It allows /test/v1/ and /test/v2/ (without final slash works as well).
It fails when /test/nope/ or /nope.
Test it on regex101
Allow test/(v1|v2)/, and disable all the rest:
location ~* /test(\/(v1|v2)\/) {
try_files $uri $uri/ =404;
break;
}
location / {
return 400 "bad request";
}

Nginx $http_cookie if directive pattern matching

So on the Nginx documentation it is a bit unclear but it appears we can use Regex to match anything within the if statement
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if
So i wanted to tweak this to make it so Nginx checks the value of any cookie.
But my following string what should be from my understanding * matching any cookie name and = matching any cookie contents.
if ($http_cookie ~* "*=*") {
return 444;
}
But i get the error "pcre_compile() failed: nothing to repeat in "" at "" in"
What i am trying to achieve is to Have nginx check the cookie like a WAF (web application firewall) to make sure it only contains A-Z uppercase a-z lowercase 0-9 + - _ . my PHP app is Joomla what does these checks too but be useful if i could perform these checks with Nginx too since it could deny the request faster.
EDIT to Show half solved issue / dilemma
set $block_cookie_exploits 0;
#If cookie name or contents does not contain the following
if ($http_cookie !~ "[a-zA-Z0-9\+\-\_]=[a-zA-Z0-9\+\-\_]") {
set $block_cookie_exploits 1;
}
#Block the client request
if ($block_cookie_exploits = 1) {
return 403;
}
New problem with above configuration is it will return 403 while no cookie is present. And if you put characters in the name or contents of the cookie like {} it does not return 403

Add slash to the end of every url (need rewrite rule for nginx)

I try to get an / to every urls end:
example.com/art
should
example.com/art/
I use nginx as webserver.
I need the rewrite rule for this..
For better understanding check this:
http://3much.schnickschnack.info/art/projekte
If u press on a small thumbnail under the big picture it reloads and shows this url:
http://3much.schnickschnack.info/art/projekte/#0
If i now have a slash on all urls (on the end) it would work without a reload of the site.
Right now i have this settings in nginx-http.conf:
server {
listen *:80;
server_name 3much.schnickschnack.info;
access_log /data/plone/deamon/var/log/main-plone-access.log;
rewrite ^/(.*)$ /VirtualHostBase/http/3much.schnickschnack.info:80/2much/VirtualHostRoot/$1 last;
location / {
proxy_pass http://cache;
}
}
How do I configure nginx to add a slash? (I think i should a rewrite rule?)
More likely I think you would want something like this:
rewrite ^([^.]*[^/])$ $1/ permanent;
The Regular Expression translates to:
"rewrite all URIs without any '.' in them that don't end with a '/' to the URI + '/'"
Or simply:
"If the URI doesn't have a period and does not end with a slash, add a slash to the end"
The reason for only rewriting URI's without dots in them makes it so any file with a file extension doesn't get rewritten. For example your images, css, javascript, etc and prevent possible redirect loops if using some php framework that does its own rewrites also
Another common rewrite to accompany this would be:
rewrite ^([^.]*)$ /index.php;
This very simply rewrites all URI's that don't have periods in them to your index.php (or whatever file you would execute your controller from).
rewrite ^([^.\?]*[^/])$ $1/ permanent;
to avoid querystrings of a rest url getting a / tagged on.
e.g.
/myrest/do?d=12345
For nginx:
rewrite ^(.*[^/])$ $1/ permanent;
Odd that this is the first result in Google, but doesn't have a satisfactory answer. There are two good ways to do this I know of. The first is to straight-up check if the request will hit a file and only apply a rewrite condition if not. E.g.
server {
# ...
if (!-f $request_filename) {
rewrite [^/]$ $uri/ permanent;
}
location / {
# CMS logic, e.g. try_files $uri $uri /index.php$request_uri;
}
# ...
}
The second, which many prefer as they'd rather avoid any use of if that isn't 100% necessary, is to use try_files to send the request to a named location block when it won't hit a file. E.g.
server {
# ...
location / {
try_files $uri $uri/ #cms;
}
location #cms {
rewrite [^/]$ $uri/ permanent;
# CMS logic, e.g. rewrite ^ /index.php$request_uri;
}
# ...
}
it's too late but I want to share my solution, I've met issue with trailing slash and nginx.
#case :
# 1. abc.com/xyz => abc.com/xyz/
# 2. abc.com/xyz/ => abc.com/xyz/
# 3. abc.com/xyz?123&how=towork => abc.com/xyz/?123&how=towork
# 4. abc.com/xyz/?123&ho=towork => abc.com/xyz/?123&how=towork
and this is my solution
server {
....
# check if request isn't static file
if ($request_filename !~* .(gif|html|jpe?g|png|json|ico|js|css|flv|swf|pdf|xml)$ ) {
rewrite (^[^?]+[^/?])([^/]*)$ $1/$2 permanent;
}
....
location / {
....
}
}
server {
# ... omissis ...
# put this before your locations
rewrite ^(/.*[^/])$ $1/ permanent;
# ... omissis ...
}
If you want some kind of requests (say other than GET ones) to be prevented from doing this (usually it's about POST requests, as rewrite turns any request method into GET, which may break some of your site's dynamic functionality), add an if clause:
server {
# ... omissis ...
# put this before your locations
if ($request_method = "GET" ) {
rewrite ^(/.*[^/])$ $1/ permanent;
}
# ... omissis ...
}
You can also put the rewrite in a location block (if too), to make it more specific.
using the rewrites from anthonysomerset in a Wordpress, I experimented problems accesing to /wp-admin dashboard due to reirection loop. But i solve this problem using the above conditional:
if ($request_uri !~ "^/wp-admin")
{
rewrite ^([^.]*[^/])$ $1/ permanent;
rewrite ^([^.]*)$ /index.php;
}
If nginx behind proxy with https, this snippet do correct redirect for $scheme
map $http_x_forwarded_proto $upstream_scheme {
"https" "https";
default "http";
}
server {
...
location / {
rewrite ^([^.\?]*[^/])$ $upstream_scheme://$http_host$1/ permanent;
}
...
}
And on the upstream proxy pass the X-Forwarded-Proto header like:
location / {
proxy_set_header X-Forwarded-Proto $scheme;
...
}
This rule solves query string case too:
location ~ ^/([^.]*[^/])$ {
if ($query_string) {
return 301 $scheme://$host/$1/?$query_string;
}
return 301 $scheme://$host/$1/;
}
The regex has taken from #marc's answer:
rewrite ^([^.\?]*[^/])$ $1/ permanent;
The extra slash ^/ in regex is added to improve readability
Try this: ^(.*)$ http://domain.com/$1/ [L,R=301]
This redirects (Status code 301) everything ($1) without a "/" to "$1/"