How to handle application level redirects in Nginx with Reverse Proxy

Viewed 396

I am writing an Nginx configurations for Crystal-Lang based application to send all the traffic http://example.com/videos/ to http://0.0.0.0:3000 via reverse proxy.

I have written the following config which is not working and I'm heading over the internet but no luck.

When I go to http://example.com/videos/, application internally performing a redirect from http://example.com/ to http://example.com/feed/popular which is the problem, it redirects to http://example.com/feed/popular which is wrong, I need /videos/ part to always concatenated with URL like http://example.com/videos/xxxx always but after redirect the /videos/ part is being chopped out. So the application should consider http://example.com/videos/ as host.

Here is my config:

server {
    listen 80;
    server_name elearn.com.pk default_server localhost;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    location /videos/ {
        proxy_pass http://0.0.0.0:3000/;
        proxy_http_version 1.1;
        rewrite /videos/(.*) /$1 break;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host/videos/;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
   }
}

Can someone please help me to resolve this issue please? Thanks.

3 Answers

Assuming the redirect comes from the proxied application, you need to rewrite the Location header to match the prefix path on the proxy server.

proxy_redirect off is causing this error. You need to set it to default or configure a custom rewrite (default should work fine for your purpose, though).

You should define upstream in http directive.

http {
# ...

  upstream myapp {
    server 0.0.0.0:3000;
  }

# ...

}

Then use it in the server scope in location like this:

location ^~ /video/ {
  proxy_pass http://myapp;
}

You can use proxy_redirect to force change the header of Location the upstream returned redirect.

If I want nginx to dispatch the path foo to an upstream app with listen port is 7001, the simplest configure:

location /foo/ {
    proxy_pass  http://localhost:7001/;
}

However, for my situation, this reverse proxied upstream app will return a redirect of 301 Moved Permanently with header Location:/bar/ when user successfully login. (You can know how the redirect works by tracing network activity via DevTools of a browser.)

I want xxx.com/foo/bar => localhost:7001/bar, but because the incorrect Location of its redirect, by combing the host header it will return xxx.com/bar to clients. The problem is, it will require nginx to look location location /bar/ {...}, which is not configured at all.


Naturally, one brutal way in my head is to use another redirect to correct the url:

location / {
    ...
    rewrite /bar/.* /foo/bar/$1;
}
# OR
location /bar/ {
    return 301 $scheme://$http_host/foo/bar/;
}


After thinking, I realize a more favorable solution is to just change the Location of the returned redirect package directly. Fortunately, the proxy_redirect of nginx provides this function to allow us change the Location of proxied redirect.

Syntax: proxy_redirect redirect replacement;

from: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect.

OK, here is the solution:

location /foo/ {
    proxy_pass  http://localhost:7001/;
    proxy_redirect /bar/ /foo/bar/;
    # you may need to debug what content of "Location" in your wrong redirect package by DevTools, and replace it here.
}

A simply way to replace the wrong Location from /bar/ to /foo/bar/ the Location field fixed my problem.

PS: a trick of debuggin nginx and network activity is to use new “Incognito window” every time. Or the browser cache will give you misleading reaction.

Related