try_files always returns 404 with variable - nginx

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

Related

redirect from one folder into another using nginx

I am running any Nginx file server. I have 2 main folders i.e. folder-a and folder-b. If a user tries to land on /folder-a/abc and it's a 404, I should auto-redirect to another folder like /folder-b/abc. How do I set up such a rule in Nginx? My top folder names will always be hard-coded names like folder-a and folder-b.
As being said by #RichardSmith, if you want to look for a file in one of two locations, you can use try_files directive:
location ~ ^/folder-a(?<suffix>/.*) {
try_files $uri $uri/ /folder-b$suffix /folder-b$suffix/ =404;
}
If you want to generate an HTTP redirect, you can use error_page directive with the additional named location:
location ~ ^/folder-a(?<suffix>/.*) {
error_page 404 #redirect;
}
location #redirect {
return 301 /folder-b$suffix;
}
If you have some additional configuration directives in your root location (location / { ... }), you should either duplicate them inside the location ~ ^/folder-a(?<suffix>/.*) { ... } or move them to the server context if there are no other locations where those directives should not be applied.

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.

How can I manually set static html files for each location block

I am trying to play with nginx. I am trying to serve a particualar index.html files for each location declared on my configuration file like
location / {
root /usr/src/seo/homepage;
}
location ~ /mypage {
root /usr/src/seo/mypage;
}
location ~ /mypage2 {
root /usr/src/seo/mypage2;
}
Where each of the folder location specified has it's own index.html file. But when I try to access mypage and mypage2, nginx returns 404. I am expecting it to render it's respective index.html
UPDATE!!!
Solved it using alias like:
location / {
alias /usr/src/seo/homepage;
}
location ~ /mypage {
alias /usr/src/seo/mypage;
}
location ~ /mypage2 {
alias /usr/src/seo/mypage2;
}
From the docs:
To obtain the path of a requested file, NGINX appends the request URI to the path specified by the root directive
I.e. when /mypage is requested, nginx tries to find /usr/src/seo/mypage/mypage.
To address that, location blocks for mypage and mypage2 should look something like
location ~ /(mypage|mypage2) {
root /usr/src/seo;
}
That however requires the request to end with a slash / for index directive to work. So it might be a good idea to include try_files:
location ~ /(mypage|mypage2) {
root /usr/src/seo;
try_files $uri $uri/ =404;
}

How to make map-derived variable reflect the current $uri?

A request for /olddir1/img.jpeg using the following nginx configuration will do a correct internal redirect to /newdir1/img.jpeg but it will leave the variable $extra_uri set to the value it would have during the first rewrite cycle, that is /olddir1/img.jpeg.
Just before executing the rewrite directive, $alias_uri and $extra_uri will have the following values, all correct:
$alias_uri: /newdir1/img.jpeg
$extra_uri: /olddir1/img.jpeg
After the rewrite directive is run, setting $uri to /newdir1/img.jpeg, the variables will have the following values:
$alias_uri: /newdir1/img.jpeg
$extra_uri: /olddir1/img.jpeg
$alias_uri has the correct value (nothing has matched in the map, so the default is being used, i.e. the current $uri). $extra_uri instead has a stale value.
How come $extra_uri isn't set to the new $uri?
server {
listen 80 default_server;
server_name 'test.example.local';
location / {
root '/var/www/test/content';
set $alias_uri $example__alias_uri;
set $extra_uri $example__extra_uri;
if ($alias_uri != $uri) {
rewrite ^ $alias_uri last;
}
add_header X-Alias "uri: >$uri< alias_uri: >$alias_uri<" always;
add_header X-Extra "uri: >$uri< extra_uri: >$extra_uri<" always;
try_files $uri =404;
}
map $uri $example__alias_uri {
default $uri;
~/olddir1(?<file>/[^/]*)$ /newdir1$file;
~/olddir2(?<file>/[^/]*)$ /newdir2$file;
}
map $uri $example__extra_uri {
default $uri;
}
Marking the maps as volatile makes this problem go away.
map $uri $example__alias_uri {
volatile;
default $uri;
~/olddir1(?<file>/[^/]*)$ /newdir1$file;
~/olddir2(?<file>/[^/]*)$ /newdir2$file;
}
map $uri $example__extra_uri {
volatile;
default $uri;
}
It seems that maps are evaluated only once during the very first rewrite phase and never afterwards.

Conditional url rewrite and proxy

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?

Resources