Tomcat / Apache / Grails Config - apache

Hoping someone can help / advise as i'm not very familiar with Apache / Tomcat .. I already have Apache in front of Tomcat with grails app deployed. I have IIs setup (by someone else) which redirects www.xyz.com/myApp to an Apache instance which runs a grails app. In my apache conf I have a proxy ..
ProxyPass /myApp http://localhost:8080/myApp
ProxyPassReverse /myApp http://localhost:8080/myApp
and I have a connector defined in my tomcat server.xml
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
proxyName="www.xyz.com"
proxyPort="443" />
This works without problem
I now want to add another app so in IIS I had setup for me www.xyz.com/myOtherApp
with
ProxyPass /myOtherApp http://localhost:8081/anotherApp
ProxyPassReverse /myOtherApp http://localhost:8081/anotherApp
in my Apache conf I added another connector
<Connector port="8081" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
proxyName="www.xyz.com"
proxyPort="443" />
When i go to www.xyz.com/myOtherApp i get the url rendered (correctly i think) as https://www.xyz.com/anotherApp but with a 404 error saying "Object not Found" ..
Can anyone help me with the config ? Is it possible to have 2 connectors on different ports
with the same proxyName ? As i say i'm not familiar with Apache/Tomcat and i'd really like to get this done asap ..
Thanks
Hi #Stefan, The apps do live on the same server and domain so i eliminated one of the connector definitions . I'm now left with
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
proxyName="www.xyz.com"
proxyPort="443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
</Server>
Also I switched on the logging (JULI) but it didn't seem to report anything . The apache error log just gives me a 404 .. I left it as HTTP rather than AJP as i'd have to setup HTTPS and i'm not sure how easy that is. So i'm left with the same problem in that one app works, the other doesn't .. Is it possible to run multiple grails apps over http as opposed to using ajp and virtual hosts ? Forgive me if i'm being stupid - i haven't had much exposure to webapps and i seem to have come to a grinding halt at what i thought should have been relatively easy - deployment !

If you want to use Apache in front of Tomcat, it's better to use mod_proxy_ajp instead of mod_proxy_http. For setting this up, see https://confluence.sakaiproject.org/display/~steve.swinsburg/Fronting+Tomcat+with+Apache+via+mod_proxy_ajp.
Be sore to add
ProxyRequests Off
<Proxy *>
Order deny,allow
Deny from all
Allow from localhost
</Proxy>
to your config to prevent abuse of the proxy.
If /myApp and /myOtherApp reside in the same tomcat engine, you only need a single connector for both apps. Aside from this, I can see no obvious error in your setup. Maybe you could post your tomcat's server.xml. During working on the config, using LogLevel Debug might be a good idea.

This isn't a direct answer to your question, but I was configuring Tomcat behind Apache before and I had problem with it.
I now use Amazons Elastic beanstalk...where you can deploy your grails app war file directly. It works a beautifully, especially with in built auto scaling and health monitoring!
Less configuration == Ease of life.

Related

Tomcat 9 - long https request

I am sending a request that includes media and has a contentLength of about 200k.
It works fine when sending to the non-SSL port but when sending to the SSL port
the ByteBuffer of the request's Reader does not contain all the request.
I think it has to do with the appReadBufSize setting.
A shorter, 255-byte SSL request works fine - so the problem is not with SSL
but has to do with the length.
I suppose it should be possible to pass long SSL requests to Tomcat but did not
find any reference about the difference between SSL and non-SSL handling of long requests. The connector uses openssl.
server.xml connector definitions:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000" maxPostSize="-1"
maxThreads="150" SSLEnabled="true" sslProtocol="TLS"
scheme="https" secure="true" clientAuth="false"
... SSL keystore definitions/>
Please advise,
Many thanks,
Yuval
It turned out that there was indeed a bug in Tomcat:
http://tomcat.10.x6.nabble.com/Bug-64486-New-Receiving-null-empty-request-body-when-SSL-enabled-td5099846.html
I was running Tomcat 9.0.31 under Ubunto 20. The problem disappeared when upgrading to Tomcat 9.0.37 (manual install).

Redirect http to https on Tomcat 7 application

I have a webapp application running on Tomcat7 which connects easily via https but returns Unable to connect error when accessed without it.
Below is my server.xml file content
<Service name="Catalina">
<Connector protocol="org.apache.coyote.http11.Http11Protocol"
port="443"
maxThreads="200" scheme="https"
secure="true" SSLEnabled="true"
keystoreFile="/usr/share/.keystore"
Host is Amazon lightsail and port 80 and 443 are available. I noticed port 80 which is meant to enable non-http traffic is not in use. 443 is anyway.
I have tried other methods on SO and other blogs, none seem to be working.
Finally,
I stumbled on what could have been the troubling issue.
After adding the connector code for port 80 and redirecting to 443.
I changed this section of my code to
<Service name="Catalina">
**<Connector port="443" protocol="HTTP/1.1"**
maxThreads="200" scheme="https"
secure="true" SSLEnabled="true"
keystoreFile="/usr/share/.keystore"
keystorePass="xxx111!!"
And editing the web.xml file as always advised. I guessed the major change was in the code section below.
Hoping this helps someone out there.

