This section demonstrates how to run the TDS and Tomcat Servlet Container behind an Apache HTTP proxy server using the mod_jk connector.

About Reverse Proxies

View the Wikipedia entry on Reverse Proxies for more information on reverse proxies uses and types of proxies servers.

Uses Of Reverse Proxies

  • A reverse proxy is a proxy server that appears to clients to be an ordinary server. Requests are forwarded to one or more origin servers which handle the request. The response is returned as if it came directly from the proxy server.

    reverse proxy
  • Reverse proxies can be used to hide the existence and characteristics of the origin server(s) and can be an additional layer of defense and can protect against some OS and WebServer specific attacks. However, it does not provide any protection to attacks against vulnerabilities in the web application or proxy service itself (e.g., Apache, Tomcat).
  • A reverse proxy can also be used for load balancing, caching content, content compression, and SSL acceleration.

Using Tomcat And Apache HTTP Server

  • Using Apache as a front-end proxy server for the TDS running on Tomcat is perhaps the easiest method for setting up a reverse proxy for the TDS. There are two methods to accomplish this:
    • Apache’s mod_proxy in combination with Tomcat’s HTTP connector; or
    • the mod_jk Apache module with the Tomcat AJP connector.

Tomcat-Apache Proxy Documentation

  • Tomcat Connectors Documentation describing the difference between the Tomcat HTTP and AJP connectors.
  • mod_proxy
  • mod_jk
    • Tomcat AJP Connector Configuration for the Tomcat AJP connector (for use with Apache’s mod_jk).
    • Tomcat Reverse Proxy - How To Configurations and fine-tuning of a reverse proxy set up using the mod_jk Apache module.

Implementing The Tomcat-Apache Proxy Using AJP

The following example shows how to implement a proxy using the Apache HTTPD server, Tomcat Servlet Container, and Tomcat’s mod_jk on a linux system.

Install mod_jk

  1. Download the latest version of Tomcat’s mod_jk module.

  2. Build and install the mod_jk module as per the installation instructions that come bundled with the download. The build and installation will need to be done as either root, sudo, or as user with privileges to modify Apache.

     # tar xvfz tomcat-connectors-1.2.xx-src.tar.gz
     # cd tomcat-connectors-1.2.xx-src/native
     # ./configure --with-apxs=/usr/bin/apxs  <--- path to your apache apxs
     # make
     # make install
    

    Confirm the module was added to the directory in which the Apache HTTPD server stores its modules (/usr/local/apache/modules in this example):

     # cd /usr/local/apache/modules
     # ls -l  mod_jk.so
        
     -rwxr-xr-x 1 root root 1147204 Oct  8 12:34 mod_jk.so
    

Configure Apache HTTP Server To Use mod_jk To Talk To Tomcat

  1. Update Apache configurations to use the mod_jk module.

    mod_jk was built as a DSO module, therefore you will need to update your Apache configurations to enable this 3rd-party module:

    The following example shows adding mod_jk configurations to a Apache HTTPD 2.4 server built from source.
    Modify the main Apache server configuration file (usually httpd.conf) in the following manner (in this example /usr/local/apache/conf is where the Apache configuration files are located):

    # cd /usr/local/apache/conf
    # vi http.conf
    

    Add the following configurations to enable the mod_jk module, restrict access to web application WEB-INF and META-INF directories, and tell Apache where to find the workers.properties file using the JkWorkersFile directive. (The worker.properties file is discussed in more detail below.)

    # Third party modules
    LoadModule jk_module    modules/mod_jk.so
     
    <IfModule jk_module>
        JkWorkersFile "conf/workers.properties"
        JkShmFile "logs/mod_jk.shm"
        JkLogFile "logs/mod_jk.log"
        JkLogLevel warn
        #Tomcat Security Section
        <LocationMatch "/WEB-INF/">
            Require all denied
        </LocationMatch>
        
        <LocationMatch "/META-INF/">
            Require all denied
        </LocationMatch>
    </IfModule>
    
  2. Create a workers.properties file.

    The mod_jk modules in the Apache HTTPD server uses the workers.properties file to relevant map requests to the TDS using Tomcat’s AJP connector.

    Use your favorite text editor to create a workers.properties file in the Apache configuration directory that you specified in the previous step using the JkWorkersFile directive:

     # cd /usr/local/apache/conf
     # vi http.conf
    

    Add the following configurations to the workers.properties module to define a worker that will handle communication between the Apache HTTPD server and Tomcat.

     # workers.properties
     # To allow tomcat and apache to talk to each other.
     # needed by mod_jk
        
     # Define workers
     worker.list=worker1
        
     # Define workers using ajp13 protocol to forward requests to the Tomcat processes.
     worker.worker1.type=ajp13
        
     # TDS app
     # worker1 will talk to Tomcat listening on localhost at port 8009
     worker.worker1.host=localhost
     worker.worker1.port=8009
    
  3. Configure your Apache host to send the appropriate requests to TDS via mod_jk and Tomcat AJP.

    You will use the JkMount directives that come with the mod_jk to specify/match which URL requests should be proxied to the TDS in the Tomcat Servlet Container.

    The following shows an example of configuring an Apache VirtualHost with the JkMount directives.
    Note that these directives reference the worker configured in the workers.properties file in the previous step.

    <VirtualHost IP_ADDRESS:PORT>
        ServerName thredds.unidata.ucar.edu 
        ...
           
        # Proxy requests to the TDS
        JkMount /thredds* worker1
        JkMount /thredds worker1
        # Proxy requests to the Manager App
        JkMount /manager* worker1
        JkMount /manager worker1
           
        ...
    </VirtualHost>
    

