How can the $request_method parameter be changed in nginx for a proxy_pass directive? - rest

I need to alter the nginx $request_method variable under certain conditions when I hand off the request through a proxy_pass directive.
I was thinking of using something like the map directive:
map $request_method $request_method {
default $request_method;
DELETE POST;
PUT POST;
}
But, there are 2 problems:
map directives are only allowed in the top level http block and can't be changed inside of a location directive.
this also gives me a duplicate "request_method" variable error from nginx.
How can I alter the $request_method for a proxy_pass?

There is a directive proxy_method.
You will need another variable declared via map (yes, at server level):
map $request_method $my_proxy_method {
default $request_method;
DELETE POST;
PUT POST;
}
And then in your location:
proxy_method $my_proxy_method;
Note that Nginx variables are evaluated lazily, so if you have lots of other locations, my_proxy_method will be evaluted only for this one.

Related

Multiple nginx locations

I have multiple nginx locations via the same route
location ~^/(v1) {
proxy_pass http://localhost:8000/;
}
location = /v1/smth {
}
Does the proxy_pass would be applied for /v1/smth?
The nginx http-core-module documentation describes the order of precedence when evaluating a match. Specifically:
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.
In your example, /v1/smth therefore matches exactly with the second (empty) location block, and the proxy_pass is therefore not applied.

nginx: How to mass permanent redirect from a given list?

I have about 400 url that will change in the new version and for some reasons I can't repeat the same type of url structure in the new website.
My question is, can I give a url list to nginx (yeah I know the 400 ones), and tell him simply that each one of them are going to another url?
Like I said the url structure will be different so I can't use any type of pattern.
Thanks in advance.
The map directive
If you have a very long list of entries, it could be a good idea to keep them outside of the nginx configuration file - using a .map file.
First you need to add a map directive inside your nginx.conf file - keep in mind that your .conf file could be named in another way (e.g. default.conf).
nginx.conf
map_hash_bucket_size 256; # see http://nginx.org/en/docs/hash.html
map $request_uri $new_uri {
include /etc/nginx/oldnew.map; # or any file readable by nginx
}
server {
listen 80;
server_name your_server_name;
if ($new_uri) {
return 301 $new_uri;
}
...
}
Then, the map directive will map any $request_uri to the matching $new_uri found inside the oldnew.map file.
/etc/nginx/oldnew.map:
/my-old-url /my-new-url;
/old.html /new.html;
Be sure to end each line with a ";" char!
Additional configuration
If you need to redirect all URLs to another host, you can use:
return 301 http://example.org$new_uri;
Or, if you also need to redirect to another port, you can use:
return 301 http://example.org:8080$new_uri;
Probably the easiest way to do that is to wrap map directive around your list. The configuration in this case would look like this:
map $request_uri $new_uri {
default "";
/old/page1.html /new/page1.html;
/old/page2.html /new/page2.html;
...
}
server {
...
if ($new_uri != "") {
rewrite ^(.*)$ $new_uri permanent;
}
...
}

nginx 301 redirect with query_string variable and if

I'm new to nginx and I need to setup up a load of 301 redirects each pointing old files to the new ones, like this:
# www.domain.com/products/category/product.php?id=103
# to
# www.domain.com/products/new-category-name/new-product-name.html
To deal with the ? I have the following which seems to be working fine:
if ($args ~ "id=103") {
rewrite ^ /products/new-category-name/new-product-name.html? permanent;
}
How does this look? I'm aware that if is mostly a bad idea in nginx but I don't fully understand why. Is the above rule okay? it seems to work fine. Lastly, I have around 100 of these urls to redirect. Will it be okay to just duplicate this rule for each url?
Thanks
UPDATE
The mapping looks to be a great solution but I'm not sure where to place the code. I currently have the following:
location / {
try_files $uri $uri/ #modx-rewrite;
}
It's stated that any additional rules need to be placed before this location block.
I would sugguest to use the ngx_http_map_module
create a file for the urlmapping, that contains old and new urls, like
/products/category/product.php?id=103 /products/new-category-name/new-product-name.html ;
/products/category2/product.php?id=104 /products/new-category2-name/new-product104-name.html ;
that's easy to maintain. just add a new line for a new mapping and reload your nginx config.
in your nginx config create a location with a mapping like
map $request_uri $newuri {
include /path/to/your/mappingfile;
}
server {
...
location / {
if ($newuri) {
return 301 $newuri;
}
}
}

Nginx redirect URL with specific query parameter

Nginx, I am trying to permanently redirect the URLs with a device GET parameter (http://www.example.org/page?device=desktop) to the relative URL without this parameter (http://www.example.org/page).
I did this, but it doesn't work.
location {
rewrite ^(.*)\?device=desktop $1 permanent;
}
Each query parameter is exposed as a variable prefixed with $arg_ in the configuration file. For example, device would become $arg_device. Using this you can make the comparison check within your location block, for example:
location / {
if ($arg_device = desktop) {
return 301 $uri;
}
}

how to do nginx rewrites from a url with get parameters

This is my first ever StackOverflow question so please bear with me.
Nginx serves many different sites for us and we have a lot of redirects from migrating clients from different vendors and such. We have set up an /includes directory that houses redirect files for each domain that we migrate over. Occasionally, we will need to write redirects from a url that contains get parameters:
http://example.com/content/default.aspx?NewsId=28
To do this, we have been doing this in an nginx /includes file called example.com-redirects
location ^~ /content/default.aspx {
if ($args ~ "NewsId=28") { rewrite ^ http://example.com/news? permanent; break; }
# add more statements like the one above
}
That has worked just fine for us thus far. Unfortunately, we need to do the same thing but for a different domain that could have the same get parameters. And of course nginx doesn't allow for duplicate locations.
location ^~ /content/default.aspx {
if ($args ~ "NewsId=28") { rewrite ^ http://differentexample.org/news? permanent; break; }
}
I've tried a couple of different solutions all giving me syntax errors. No one at my company is an nginx expert anymore so I could really use some help solving this. I have added an if ($host ~ "example.com") within the location block and that gave me an error. And I've tried adding the location block within the if ($host ~ "example.com") block. Both times nginx told me that I can't put that there.
I usually find my answer in the vast knowledge base that is the internet but seem to be striking out on a solution for this and we're running out of time before we launch this client.
Instead of using if, use a variable. In the virtual host config you set this variable. In the include with the location you use it:
server {
...
set $redirect_host "example.org";
include /includes/news28.conf;
...
}
# include part
location /foo {
if ($args ~ "NewsId=28") { rewrite $scheme://$redirect_host/news? permanent; }
}
Of course you need to set that variable also in the server config of the host already using this include. Hope this helps.