8

I'm having problems configuring nginx, I've searched the web for solutions and I have some bits and pieces but I'm still not able to come up with proper configuration.

I have registered a domain, let's say - www.example.com. I've configured everything on the registrars site, pinging www.example.com and www.*.example.com succeeds.

I have Apache Tomcat running on my machine listening on port 8080. I want to set up dynamic proxy_pass. So if I have application MyApp running in tomcat and reachable through localhost:8080/MyApp, I want to be able to reach it with www.MyApp.example.com, so basically the subdomain would be the name of the application in tomcat.

Here's my nginx config:

server {
  server_name ~^(www\.)?(?<sub_domain>.+)\.example\.com$;
  listen 80;

  location / {
     proxy_pass http://localhost:8080/$sub_domain/;
  }
}

When I go to www.myapp.example.com I'm being redirected to http://localhost:8080/myapp - I mean I literally end up with http://localhost:8080/myapp in my browser.

If however I change the regex in nginx setup to:

server {
      server_name www.myapp.example.com myapp.example.com
      listen 80;

      location / {
         proxy_pass http://localhost:8080/myapp/;
      }
    }

Then everything works like a charm. I know it has to do something with the resolver, I've already tried putting resolver in the nginx but it changes nothing.

What am I missing here?

//edit:

Here's my config. I'm still getting redirected to www.myapp.example.com/myapp/login instead of www.myapp.example.com/login. I've changed the regex, still the same.

  http {

    upstream backend {

             server 127.0.0.1:8080;

    }

    server {                                                         
          server_name ~^(www\.)?(?<sub_domain>.+)\.example\.com$;
          listen 80;                                                        


           location / {
               proxy_set_header "Host" $host;
               proxy_pass http://backend/prefix-$sub_domain/;

               proxy_redirect http://$host/prefix-$sub_domain/ http://$host;

           }

    }

curl:

* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /prefix-myapp/ HTTP/1.1
> User-Agent: curl/7.35.0
> Accept: */*
> Host: www.myapp.example.com
>
< HTTP/1.1 302 Found
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=E609EB96D8F27FD6F4E7F9ED9ACA5245; Path=/prefix-myapp/; HttpOnly
< Location: http://www.myapp.example.com/prefix-myapp/login;jsessionid=E609EB96D8F27FD6F4E7F9ED9ACA5245
< Content-Length: 0
< Date: Tue, 21 Oct 2014 16:48:05 GMT
<
* Connection #0 to host 127.0.0.1 left intact

Edit://

Many thanks Xavier! Adding following two lines helped:

proxy_pass http://backend/prefix-$domain$request_uri;
proxy_redirect http://$host/prefix-$domain http://$host;

2 More questions though:

  1. Does this configuration has big impact on performance?
  2. Can I filter out something from the $request_uri (e.g. JSESSIONID=1233....)?

Again, many thanks! It took me a week to figure this one out!

Stugal
  • 193
  • 1
  • 1
  • 4
  • Seems fine to me on the nginx side. Could you curl the proxy target directly and find out what's the intermediate redirection (`curl -sv "http://127.0.0.1:8080/prefix-myapp/" -H "Host: www.myapp.example.com"`)? – Xavier Lucas Oct 21 '14 at 15:54
  • If I substitute $sub_domain to 'myapp' in proxy_pass then everything works fine. I honestly don't get it. – Stugal Oct 22 '14 at 07:52
  • 2
    That's because when using variables nginx can't guess the normalized URI nor the default rewrite for proxy redirects. What nginx version are you using ? Remove the trailing slash on the first parameter of proxy_redirect. – Xavier Lucas Oct 22 '14 at 08:08
  • You could also try to use a regex directly like `proxy_redirect ~^http://((www\.)?.+\.example\.com)/prefix-.+$ http://$1`. But on my rig the original form with variables do work, nginx 1.6.1. – Xavier Lucas Oct 22 '14 at 08:18
  • Well there's something you missed to post in the OP so because all works good here. – Xavier Lucas Oct 22 '14 at 08:49
  • It's literally copied from my config. I just change actual domain name and app name. I'm wondering whethet it can be something with the application, but considering that it works when regex is substituted with static name i would say it's not the case. //EDIT: I've just checked with plain Java application (no redirects, two plain servlets etc), the same issue, it seems that the proxy_redirect is not appending the URI – Stugal Oct 22 '14 at 09:52
  • I'm not sure it explains the thing but could you set your `proxy_pass` to `http://backend/prefix-$sub_domain$request_uri` ? You meant removing the `prefix-myapp` instead of appending in your last comment right ? – Xavier Lucas Oct 22 '14 at 10:34
  • I meant that changing prefix-$sub_domain to prefix-myapp solves all issues. Now I've added the $request_uri, it works for the test app (the plain simple java 2 servlet weba app) and it doesn't for the production one with authentication mechanism (this is causing redirects) – Stugal Oct 22 '14 at 10:41
  • For anyone running in docker, you can just add `resolver 127.0.0.11;` as suggested [here](http://stackoverflow.com/a/37656784/1194883), for example. – Mike Mar 18 '17 at 17:44

1 Answers1

12

When you are using variables in a proxy_pass directive, nginx will use runtime resolving except if :

  • the target server is declared as an IP address
  • the target server name is part of an upstream server group
  • the target server name has already been resolved (e.g. it matches a server name in another server block)

Here, a runtime resolver won't help as localhost may not be resolved by a DNS. Also it's a waste to have runtime resolving as you can clearly avoid it here.

So, two simple solutions :

  • use 127.0.0.1
  • declare an upstream block if you have server names or a pool of target servers

Now you need your proxied server redirection to be correct. So either :

  • your proxy target handles the host header and you pass it through with :

    proxy_set_header "Host" $host;

  • your proxy target can't handle the Host header for redirects and you need to rewrite them with nginx using :

    proxy_redirect http://$proxy_host/$sub_domain http://$host;

However if it doesn't support the Host header at all, links will be broken.

Xavier Lucas
  • 12,815
  • 2
  • 44
  • 50
  • Hi Xavier. Many thanks for your advise, however I've tried already with 127.0.0.1 instead of localhost, unfortunately to no effect :/ – Stugal Oct 21 '14 at 13:24
  • @Stugal Check updated answer. – Xavier Lucas Oct 21 '14 at 13:38
  • I'm getting closer! I've added the upstream block with 127.0.0.1. I've also added the proxy_set_header "Host" $host; above my proxy_pass line. The only problem now is that i think the $host variable is subdomain.example.com/myapp, and it would have to be just subdomain.example.com – Stugal Oct 21 '14 at 15:14
  • @Stugal The $host variable doesn't contain an URI. – Xavier Lucas Oct 21 '14 at 15:17
  • why do I end up at subdomain.example.com/myapp/login instead of subdomain.example.com/login ? – Stugal Oct 21 '14 at 15:19
  • @Stugal Because your proxy target don't subsitute the myapp part in redirects ? In this case you need to add `proxy_redirect http://$host/$sub_domain http://$host;`. It would be good to put your actual configuration and results because it's hard to get visibility on what you are doing. – Xavier Lucas Oct 21 '14 at 15:38