How can Tomcat 9 Connector listening 127.0.0.1 rev

2019-08-27 11:56发布

问题:

I'm wanting Tomcat 8080 to listen only on 127.0.0.1, and reverse proxy to Windows Apache 2.4 that uses a private network ServerName

I don't want tomcat port 8080 to be accessible outside of the machine where Tomcat is running.

The Tomcat web app deployed is a Spring MVC web app with a spring security login page

I tried the simple setup from these links, questions and apache docs:

How to set a IP address to the tomcat?

https://cgsrv1.arrc.csiro.au/blog/2009/07/10/tomcat-listen-only-on-localhost/

https://julienprog.wordpress.com/2017/06/21/how-to-bind-apache-server-non-localhost-to-tomcat-server/

https://wiki.jasig.org/display/UPM43/Fronting+Tomcat+with+Apache+HTTP+Server

What's happening is - it seems like the reverse proxy or tomcat connector is redirecting the client browser to HTTP localhost/acme - instead of providing the fronted proxy apache server with data from HTTP localhost:8080/acme

The client browser should be getting/displaying data on the URL: https my.server.domain/acme

I'm wanting the flow to be:

user client -> https apache -> http tomcat http -> https apache -> user client

apache and tomcat live on the same Windows 7 server machine with jdk8

I don't see anything helpful or errors in any logs

I'm thinking that tomcat is correctly listening only on 127.0.0.1 - but when the apache reverse proxy happens, it gets the data from tomcat - and then for some reason, it is making the client's browser(separate network machine) get directed to:

HTTP localhost/acme instead of letting the client browser URL remain on: https my.server.domain/acme

Note it did not make the client browser attempt going to 8080 so that's good

The client definitely isn't hosting their own webapp at the URL HTTP localhost/acme which they get directed to so the client browser displays: HTTP Error 404. The requested resource is not found.

I don't think the spring MVC security login page would be the culperit

My apache httpd.conf has this line: ServerName my.server.domain:80

I'm thinking I can't change that value because my SSL cert common name and SAN is based on that private network name, so I need it to stay that for the SSL connection to be valid.

I'm using Rewrite to require SSL below but I don't think that would be the problem

I can get the proxy/reverse-proxy and https working, without my full goal of blocking 8080, by doing this:

apache httpd.conf:

ProxyPass         /acme  http://my.server.domain:8080/acme
ProxyPassReverse  /acme  http://my.server.domain:8080/acme

tomcat server.xml: (note: not listening on just 127.0.0.1)

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

<Connector  
    port="8009" 
    protocol="AJP/1.3" 
    redirectPort="8443" />  

Here are my config files below that cause the undesirable browser redirect:


apache httpd.conf

Listen 80

ServerName my.server.domain:80

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

ProxyPass         /acme  http://localhost:8080/acme
ProxyPassReverse  /acme  http://localhost:8080/acme

LoadModule rewrite_module modules/mod_rewrite.so

Include conf/extra/httpd-vhosts.conf
Include conf/extra/httpd-ssl.conf

apache httpd-vhosts.conf

# I have this so httpS only is supported
<VirtualHost _default_:80>  
  ServerName my.server.domain  
  RewriteEngine On
  RewriteCond %{SERVER_PORT} !443
  RewriteRule ^(/(.*))?$ https://%{HTTP_HOST}/$1 [R=301,L]            
</VirtualHost>

apache httpd-ssl.conf

I set my paths for: server cert, private key, CA intermediary cert


tomcat server.xml

<!-- Note: proxyPort="80"  I think is correct right? (from docs) -->

<Connector  
   address="127.0.0.1"
   port="8080" 
   protocol="HTTP/1.1"
   connectionTimeout="20000"
   redirectPort="8443" 
   proxyPort="80" />

<Connector  
    address="127.0.0.1" 
    port="8009" 
    protocol="AJP/1.3" 
    redirectPort="8443" />   

==============================================

Sure I can use Ms Windows IP filtering to block 8080 too, I was hoping to get this connector address working as well

回答1:

I found the solution:

In my Tomcat server.xml, I needed to edit the http connector and add the additional attribute:

proxyName="my.server.domain"

so that it appears as:

<Connector
 port="8080"
 address="127.0.0.1"
 protocol="HTTP/1.1"
 connectionTimeout="20000"
 redirectPort="8443"
 proxyPort="80"
 proxyName="my.server.domain"
 />

This allows the tomcat-hosted spring mvc webapp to construct urls resembling:

http://my.server.domain/acme

instead of:

http://localhost/acme

=========================================

The problem that had been happening when missing the attribute: proxyName="my.server.domain" --- was:

The spring mvc webapp hosted on Tomcat was constructing urls to handle requests - and it was asking Tomcat: "What is your server name?" - to which Tomcat was replying "localhost" (the value Tomcat received requests as from the Apache proxy). So spring was using "localhost" when it was constructing urls to resemble: http://localhost/acme

The fronted Apache proxy was receiving these urls from Tomcat responses(from the spring mvc webapp responses) - and the Apahe proxy was giving the end user client browser this url to go to: http://localhost/acme The end user client definitely does not have that webapp hosted on their local machine - so the browser was giving them the: HTTP Error 404

=========================================

One can see this clearly from the apache proxy config:

ProxyPass         /acme  http://localhost:8080/acme
ProxyPassReverse  /acme  http://localhost:8080/acme

Apache is sending in a url containing "localhost" in the request - to tomcat. The Tomcat connector response must specify the real proxyName (not localhost) to Apache that should be given back to the clients.

=========================================

Tomcat connector docs:

*proxyName

If this Connector is being used in a proxy configuration, configure this attribute to specify the server name to be returned for calls to request.getServerName(). See Proxy Support for more information.

Proxy Support

The proxyName and proxyPort attributes can be used when Tomcat is run behind a proxy server. These attributes modify the values returned to web applications that call the request.getServerName() and request.getServerPort() methods, which are often used to construct absolute URLs for redirects. Without configuring these attributes, the values returned would reflect the server name and port on which the connection from the proxy server was received, rather than the server name and port to whom the client directed the original request.*

============================================

A lot of the blogs online - that mention how to make tomcat connectors listen only on 127.0.0.1 - do not explain that the proxyName must be set in a addition to the proxyPort, if you have a webapp like spring mvc that's constructing url's - and you are using apache mod proxy to send request urls of localhost to Tomcat.