1

I'm trying to use nginx as a load balancer / proxy server which points to a series to tomcat servers. This is my current nginx configuration.

server {

    listen 80;
    server_name _;
    rewrite ^ https://$http_host$request_uri? permanent;
}

server {
     listen 443;

     resolver 127.0.0.11 valid=5s;

     ssl on;
     ssl_certificate /etc/nginx/certs/default.crt;        # path to your cacert.pem
     ssl_certificate_key /etc/nginx/certs/default.key;    # path to your privkey.pem
     ssl_verify_client off;
     server_name localhost;
     fastcgi_param   HTTPS               on;
     fastcgi_param   HTTP_SCHEME         https;

     charset utf-8;
     client_max_body_size 200M;

     set $app https://app:8443;
     set $auth https://auth:8443/authentication/;
     set $discovery https://discovery:8443/discovery/;

   location / {
       proxy_pass $app;
   }
   location /authentication {
       proxy_pass $auth;
   }
   location /discovery {
       proxy_pass $discovery;
       proxy_set_header Host $http_host;
       proxy_set_header X_FORWARDED_PROTO https;
   }

}

This is dockerized if it makes any difference, but provisioning fails to resolve correctly while docs is working fine. The only difference between docs and provisioning is that 'docs' is serving pure html files via tomcat. (The tomcat7 standard /docs/) while provisioning is actually a java servlet (JaxRS/spring etc ).

If I hit the image directly it works as expected, while if I try to hit the same endpoint via the nginx it fails to resolve.

My docker-compose configuration for reference.

version: '2'
services:
  db:
    image: db:nodata
    expose:
    - 5433
  zk:
     image: zookeeper
     ports:
     - 2181:2181
  discovery:
    image: services_discovery:latest
    env_file: docker_environment
    expose:
    - 8443
    ports:
    - 8443:8443
    links:
     - db
     - zk
  app:
    image: tomcat-jsse-ssl:7-jdk8
    volumes:
    - ./app/www/:/usr/local/tomcat7/webapps/ROOT/
    expose:
    - 8443
    ports:
    - 8444:8443
  auth:
    image: tomcat-jsse-ssl:7-jdk8
    volumes:
    - ./authentication/www/authentication/:/usr/local/tomcat7/webapps/authentication/
    expose:
    - 8443
  proxy:
    build: ./proxy/
    depends_on:
     - 'auth'
     - 'app'
     - 'discovery'
    ports:
    - 443:443
    restart: always

With the images running I can resolve the following URLs just fine.

ie. both containers are running fine:

Server Logs:

proxy_1      | 172.20.0.1 - - [24/Apr/2017:00:04:28 +0000] "GET /discovery/ready HTTP/1.1" 404 400 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"
proxy_1      | 172.20.0.1 - - [24/Apr/2017:00:04:43 +0000] "GET /discovery/api/swagger.json HTTP/1.1" 404 400 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"
proxy_1      | 172.20.0.1 - - [24/Apr/2017:00:04:57 +0000] "GET /discovery/ready HTTP/1.1" 404 400 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"

Discovery Tomcat Access Log (when access directly)

172.20.0.1 - - [23/Apr/2017:00:02:38 +0000] "GET /discovery/ready HTTP/1.1" 200 70
172.20.0.2 - - [24/Apr/2017:00:04:28 +0000] "GET /discovery/ HTTP/1.0" 404 949
172.20.0.2 - - [24/Apr/2017:00:04:43 +0000] "GET /discovery/ HTTP/1.0" 404 949
172.20.0.2 - - [24/Apr/2017:00:04:57 +0000] "GET /discovery/ HTTP/1.0" 404 949

The first entry is when I hit the server directly via https://localhost:8443/discovery/ready everything else is when nginx sends the request to the server. For some reason it's not translating the request correctly.

Any thoughts/suggestions would be appreciated?

Note: I simplified my example/config for the purposes of this question and any references to "provisioning" are now "discovery".

UPDATE: I figured out why it's breaking for the 'servlet'. It's actually breaking constantly. It's stripping away all of the URL except the base.

for example.

https://localhost/authentication?q=dummy

becomes 172.20.0.3 - - [24/Apr/2017:03:22:06 +0000] "GET /authentication/ HTTP/1.0" 200 28

note that the query parameters are stripped away.

csgeek
  • 270
  • 3
  • 19
  • Are the containers on the same docker network? – BMitch Apr 20 '17 at 18:18
  • Yeah, same network. If I enter the nginx container I see all the various containers and can ping them as I said, as long as the data is static html/css it seems to work okay. – csgeek Apr 23 '17 at 02:37
  • Do you see an error in the provisioning container logs? Can you tell which container generated the 404? – BMitch Apr 23 '17 at 02:40
  • nope, everything works as expected. If I expose the port tomcat is running on 8443 to my laptop, I can connect to the servlet and everything works as expected. If I try to go through nginx that's when it fails. It's nginx that's causing issues as far as I can tell. Or a combination of tomcat/nginx. I setup a test case here: https://github.com/safaci2000/docker_loadbalancer. I'm using the same pattern (except not using tomcat for the app) and for the example all works as expected, but tomcat + servlet is causing issues. – csgeek Apr 23 '17 at 02:58
  • Can you tell from the provisioning server logs, whether a request comes in? There's a chance that nginx doesn't even try to reach the provisioning container. – gesellix Apr 23 '17 at 11:29
  • Please update the question to include the container logs of both nginx and provisioning for both the working and broken scenarios. – BMitch Apr 23 '17 at 11:29
  • It would also help if you added a minimal (broken) Java app in your Github test case repository. – gesellix Apr 23 '17 at 11:42
  • Update the description and added server logs from both tomcat server and nginx proxy. – csgeek Apr 24 '17 at 01:01

1 Answers1

2

The nginx documentation says that you are responsable to rebuild the url:

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

So, you can try to capture the rest of the URI using regex and send it on the proxy_pass section:

location ~* ^/discovery/(.*) {
  proxy_pass $discovery$1$is_args$args;
  .... other configs....
}
Oscar Romero
  • 121
  • 3
  • this worked for me awesome! Just a few follow up questions. I assume (.*) gets mapped to $1. I got the $vars definitions from: http://nginx.org/en/docs/http/ngx_http_core_module.html. What's the purpose to ~* – csgeek Apr 25 '17 at 14:42
  • Ah, got it. ~* marks it as a regex pattern. Thanks! – csgeek Apr 25 '17 at 14:51