Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify $request_uri in Nginx

Tags:

nginx

I have multiple apps running on the Nginx server:

http://example.com/app1/ctrl/view
http://example.com/app2/ctrl/view
...

I would like to assign these apps DNS like so:

http://app1.example.com
http://app2.example.com
...

For that I've tried the following server block:

server {
        listen 80;
        server_name app1.example.com;

        location / {
            proxy_pass http://example.com/app1/$request_uri;
        }
}

If a user is not logged in, my app would redirect to URI:

app1/ctrl/user/login?_next=/app/ctrl/view

Essentially $request_uri becomes (Note doubled app1 instance):

app1/app1/ctrl/user/login?_next=/app/ctrl/view

Is there a convenient way to modify $request_uri or a better method to get around this problem?

EDIT1

It seems I've solved my problem with the following server block:

server {
        listen 80;
        server_name app1.example.com;

        location / {

            set $new_request_uri $request_uri;

            if ($request_uri ~ ^/app1/(.+)$) {
                set $new_request_uri $1;
            }

            proxy_pass http://example.com/app1/$new_request_uri;
        }
}

If someone knows a better (or proper "Nginx") way to do this please don't hesitate to post an answer.

EDIT2

Based on the comments I've also tried the following:

server {
        listen 80;
        server_name app1.example.com;

        location / {
            proxy_pass http://example.com/app1/;
            proxy_redirect /app1/ /;
        }

        location ~ ^/app1/(.+)$ {
            return 301 http://$server_name/$1;
        }
}

This one looks better on screen, as it eliminates app1 instance in the $request_uri part completely, but you must have two location blocks.

EDIT3

The most efficient way to solve my problem apparently is as shown in this config:

server {
        listen 80;
        server_name app1.example.com;

        location / {
            proxy_pass http://example.com/app1/;
            proxy_redirect /app1/ /;
        }

        location /app1/ {
            rewrite ^/app1(.+) $1 permanent;
        }
}

This is due to the fact, that Nginx always tries to match the longest prefix first and then (if ^~ modifier is not present) starts sequentially processing regexes until the first regex match is found. Essentially this means that all regexes are processed on every request, regardless if any of these find a match, therefore it's better to have regexes inside location directives.

like image 512
NarūnasK Avatar asked Sep 02 '15 11:09

NarūnasK


People also ask

How do I rewrite rules in nginx?

The syntax of rewrite directive is: rewrite regex replacement-url [flag]; regex: The PCRE based regular expression that will be used to match against incoming request URI. replacement-url: If the regular expression matches against the requested URI then the replacement string is used to change the requested URI.

What is $1 in nginx?

*$ $1/linux/$2.html break; redirect: This flag will do a temporary redirection using 302 HTTP code. This is mainly used when the replacement string is not http, or https, or $scheme.

What is return 301 in nginx?

Temporary and Permanent Nginx Redirect Explained To map this change, the redirects response code 301 is used for designating the permanent movement of a page. These kinds of redirects are helpful when the user wants to change the domain name and no longer wants a browser to access it.


1 Answers

You don't need to go complex way. Solution is much simpler

server {
        listen 80;
        server_name app1.example.com;

        location / {
            proxy_pass http://app1.example.com/app1/;
        }

        location /app1/ {
            proxy_pass http://app1.example.com/app1/;
            # or
            # rewrite ^/app1(.+) $1 permanent;
        }
}

Nginx will take care of adding /app1/ to request and strip it from Location header.

See proxy_redirect directive.

like image 197
Alexey Ten Avatar answered Oct 30 '22 13:10

Alexey Ten