Nginx as reverse proxy for Docker-contained Tomcat

Consider the following diagram:

infrastructure diagram

I have a Debian droplet from Digital Ocean where I need to deploy N Java applications inside individual Docker containers running a Tomcat instance.

Each image has the following Dockerfile configuration:

FROM tomcat:jdk8-openjdk
LABEL maintainer="[email protected]"
ADD webapp1.war /usr/local/tomcat/webapps/ #webapp1, webapp2,... webappN
EXPOSE 8080
CMD ["catalina.sh", "run"]

And is built with:

docker build -t webapp1 .
docker build -t webapp2 .
...

Each container is started with the command:

docker run -it -d -p 8081:8080 webapp1
docker run -it -d -p 8082:8080 webapp2
...

Every application works correctly and is accesible through the droplet IP address, port and application name:

http://123.123.123.123:8081/webapp1
http://123.123.123.123:8082/webapp2
...

But I need to use a domain name (without SSL for now):

http://example.com/webapp1
http://example.com/webapp2
...

So I'm using Nginx as reverse proxy to achieve this. The following is the Nginx configuration in sites-available folder I'm using:

default file:

# Default server configuration
#
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

webapp1 file:

# webapp1 configuration
#
server {
  listen 80;

  server_name example.com;
  access_log /var/log/nginx/tomcat-access.log;
  error_log /var/log/nginx/tomcat-error.log;

  location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://123.123.123.123:8081/;
  }
}

webapp2 file:

# webapp2 configuration
#
server {
  listen 80;

  server_name example.com;
  access_log /var/log/nginx/tomcat-access.log;
  error_log /var/log/nginx/tomcat-error.log;

  location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://123.123.123.123:8082/;
  }
}

Here's the problem, when I deployed the first application and made it accesible through the domain name (example.com/webapp1) it was working fine but an 404 error was produced when I try to access example.com (my landing page). I decided to solve this problem later and better to try to deploy a second application. It worked, webapp2 was successfully deployed and was accesible through example.com/webapp2 but now both example.com and example.com/webapp1 are giving an 404 error.

I'm a Nginx and Docker newbie. Please, help.


Solution 1:

In Nginx a server configuration block defines a single named virtual host. If you define multiple server blocks for the same domain, there should be a warning in the logs, but a single server block will be chosen, the others will be ignored.

What you need is multiple location blocks. So you need a single sites-available/example.com configuration (symlinked from sites-enabled/example.com) like this:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    server_name example.com;

    location / {
        try_files $uri $uri/ =404;
    }

    # For each web application
    location /webapp1/ {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://192.0.2.1:8081;
    }
}

Remark: the X-Forwarded-For and X-Forwarded-Proto headers have no effect on Tomcat, unless you add:

    <Valve className="org.apache.catalina.valves.RemoteIpValve" />

to the Tomcat <Host> configuration.