8

I'm trying to put a reverse proxy in front of a few internal web services.

Nginx is setup and working properly to serve request. If I only serve one location / in my conf file, it loads that proxy_pass target successfully ie:

location / {
  proxy_pass https://internal.ip:port/;
 }

Browsing to the https://public_proxy_address/ loads that internal resource perfectly.

However, since I have multiple internal applications, I want to proxy all of them through nginx. So, in my testing I have changed the conf to as follows:

location /app1 {
  proxy_pass https://internal.ip:port/;
}

With this in place, I get the main/default internal app index page, but the view source shows me that no link stylesheets, js, or other resources are being re-written. Therefore the entire contents of the page, fails to load. In Apache, I would probably write a proxyhtmlurlmap ^/resource/ /app1/resource R. I cannot find any way to achieve this in nginx though.

I have also tried this, to no avail:

location /app1 {
  rewrite /resource(.*?) /app1/resource$1 break;
  proxy_pass https://internal.ip:port/;
 }

How do I get nginx to properly prepend the target location (app1) to the requested resource urls so that they load?

PenguinCoder
  • 529
  • 2
  • 6
  • 17

5 Answers5

8

As I don't have enough credit, I cannot comment on entries, so, here comes my response as a separate entry.

I don't know why the OP disagrees but I think Martin Fjordval identifies the problem correctly and suggests the right thing. I'd suggest a slight modification to his snippet as below though;

                location /app1/ {
                    proxy_set_header Host $http_host/app1;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Scheme $scheme;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;
                    proxy_redirect    off;
                    add_header Pragma "no-cache";
                    add_header Cache-Control "no-cache";

                    proxy_pass http://internal.ip:port/;
                    sub_filter 'action="/'  'action="/app1/';
                    sub_filter 'href="/'  'href="/app1/';
                    sub_filter 'src="/'  'src="/app1/';
                    sub_filter_once off;
            }

So, if you are sure that all your relative urls that are starting with '/' needs redirecting, the above would append '/app1/' to them all and get them caught by the 'location /app1/' block when referenced. You can then view the page source and confirm that the rewriting is happening.

You'd also probably need the whole or at least the part of the 'proxy_set_header' shabang, especially the 'proxy_set_header Host $http_host/app1' bit.

abdus_salam
  • 191
  • 1
  • 5
2

I ended up just going with subdomain based proxying. The basics look like this:

server {
   listen 443 ssl;
   ssl on;
   ssl_cert <cert>;
   ssl_key <key>;

   server_name appname1.public.com;

   location / {
     proxy_pass https://internalapp1.ip:port
    }
}

server {
   listen 443 ssl;
   ssl on;
   ssl_cert <cert>;
   ssl_key <key>;

   server_name appname2.public.com;

   location / {
     proxy_pass https://internalapp2.ip:port
    }
}

This eliminates the need to have any direct url or resource rewriting.

PenguinCoder
  • 529
  • 2
  • 6
  • 17
1

If I understand your problem correctly it sounds like the problem is your application thinks it's hosted at the root uri / while it's actually hosted at /app1 and just not being told this. Nginx will not normally modify the response of your backends which is what you're expecting, however, it is possible.

First you want to check if there's a configuration option in your app where you can define the root uri. If there is then setting that is by far the easiest solution.

If you cannot find anything you can use the substitution module to replace the urls in the HTML. Do note that in order for this to work you need to disable GZIP encoding on the backend so nginx can see the uncompressed HTML.

An example of what your subfilter might look like

location /app1 {
    sub_filter '<a href="/resource/' '<a href="/app1/resource/';
    sub_filter_once off;

    proxy_pass https://internal.ip:port/;
}
Martin Fjordvald
  • 7,749
  • 1
  • 30
  • 35
  • It's actually the other way around. Backend apps think they're hosted at `/` URI, and nginx location is `/app`/ So when the backend app goes to request a resource, it hits `http://internal/css/file.css` which, `css` isn't mapped by nginx so the app gets a 404. So, the backend needs to request `http://internal/app/css/file.css` , but I can't rewrite the backend app to use relative pathing. – PenguinCoder Jan 12 '16 at 19:36
0

You've specified a single absolute URL in your location, not the URL of the page and all resources that the page uses. You need to specify a regular expression that starts with that URL. Something like this may work (I haven't tested it)

location ~ /app1(/.*) {
  proxy_pass https://internal.ip:port/;
}
Tim
  • 31,888
  • 7
  • 52
  • 78
  • When I do this, I get an error starting nginx `"proxy_pass" cannot have URI part in location given by regular expression, or inside named location or inside"if" statement, or inside "limit_except" block in /etc/nginx/conf.d/proxy.conf:26` – PenguinCoder Jan 12 '16 at 01:02
  • If I remove the trailing `/` on the proxy_pass, I get nothing (blank page) on the browser request. – PenguinCoder Jan 12 '16 at 01:04
  • Oh yeah, that's always a pain. There is a way around it, and I've linked to them before, but you'll have to poke around. Hopefully someone else can come up with a better solution. I wonder if adding a parameter to the proxy pass helps. – Tim Jan 12 '16 at 01:04
-1

I had the same problem; the index page was loading but all the resources received 404.

I noticed that in the location I had: try_files $uri $uri/ =404; This returns 404 for all the resources. Just remove it.

location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        # try_files $uri $uri/ =404;                       <---- Comment out this line.
        # Uncomment to enable naxsi on this location
        # include /etc/nginx/naxsi.rules
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
Ladadadada
  • 26,337
  • 7
  • 59
  • 90
Roedit
  • 1
  • I think we do not have any indication that the configuration statements you mention are in place. The Configuration posted (it is a complete `location` block) indicates the opposite. – pacey Sep 27 '16 at 17:13