Relative link not working with nginx reverse proxy

Viewed 1613

I am reverse proxying a NextJs app's base path onto different domains, per country:

events {}
http {
    upstream nextjs_upstream {
        server localhost:3000;
    }

    server {
        listen 8080 default_server;

        server_name _;

        server_tokens off;

        location / {
            proxy_pass http://nextjs_upstream/us/;
        }
        location /_next/static {
            proxy_pass http://nextjs_upstream/_next/static;
        }
    }
}

This is working fine, and I can go to http://localhost:8080 and see the content I am expecting to see – the page from http://localhost:3000/us/.

Moreover, if I add something like this:

<Link href='/about-us'>
  <a>NextJs Link</a>
</Link>

And click on it, I correctly get sent to http://localhost:8080/about-us, which displays content from http://localhost:3000/us/about-us.

This is all working as expected, and perfectly.

However, I also have some hardcoded <a> tags on the page:

<a href="/about-us">
  Normal link
</a>

You can see this is a typical relative URL link. However, when I click on it, the browser navigates me to http://localhost:8080/us/about-us/, which of course 404s as it is proxied to http://localhost:3000/us/us/about-us/, which doesn't exist.

This behaviour also occurs if I do window.location = '/about-us' in the browser console, however, the output of window.location.href is "http://localhost:8080/".

It looks like the req to http://localhost:8080/about-us ends up getting a 308 to http://localhost:8080/about-us, but I am not sure why. Even more confusingly, it seems like the behaviour differs based on what browser I use.

What have I done wrong here? Do I need to rewrite the req path, or something?

1 Answers

Imaging like that:

1/ If my link is: http://localhost:8080/us/about-us

2/ It's going to your proxy and meet first condition:

location / {
    proxy_pass http://nextjs_upstream/us/;
}

3/ After that, your server will add us path to your link and that the reason why it lead to: http://localhost:3000/us/us/about-us/

My suggestion is add if clause for remove /us in your reverse proxy config file:

if ($request_uri ~ ^(.*)/us/) {
    rewrite (.*)/us/(.*)$ $1/$2;
}

Your config file look like this:

events {}
http {
    upstream nextjs_upstream {
        server localhost:3000;
    }

    server {
        listen 8080 default_server;

        server_name _;

        server_tokens off;
        
        if ($request_uri ~ ^(.*)/us/){
            rewrite (.*)/us/(.*)$ $1/$2;
        }
        location / {
            proxy_pass http://nextjs_upstream/us/;
        }
        location /_next/static {
            proxy_pass http://nextjs_upstream/_next/static;
        }
    }
}
Related