NarūnasK
NarūnasK

Reputation: 4950

Modify $request_uri in 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.

Upvotes: 15

Views: 54807

Answers (1)

Alexey Ten
Alexey Ten

Reputation: 14354

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.

Upvotes: 7

Related Questions