Issues with configuration of Bitbucket Server with HTTPS reverse proxy using Tomcat

I'm trying to install some Atlassian products (Bitbucket Server, Jira, Confluence etc.) on my VPS with using HTTPS. Every product should be available on their own subdomain e.g. https://bitbucket.mydomain.de or https://jira.mydomain.de I tried many things but now I'm very confused. It always redirect me to the Tomcat-GUI instead of my installed Bitbucket Server application. Maybe managing the ports is too confusing for me.
Three configuration files are involved - Tomcats server.xml, Apaches mydomain.conf file and Bitbuckets bitbucket.properties configuration.
I've tried to use an own Bitbucket Connector in Tomcat, while using an reverse Proxy in Apache. Here are some of my files.
Apaches mydomain.conf
<VirtualHost *:443>
ServerName bitbucket.mydomain.de
ServerAlias bitbucket.mydomain.de
ProxyRequests Off
<Proxy *>
Require all granted
</Proxy>
ProxyPass / http://bitbucket.mydomain.de:7990/
ProxyPassReverse / http://bitbucket.mydomain.de:7990/
SSLEngine on
SSLCertificateFile /etc/ssl/certs/mydomain_ssl_certificate.cer
SSLCertificateKeyFile /etc/ssl/private/mydomainprivate_key.key
SSLCertificateChainFile /etc/ssl/certs/mydomain_ssl_certificate_intermediate.cer
</VirtualHost>
Bitbuckets bitbucket.properties
server.port=7990
server.secure=true
server.scheme=https
server.proxy-port=443
server.proxy-name=bitbucket.mydomain.de
And Tomcats server.xml
<Server port="8005" shutdown="SHUTDOWN">
<...>
<Service name="Catalina">
<!-- Default Connector -->
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
<!-- Bitbucket Connector -->
<Connector port="7990" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="443" compression="on" compressableMimeType="text/html,text/xml,text/plain,text/css,application/json,application/javascript,application/x-javascript"
secure="true" scheme="https" proxyName="bitbucket.mydomain.de" proxyPort="443" />
<!-- SSL Connector -->
<Connector port="8443" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false"
disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keyAlias="tomcat"
SSLEnabled="true" keystoreFile="keystore/mydomain-keystore.jks" keypass="mypass" keystoreType="JKS"/>
</Service>
</Server>
Actually, it shows me on bitbucket.mydomain.de every single time the Tomcat GUI instead of Bitbucket.. and I can't explain why. What am I missing? I think the whole server.xml is misconfigured...
Thanks a lot for every help!
You can use something a little bit lighter than Apache like haproxy. Haproxy is available as a standard Linux package. Haproxy will terminate your SSL connection. It will act as a reverse proxy for the various Atlassian applications. See the following link for information on how to set it up:
https://confluence.atlassian.com/bitbucketserver/securing-bitbucket-server-behind-haproxy-using-ssl-779303273.html
You won't have to change your Tomcat server.xml

Redirect HTTP to HTTPS:PORT in Tomcat