Configure Tomcat and the TDS for the proxy

  1. Modify the Tomcat AJP Connector

    In the ${tomcat_home}/conf/server.xml file, locate the AJP Connector (uncommented and enabled by default) and add the following additional configuration to it:

    <!-- AJP 1.3 Connector on port 8009 -->
        <Connector port="8009" 
                   enableLookups="false"
                   useBodyEncodingForURI="true"
                   connectionTimeout="20000"
                   protocol="AJP/1.3" />
    
  2. Disable any active Java HTTP/1.1 Connector and the SSL HTTP/1.1 Connector Tomcat connectors.

    This will prevent direct communication to Tomcat via ports 8080 and 8443 ensuring the AJP proxy via Apache is the only HTTP method by which to access Tomcat and the TDS.

    Locate the Java HTTP/1.1 Connector listening on port 8080 and the active SSL HTTP/1.1 Connector listening on port 8443 and comment them out:

      <!--
        <Connector port="8080" 
                   protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
      -->
      ...
      <!--
        <Connector port="8443" 
                   protocol="org.apache.coyote.http11.Http11NioProtocol" 
                   maxThreads="150" 
                   SSLEnabled="true">
           <SSLHostConfig>
               <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" 
                            type="RSA" />
           </SSLHostConfig>
        </Connector>
       -->
    
  3. Configure the TDS to relinquish control of TLS/SSL to Apache

    The TDS deployment descriptor (${tomcat_home}/webapps/thredds/WEB-INF/web.xml) is configured to only allow access parts of the TDS application via TLS/SSL.
    Because we’ve disabled Tomcat’s handling of the TLS/SSL, we need to update these configurations.

    Use your favorite editor to open the TDS ${tomcat_home}/webapps/thredds/WEB-INF/web.xml file.
    Around line 106 you’ll start seeing configurations that look like the following:

    <!-- tdsConfig with HTTPS needed for /admin access  -->
      <security-constraint>
         <web-resource-collection>
           <web-resource-name>sensitive read access</web-resource-name>
           <url-pattern>/admin/*</url-pattern>
         </web-resource-collection>
         <auth-constraint>
           <role-name>tdsConfig</role-name>
         </auth-constraint>
         <user-data-constraint>
           <transport-guarantee>CONFIDENTIAL</transport-guarantee>
         </user-data-constraint>
       </security-constraint>
     ...
    

    These configs restrict access to the url in the <url-pattern> tags to the role in the <role-name> tags (which correspond to the roles defined in the ${tomcat_home}/conf/tomcat-users.xml file).
    The <transport-guarantee>CONFIDENTIAL</transport-guarantee> says access must take place via HTTPS.

    For any restricted part of the TDS you want to access that is listed here, you’ll need to comment out the configurations in the <user-data-constraint> tags:

    <!-- tdsConfig with HTTPS needed for /admin access  -->
      <security-constraint>
         <web-resource-collection>
           <web-resource-name>sensitive read access</web-resource-name>
           <url-pattern>/admin/*</url-pattern>
         </web-resource-collection>
         <auth-constraint>
           <role-name>tdsConfig</role-name>
         </auth-constraint>
         <!-- do not use tomcat https
           <user-data-constraint>
             <transport-guarantee>CONFIDENTIAL</transport-guarantee>
           </user-data-constraint>
         -->
       </security-constraint>
     ...
    

Changing The TDS Context Path (/thredds)

We do not recommend changing the TDS context path (the /thredds part of the URL path). However, if your network configuration requires that you use a different context path (e.g., /my/thredds) or you are proxying two TDS installations and need to differentiate them with different context paths (e.g., /thredds1 and /thredds2 ), you will need to make the following changes:

  1. Rename the thredds.war file to match the desired context path before you deploy it to Tomcat. Tomcat and other servlet engines direct incoming requests to a particular web application when the beginning of the request URL path matches the context path of that particular webapp. The easiest way to let Tomcat (or any other servlet engine) know what context path to use for a given webapp is to rename that webapp’s .war file before deploying it to Tomcat.

    For instance, if you want all URLs starting with /thredds2 to be handled by your TDS install, rename the thredds.war file to thredds2.war before you deploy it to Tomcat.

    If the desired context path is a multi-level context path (e.g., /my/thredds ), you must use a pound sign (“#”) in the .war filename to encode the slash (/). In this case, the thredds.war file would need to be renamed to my#thredds.war.

  2. Edit the TDS web.xml file and change the value of the ContextPath parameter to match the desired context path.

    The TDS uses the value of the ContextPath context parameter (as defined in the TDS web.xml file) when generating TDS URLs in certain situations. To make sure all generated URLs are consistent, you must change the value of the ContextPath parameter to match the desired context path.

    (Changing the value of ContextPath will no longer be necessary in a future release once we require Tomcat 6.0 (Servlet 2.5).

    The TDS web.xml file is located in ${tomcat_home}/webapps/<contextPath>/WEB-INF/web.xml, where <contextPath> is the value of the desired context path. The ContextPath context parameter is defined in the web.xml file (starting at line 12):

    <context-param>
      <param-name>ContextPath</param-name>
      <param-value>thredds</param-value>
    </context-param>
    

    For the /thredds2 example, it should be changed to:

    <context-param>
      <param-name>ContextPath</param-name>
      <param-value>thredds2</param-value>
    </context-param>
    

    And for the /my/thredds example, it should be changed to:

    <context-param>
      <param-name>ContextPath</param-name>
      <param-value>my/thredds</param-value>
    </context-param>
    
  3. Edit your TDS configuration catalogs and change the service base URLs to start with the desired context path.

    So that users will receive the correct data access URLs for datasets served by your TDS, the base URLs given by the service elements in your TDS configuration catalogs must match the desired context path.

    An OPeNDAP service element on a TDS with the context path of /thredds2 would need to look similar to this:

    <service name="odap" serviceType="OPeNDAP" base="/thredds2/dodsC/"/>
    

    And, similarly, an OPeNDAP service element on a TDS with the context path of /my/thredds would need to look similar to this:

    <service name="odap" serviceType="OPeNDAP" base="/my/thredds/dodsC/"/>
    

Troubleshooting

  • Check the catalog URL in the title of the HTML view of catalogs matches the requested URL.
  • Check the Data Access URL in the OPeNDAP Data Access Form matches the requested URL (minus the .html suffix).
  • If you have TDS Remote Management configured, go to the TDS debug page (e.g., http://localhost:8080/thredds/admin/debug) and follow the “Show HTTP Request info” link.
  • Once there, check the values listed for server name and port and the context path all match the appropriate values from the request URL, e.g., for the URL http://localhost:8080/thredds/admin/debug?General/showRequest , the values should be:

     req.getServerName(): localhost
     req.getServerPort(): 8080
     req.getContextPath(): /thredds