Nginx reverse proxy with different context path

2020-04-16 03:55发布

问题:

I'm trying to use nginx to reverse proxy multiple web applications on the same host / port, using a different path to distinguish between applications.

My nginx config looks like the following:

proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;

upstream app1 {
    server 192.168.0.1:8080;
}
upstream app2 {
    server 192.168.0.2:8080;
}

server {
    server_name my-application-server;
    listen 80;

    location /app1/ {
        proxy_pass http://app1/;
    }
    location /app2/ {
        proxy_pass http://app2/;
    }

}

This correctly proxies any requests to individual pages on my app - e.g. http://my-application-server/app1/context/login, but any hyperlinks in my app are broken because they're missing the app1 part of the path - e.g. they direct me to http://my-application-server/context/login-success rather than http://my-application-server/app1/context/login-success.

I've tried adding in various values for proxy_redirect and rewrite, but nothing I do can convince these links to be rendered correctly.

My app is a java webapp running in tomcat, if that makes any difference. I've seen other solutions where I can change the context path of my webapp, but I need nginx to transparently proxy the requests without the tomcat having to be configured to know about the nginx path.

回答1:

Well first of all there is nothing like transparently proxying a backend from a root domain to a domain with a added base url.

If you want to proxy http://xyz/abc to http://def then there is no way to have a 100% guarantee to have everything work. You need application specific changes

If you backend API is something which doesn't return url accessing current url then you don't need to worry about the proxy_pass. But if you have a html then you need to fix everything that comes your way.

See a simple config I created for deluge backend

How to proxy calls to specific URL to deluge using NGINX?

As you can all the sub_filter were done to fix urls in CSS, JavaScript and HTML. And I had to run it, find issues and then implement fixes. Below is the config for your reference

location ~* /deluge/(.*) {
    sub_filter_once off;
    sub_filter_types text/css;
    sub_filter '"base": "/"' '"base": "/deluge/"';
    sub_filter '<head>' '<head>\n<base href="/deluge/">';
    sub_filter 'src="/' 'src="./';
    sub_filter 'href="/' 'href="./';
    sub_filter 'url("/' 'url("./';
    sub_filter 'url(\'/' 'url(\'./';

    set $deluge_host 192.168.33.100;
    set $deluge_port 32770;
    proxy_pass http://$deluge_host:$deluge_port/$1;
    proxy_cookie_domain $deluge_host $host;
    proxy_cookie_path / /deluge/;
    proxy_redirect  http://$deluge_host:$deluge_port/ /deluge/;
}

You can customize the above based on your app. But below is what you would need

location /app1/ {
    sub_filter_once off;
    sub_filter '<head>' '<head>\n<base href="/app1/">';
    sub_filter 'src="/' 'src="./';
    sub_filter 'href="/' 'href="./';
}