I have a running tomcat application that already have the following redirection rule from HTTP to HTTPs:
<Connector executor="tomcatThreadPool"
port="80"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" />
Is it possible to add an exception/rule, that a specific HTTPrequest (http://www.example.com), will be redirected to another specific address , with a port specified (say https://www.example.com:8443/test), without changing/removing the above Connector ?
You can do it to every app deployed to tomcat by adding this to the end of tomcat_dir/conf/web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>Entire Application</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<!-- auth-constraint goes here if you requre authentication -->
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
So you don't have to change it on the web.xml of your webapp.
That should work, assuming you already have https working in another port (usually 443). If you don't, make sure your tomcat_dir/conf/server.xml looks like this:
<!-- Default tomcat connector, changed the redirectPort from 8443 to 443 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" />
<!-- To make https work on port 443 -->
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/>
<SSLHostConfig>
<Certificate certificateKeyFile="/your/own/privkey.pem"
certificateFile="/eyour/own/cert.pem"
certificateChainFile="/your/own/chain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
The connector configuration you shown does not redirect a specific URL in the way you suppose.
That configuration acts if you have configured a CONFIDENTIAL transport guarantee for a web application inside that servlet container.
I mean, if you have deployed any application on that connector, where its web.xml descriptor has a security-constraint as follows:
<security-constraint>
<web-resource-collection>
<web-resource-name>Secured</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
...
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Then, Tomcat will redirect any matching url-pattern to the configured port in order to use HTTPS as guarantor of confidentiality in transport.
So, if you want to redirect a specific URL, you have to complement connector's configuration with specific application configuration.
Edit
As you suggest in your comment, it could be another step to get this configuration working. Once you have configured http connector as shown, and then configured app as I told you, you only to ensure that your Tomcat server has an HTTPS connector configured, other way redirection won't work.
To configure this HTTPS connector, you can use a configuration as following:
<Connector connectionTimeout="20000"
acceptCount="100" scheme="https" secure="true"
port="443" clientAuth="false" sslProtocol="TLS"
keystoreFile="PATH_TO_KEY_STORE"
keystorePass="KEY_STORE_PASS"
keyAlias="KEY_STORE_ALIAS"/>
This is a sample configuration where I didn't put some attributes that can be important for you as threads attrs, executors, and so on.
The most important thing is the KeyStore configuration that you need to serve HTTPS connections. Here you have the official documentation to prepare a java KeyStore for Tomcat to serve HTTPS.
I have a running tomcat application that already have the following redirection rule from HTTP to HTTPs:
As malaguna answered, that Connector configuration is not a redirection rule. It is just a setting that is used when performing redirection triggered by <transport-guarantee>CONFIDENTIAL</transport-guarantee>.
There is no way to overwrite that setting on per-application basis.
If you need better control over such redirection, you need to implement your own Filter that will implement a redirection (if (!request.isSecure()) { response.sendRedirect(...);}), or configure a 3rd party one.
// Technically, in current Tomcat 8 code the redirection triggered by transport-guarantee is performed by org.apache.catalina.realm.RealmBase.hasUserDataPermission(...) method.
If you use tomcat with httpd, you can use RewriteEngine.
With port specified is like the followings in the http.conf:
NameVirtualHost *:8443 #your specified port
<VirtualHost *:8443>
ServerName www.example.com
Redirect permanent / https://secure.example.com/
</VirtualHost>
See: RewriteHTTPToHTTPS and Redirect Request to SSL
Putting transport-guarantee CONFIDENTIAL in conf/web.xml is good, but it does not cover the manager app and the host-manager app (Tomcat 8.5.38).
My solution is to put a valve in conf/context.xml that redirects all http requests to https.
https://bitbucket.org/bunkenburg/https-valve/src/master/
It's too late to answer, still I'm sharing my experience over the same, do the following changes in
Apache Software Foundation\Tomcat 8.5\conf\web.xml
Take a restart.
Pre-Req: configure https port and disable http port(optional[I did it])
<Connector connectionTimeout="20000" port="8081" protocol="HTTP/1.1" redirectPort="443"/>
<Connector port="443"
SSLEnabled="true"
acceptCount="100"
disableUploadTimeout="true"
enableLookups="false"
maxHttpHeaderSize="8192"
maxThreads="550"
minSpareThreads="25"
scheme="https"
secure="true"
compression="on"
protocol="org.apache.coyote.http11.Http11NioProtocol"
sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/>
<SSLHostConfig protocols="TLSv1.2"
certificateVerification="none"
ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA">
<Certificate type="RSA"
certificateKeystoreFile="/ssl/self-signed/your-keystore.jks"
certificateKeystorePassword="123456"
certificateKeyAlias="your-alias" />
</SSLHostConfig>
   </Connector>

Tomcat subdomain association

I have a Spring application accessible as www.mydomain.com on Amazon AWS. Now I want another Spring application under the same Amazon instance (and hence using the same tomcat) to be accessible under mysubdomain.mydomain.com. My tomcat is fronted with Apache.
App corresponding to www.mydomain.com is located at:
/env/tomcat/apache-tomcat-7.0.26/webapps/ROOT
For the app to be accessible at mysubdomain.mydomain.com, I have created another folder at:
/env/tomcat/apache-tomcat-7.0.26/mysubdomainapps/ROOT
Below are the contents of server.xml and httpd.conf
server.xml
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Note: A "Server" is not itself a "Container", so you may not
define subcomponents such as "Valves" at this level.
Documentation at /docs/config/server.html
-->
<Server port="8005" shutdown="SHUTDOWN">
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
<Listener className="org.apache.catalina.core.JasperListener" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
<!-- Define a SSL HTTP/1.1 Connector on port 8443
This connector uses the JSSE configuration, when using APR, the
connector should be using the OpenSSL style configuration
described in the APR documentation -->
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
-->
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine name="Catalina" defaultHost="localhost">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
**<Host name="mysubdomain.mydomain.com" appBase="mysubdomainapps" unpackWARs="true" autoDeploy="true"></Host>**
</Engine>
</Service>
</Server>
httpd.conf
<VirtualHost *:80>
ServerName localhost
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
<VirtualHost *:80>
ServerName mysubdomain.mydomain.com
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
It's been hours I'm trying to sort it out, but couldn't succeed.
I'd really appreciate your help.
Thanks,
James
It worked! For DNS, I had created a CNAME earlier. I tried with A-record, and it worked great!