nginx server: how to remove first directory from URL - nginx

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

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 rewrite args without an IF?

I would like to rewrite legacy links using a query parameter type of URL to a new style of URL.
Ex.
example.com/page?id=1 -> example.com/page/1
example.com/otherpage?id=1 -> example.com/otherpage/1
Currently I have the following configuration using the evil if.
if ($args ~* "id=(.*)") {
set $w1 $1;
rewrite .* $scheme://$host/page/$w1? permanent;
}
Note: I am using CloudFront, and relying on the host header above.
If the above is in a server block, with no other location block - would this qualify as a non-evil use of if in NGINX config? Also, the above only supported /page/. Any better ideas for making that portion work for otherpage and other pages?
I have seen a few other ideas discussing using a map, but I'm not quite sure how to bring it all together? I was thinking something along the lines of:
map $args_id ?? {
default ?
??
}
...
server {
...
???
}
UPDATE:
Based on the Answer from #Ivan, this was my final solution:
server {
listen 80;
root /usr/share/nginx/html;
index index.html index.htm;
# Handle legacy requests
if ($args ~* "id=(.*)") {
set $w1 $1;
rewrite ^ $scheme://$host$uri/$w1? permanent;
}
}
Your if construction isn't evil. You can use something like
rewrite ^ $scheme://$host$uri/$w1? permanent;
for any page. More complex example if you want to process both example.com/page?id=1 and example.com/page/?id=1:
map $uri $maybe_slash {
~/$ "";
default "/";
}
...
server {
...
rewrite ^ $scheme://$host$uri$maybe_slash$w1? permanent;
...
}

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

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.

Redundant Nginx Location and Rewrite Regular Expression

I have a location and rewrite directive pair that works, but there is a redundancy that it seems like I should be able to optimize out. It takes an external URL like /css/20141201-styles.css and delivers /css/styles.css.
location ~ '^/(css|js)/[0-9]{8}-' {
rewrite '^/(css|js)/[0-9]{8}-(.*)$' /$1/$2;
}
It seems like I'm doing work twice, once in matching, and then again when rewriting. Is there a way to capture the matches in the location directive, and then use them in the rewrite?
location ~ '^/(css|js)/[0-9]{8}-(.*)$' {
rewrite [something here?] /$1/$2;
}
In Apache, it looks like this:
RewriteRule ^/(css|js)/[0-9]{8}-(.*)$ /$1/$2 [NC,L]
SOLUTION
Thanks to Terra for pointing out the alias directive! This location was already nested in another location which applies the root directive, so that takes care of the server path.
location ~ ^/(css|images|js)/ {
location ~ '^/(css|js)/[0-9]{8}-(.*)$' {
alias /$1/$2;
}
root /server/path/to/web/root;
}
UPDATE
This also works, and has fewer lines. The break flag on the rewrite directive prevents looping of the server level, making it just as performant as the alias solution.
location ~ ^/(css|images|js)/ {
rewrite '^/(css|js)/[0-9]{8}-(.*)$' /$1/$2 break;
root /server/path/to/web/root;
}
Solution 1: Do not create separate location, just move rewrite to other one. location / for example.
Solution 2:
location ~ ^/(css|js)/[0-9]{8}/ {
alias /server/path/to/web/root/$1/;
}

Resources