Conditional url rewrite and proxy - nginx

I have a Javascript app, and for Social Sharing puposes I would like to return the result form another server when the facebook crawler visits the page.
Basically, if I detect a Social bot, I would like to do:
GET https://example.net/shared/route/123 -> GET https://rendered.example.net/robots/shared/route/123
I am failing to complete this, as I cannot use proxy_pass or try_files inside an if statement.
What I've tried:
location /shared/route/ {
if ($http_user_agent ~ (?!(facebookexternalhit|Facebot|Twitterbot|Pinterest|Google.*snippet))) {
try_files $uri $uri/ /index.html =404;
}
rewrite /shared/(.*) /robots/$1 break;
proxy_pass https://rendered.example.net/;
}
But I receive the error:
"try_files" directive is not allowed here in /etc/nginx/sites-enabled/webapp:22
And I've also tried
location /shared/route/ {
if ($http_user_agent ~ (?!(facebookexternalhit|Facebot|Twitterbot|Pinterest|Google.*snippet))) {
rewrite /shared(.*) /robots/$1 break;
proxy_pass https://rendered.example.net/;
}
}
But then I receive:
"proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/sites-enabled/app:24
How can I solve this?

Related

NginX redirect /service to /service/

I have two servicesr accessible via NginX. The web server configuration looks like this:
location /service1/ {
# process php files
}
location /service2/ {
proxy_pass http://127.0.0.1:9999/;
}
However, if one clicks on https://example.com/service1 (or 2) he gets a 404 error. There is no folder called "service1" (or 2) in the website root.
I would like links to "https://example.com/service1" to point to "https://example.com/service1/" (with trailing slash), possibly without specyfing a redirect for every service I have, i.e
location = /service1 {
return 301 https://$host/service1/;
}
location /service1/ {
# process php files
}
location = /service2 {
return 301 https://$host/service2/;
}
location /service2/ {
proxy_pass http://127.0.0.1:9999/;
}
I have already tried try_files $uri $uri/ =404;, but it seems to only work for real files and folders in the website root, no "virtual" subdirectories.
I am avoiding configurations like location /service { ... } because they seem more vulnerable.
Inside your location = blocks you need to generate an internal redirect to $uri/. You can achieve this using try_files or rewrite...last.
For example:
location = /service1 {
try_files nonexistent $uri/$is_args$args;
}
Notice that the internal redirection must be the last parameter. See this document for details.
Or:
location = /service1 {
rewrite ^(.*)$ $1/ last;
}
See this document for details.

nginx server: how to remove first directory from URL

Can anybody please help me to remove first directory name from URL?
My Image location is _data/hotel/3/15377/hotel_image.jpg
But Image path gets changed due to relative URL in code and it become to something like this.
example.com/france/_data/hotel/3/15377/hotel_image.jpg
example.com/usa/_data/hotel/3/15377/hotel_image.jpg
example.com/india/_data/hotel/3/15377/hotel_image.jpg
is their any possibilities to remove dynamic country name from above URL
If you want to rewrite only this particular URL, you can use this location block in your config:
location ~ /[a-z]+/_data/hotel/3/15377/hotel_image.jpg {
try_files /_data/hotel/3/15377/hotel_image.jpg;
}
If you want to rewrite all URLs which lead to /<country>/_data/..., you can use:
location ~ /[a-z]+/_data/(.+) {
try_files /_data/$1;
}
or for stricter URL checking:
location ~ /(?:france|usa|india)/_data/(.+) {
try_files /_data/$1;
}
#Ivan Shatsky's answer is great for files but also if we want to redirect a general url is better if you use the rewrite directive.
Depending where you define the rewrite directive you have two ways to implement it:
A. In the server context
server {
...
rewrite ^/[a-z]+/_data/(.+)$ /_data/$1 last;
...
}
B. In the location context
location ~ /[a-z]+/_data/(.+) {
rewrite ^/[a-z]+/_data/(.+)$ /_data/$1 break;
proxy_pass http://backend;
}
Teo, why did you change the flag to break?* Because, if this directive is put inside of a location context, the last flag might make nginx to run 10 cycles and return the 500 error.
Note:
Remember not add / at the end of the proxy_pass directive. This example wont work:
...
proxy_pass http://backend/;
...

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/;
}

try_files always returns 404 with variable

The try_files directive seem to always fail for me:
...
root /images;
location /media {
set $do_resize $uri;
# if ?resize=blah query present, rewrites do_resize to small/$uri
if ($arg_resize != '') {
set $do_resize 'small/${do_resize}';
}
try_files $do_resize $do_resize/ #fallback;
}
# placeholder for image resize server
location #fallback {
add_header Content-Type text/html;
return 200 "not found :/";
}
My folder structure:
| images
| test.jpeg
| small
test.jpeg
When requesting to http://foo/media/test.jpeg, it returns the image correctly. but when requesting http://foo/media/test.jpeg?resize=blah, it returns 404 not found. It should return the test.jpeg image inside the small folder.
Is it possible to try_files with a custom variable at all? I've never seen something else besides $uri being used for the try_files directive.
The if statement does not work inside the location block for some reason, but the use of if inside a location block is known to cause problems. See this application note.
Also, all nginx URIs begin with a leading /. So, the $do_resize inside the if block should be /small$uri.
For example:
set $do_resize $uri;
if ($arg_resize != '') {
set $do_resize /small$uri;
}
location /media {
try_files $do_resize $do_resize/ #fallback;
}

How to redirect invalid url to a valid url in nginx?

I have a valid url of the type http://example.com/valid/. Using nginx how do i redirect a url of type http://example.com/valid/dsdhshd to my valid url?
I tried:
location /valid/ {
resolver 8.8.8.8;
proxy_pass http://example.com/valid/;
proxy_redirect off;
}
But it gives a 500 internal server error.
I also tried location return 301 $scheme://example.com/valid/; but this just put me in an infinite redirection loop.
If you want to send the redirect to the client, don't proxy the request and simply send it.
server {
# Your server configuration ...
# Enclose regular expressions in default location.
location / {
location /valid {
location ~ /valid/.+ {
try_files $uri #invalid;
}
# Handle the request to the valid URL ...
}
}
location #invalid {
return 301 $scheme://$server_name/valid;
}
}
That should do the trick. You did get a redirect loop because your location block also matched the /valid/ URL itself, something you don't wanted to match. You only want to match URLs which have something after that string, e.g. /valid/foo. That is exactly what the regular expression in the location block above is ensuring.
here's a sample i could think about
server {
location /valid {
try_files $uri $uri/ #redirect_invalid;
}
location #redirect_invalid {
return 301 $scheme://$server_name/valid;
}
}
But this will be very specific and if there's many folders you'll need to add each separately, I can't think of a method to make this generic for all folders, maybe someone else could help me with this.

Resources