Tomcat behind Nginx: how to proxy both HTTP and HTTPS, possibly on non-standard ports?

10,304

Actually what I want really is not possible, so it's required to have two separate Connector tags and two upstreams in Nginx, like so:

Tomcat's server.xml:

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           proxyPort="80"
/>

<Connector port="8443" protocol="HTTP/1.1"
           connectionTimeout="20000"
           proxyPort="443"
           scheme="https" secure="true"
/>

Matching Nginx configuration:

server {
  listen 80;
  listen 443 ssl spdy;

  location /saiku-ui {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://saiku-server-$scheme; # This is upstream name, note the variable $scheme in it
    proxy_redirect off;
  }
}

upstream saiku-server-http {
  server     ip.of.tomcat.server:8080;
}

upstream saiku-server-https {
  server     ip.of.tomcat.server:8443;
}

Please note that Tomcat receives plain HTTP traffic on both 8080 and 8443 ports (no SSL there, it's terminated by Nginx), but for connections on 8443 port it will generate links must start with https:// instead of http:// (via attributes scheme="https" secure="true") and will insert in links ports, specified in proxyPort attribute.

Nginx will terminate SSL and proxy all secure connections to the 8443 port of Tomcat via saiku-server-https upstream, where https is the value of $scheme Nginx request variable (see location block)

Share:
10,304
Envek
Author by

Envek

Web developer with a strong passion to build rock solid applications: secure, reliable, fast.

Updated on June 21, 2022

Comments

  • Envek
    Envek about 2 years

    Description

    We're installing some application running Tomcat 6 behind Nginx for different clients. Some of those installations are HTTP only, some HTTPS only, somewhere both. One of those installations has HTTP and HTTPS working on non-standard ports (8070 and 8071) due to lack of public IPs. Application at hand is displayed as an iframe in another app.

    Current behaviour

    Tomcat redirects all HTTPS requests to HTTP (so nothing displayed in iframe due to browser restrictions for mixed content).

    Current configuration

    Iframe code:

    <iframe src="/saiku-ui">
    

    Tomcat's server.xml:

    <Connector port="8080" protocol="HTTP/1.1"/>
    <!-- A bit later... -->
    <Valve className="org.apache.catalina.valves.RemoteIpValve"
          remoteIpHeader="x-forwarded-for"
          protocolHeader="x-forwarded-proto"
        />
    

    Nginx vhost:

    server {
      listen 80;
      listen 443 ssl spdy;
    
      location /saiku-ui {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://saiku-server; # This is upstream name
        proxy_redirect off;
      }
    }
    
    upstream saiku-server {
      server ip.of.tomcat.server:8080;
    }
    

    Desired behaviour

    1. Tomcat should listen on one single port for both HTTP and HTTPS requests.

      If there will be two <Connector> tags it will be much harder to configure Nginx.

    2. Tomcat should not redirect between schemas.

    3. Nginx may listen on arbitrary ports (e.g. listen 8071 ssl spdy;).
    4. Links, generated by Tomcat should be either relative or include schema, host, and port as provided by Nginx.

    Additional info

    I've tried to add schema and proxyPort attributes to <Connector>, after that Tomcat will always redirect from HTTP to HTTPS (at least it's better).

    I can't google such a configuration and not experienced with Tomcat. Please help.