4. Serving QueueMetrics over Apache/SSL

Thanks to Matthew J. Roth.

4.1. Prerequisites

  • A working QueueMetrics instance, served by an Apache 2 front-end
  • Wildcard SSL certificates created by a recognized authority (e.g. GoDaddy.com)

The examples below are based on Apache 2 running on CentOS 5.3. Details may vary.

It is important to note that configuring Tomcat to take advantage of secure sockets is usually only necessary when running it as a stand-alone web server. When running Tomcat primarily as a Servlet/JSP container behind another web server, such as Apache or Microsoft IIS, it is usually necessary to configure the primary web server to handle the SSL connections from users. Typically, this server will negotiate all SSL-related functionality, then pass on any requests destined for the Tomcat container only after decrypting those requests. Likewise, Tomcat will return cleartext responses, that will be encrypted before being returned to the user’s browser. In this environment, Tomcat knows that communications between the primary web server and the client are taking place over a secure connection (because your application needs to be able to ask about this), but it does not participate in the encryption or decryption itself.

4.2. Configure the Name-Based SSL Virtual Hosts

"Note" Apache will allow you to configure name-based SSL virtual hosts, but it will always use the configuration from the first-listed virtual host (on the selected IP address and port) to setup the encryption layer. In certain specific circumstances, it is acceptable to use a single SSL configuration for several virtual hosts. In particular, this will work if the SSL certificate applies to all of the virtual hosts. For example, this will work if:

  1. All the virtual hosts are within the same domain, e.g. one.example.com and two.example.com.
  2. You have a wildcard SSL certificate for that domain (one where the Common Name begins with an asterisk, e.g. *.example.com).

Remember that the SSL directives from all virtual hosts except the first-listed one will be ignored when setting up the initial SSL connection.

4.3. Install the Apache HTTP Server and its SSL/TLS Module

  # yum install httpd
    * Installed: httpd.x86_64 0:2.2.3-31.el5.centos
  # yum install mod_ssl
    * Installed: mod_ssl.x86_64 1:2.2.3-31.el5.centos
    * Dependency Installed: distcache.x86_64 0:1.4.5-14.1

4.4. Configure the global Apache Settings

  # mkdir /etc/httpd/vhosts.d
  # cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.orig
  # vi /etc/httpd/conf/httpd.conf
    * Add the following lines to the end of 'Section 3: Virtual Hosts':
      # Use name-based virtual hosting.
      NameVirtualHost *:80

      # Use name-based SSL virtual hosting.
      NameVirtualHost *:443

      # Load virtual hosts from the vhosts directory "/etc/httpd/vhosts.d".
      Include vhosts.d/*.conf

4.5. Configure the global SSL/TLS Settings

  # cp /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.orig
  # vi /etc/httpd/conf.d/ssl.conf
    * Use the '<IfDefine>' directive to disable the default SSL virtual host as follows:
      # Disable this default SSL virtual host
      <IfDefine 0>
      ## SSL Virtual Host Context

      <VirtualHost _default_:443>

Change the following lines from:

SSLRandomSeed startup file:/dev/urandom  256
SSLSessionCacheTimeout  300


SSLRandomSeed startup file:/dev/urandom 1024
SSLSessionCacheTimeout  600

4.6. Create DNS records

  • https-test1.example.com
  • https-test2.example.com

4.7. Create the Application Directories

  # mkdir /var/www/https-test1.example.com
  # mkdir /var/www/https-test1.example.com/{conf,html,logs,webapps}
  # mkdir /var/www/https-test1.example.com/conf/ssl.{crl,crt,csr,key}
  # mkdir /var/www/https-test2.example.com
  # mkdir /var/www/https-test2.example.com/{conf,html,logs,webapps}
  # mkdir /var/www/https-test2.example.com/conf/ssl.{crl,crt,csr,key}

4.8. Install the CRT, CSR, and KEY files

  # install -m 400 -o root -g apache /tmp/wildcard.example.com.key \
  # install -m 400 -o root -g apache /tmp/wildcard.example.com.key.unsecure \
  # install -m 440 -o root -g apache /tmp/wildcard.example.com.crt \
  # install -m 440 -o root -g apache /tmp/gd_bundle.crt \
  # install -m 440 -o root -g apache /tmp/wildcard.example.com.csr \
  # install -m 400 -o root -g apache /tmp/wildcard.example.com.key \
  # install -m 400 -o root -g apache /tmp/wildcard.example.com.key.unsecure \
  # install -m 440 -o root -g apache /tmp/wildcard.example.com.crt \
  # install -m 440 -o root -g apache /tmp/gd_bundle.crt \
  # install -m 440 -o root -g apache /tmp/wildcard.example.com.csr \
  # rm -f /tmp/wildcard.example.com.* gd_bundle.crt

4.9. Configure the Virtual Hosts

  # vi /etc/httpd/vhosts.d/000-https-test1.example.com.conf

    --- START 000-https-test1.example.com.conf CONTENTS -----------------------------
    # Define the https-test1.example.com name-based SSL virtual host

    # These are the default virtual hosts for port 80 and port 443

    <VirtualHost *:80>
        # This virual host exists solely to redirect all non-SSL traffic to the SSL
        # virtual host.  This is done in an SEO friendly manner by using the
        # 'RedirectPermanent' directive.  If the redirect is somehow circumvented,
        # the 'DocumentRoot' directive is set to serve content from a non-secure
        # directory.

        ServerAdmin admin@example.com
        ServerName https-test1.example.com
        ServerAlias https-test1
        DocumentRoot /var/www/html
        ErrorLog /var/www/https-test1.example.com/logs/error_log
        CustomLog /var/www/https-test1.example.com/logs/access_log common

        RedirectPermanent / https://https-test1.example.com/

    <VirtualHost *:443>
        # This is the SSL virtual host.  It is configured so that strong
        # cryptography (128 bit encryption or greater) is required to access any web
        # content.

        ServerAdmin admin@example.com
        ServerName https-test1.example.com
        ServerAlias https-test1
        DocumentRoot /var/www/https-test1.example.com/html
        ErrorLog /var/www/https-test1.example.com/logs/ssl_error_log
        CustomLog /var/www/https-test1.example.com/logs/ssl_access_log common

        # Enable SSL for this virtual host
        SSLEngine on

        # Deny all requests which are not using SSL...
        <Directory "/var/www/https-test1.example.com/html">

        # ...even under a 'Satisfy Any' situation
        SSLOptions +StrictRequire

        # List the SSL protocol flavors with which clients can connect
        SSLProtocol -all +TLSv1 +SSLv3

        # List the cipher suites that clients are permitted to negotiate

        # Point to the PEM-encoded certificate, private key, and CA certificate
        # chain files for this virtual host
        SSLCertificateFile /var/www/https-test1.example.com/conf/ssl.crt/wildcard.example.com.crt
        SSLCertificateKeyFile /var/www/https-test1.example.com/conf/ssl.key/wildcard.example.com.key.unsecure
        SSLCertificateChainFile /var/www/https-test1.example.com/conf/ssl.crt/gd_bundle.crt

        # Handle problems with broken clients, such as older versions of Internet
        # Explorer
        SetEnvIf User-Agent ".*MSIE.*" \
                 nokeepalive ssl-unclean-shutdown \
                 downgrade-1.0 force-response-1.0

        # Log information about the SSL parameters that are negotiated for requests
        CustomLog /var/www/https-test1.example.com/logs/ssl_request_log \
                  "%t %h %{HTTPS}x %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{SSL_CIPHER_USEKEYSIZE}x %{SSL_CLIENT_VERIFY}x \"%r\" %b"
    --- END 000-https-test1.example.com.conf CONTENTS -------------------------------

Do the same for the second virtual host, setting the names as appropriate.

  # vi /etc/httpd/vhosts.d/001-https-test2.example.com.conf

4.10. Verify the Configuration

  # httpd -S
  VirtualHost configuration:
  wildcard NameVirtualHosts and _default_ servers:
  *:443                  is a NameVirtualHost
           default server https-test1.example.com (/etc/httpd/vhosts.d/000-https-test1.example.com.conf:22)
           port 443 namevhost https-test1.example.com (/etc/httpd/vhosts.d/000-https-test1.example.com.conf:22)
           port 443 namevhost https-test2.example.com (/etc/httpd/vhosts.d/001-https-test2.example.com.conf:20)
  *:80                   is a NameVirtualHost
           default server https-test1.example.com (/etc/httpd/vhosts.d/000-https-test1.example.com.conf:5)
           port 80 namevhost https-test1.example.com (/etc/httpd/vhosts.d/000-https-test1.example.com.conf:5)
           port 80 namevhost https-test2.example.com (/etc/httpd/vhosts.d/001-https-test2.example.com.conf:3)
  Syntax OK

4.11. Setup the service for automated startup

  # chkconfig httpd on ; chkconfig --list httpd
  httpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off
  # service httpd start
  Starting httpd:                                            [  OK  ]

4.12. Troubleshooting

  # openssl s_client -connect localhost:443
  ... SSL Connection Establishment ...
  GET / HTTP/1.0

  HTTP/1.1 200 OK
  ... HTTP Headers ...

  ... Web Page Contents ...

4.13. Summary of Log Files used by Apache

  • /var/log/httpd/access_log
  • /var/log/httpd/error_log
  • /var/www/https-test1.example.com/logs/access_log
  • /var/www/https-test1.example.com/logs/error_log
  • /var/www/https-test1.example.com/logs/ssl_access_log
  • /var/www/https-test1.example.com/logs/ssl_error_log
  • /var/www/https-test1.example.com/logs/ssl_request_log
  • /var/www/https-test2.example.com/logs/access_log
  • /var/www/https-test2.example.com/logs/error_log
  • /var/www/https-test2.example.com/logs/ssl_access_log
  • /var/www/https-test2.example.com/logs/ssl_error_log
  • /var/www/https-test2.example.com/logs/ssl_request_log

4.14. Notes

Warnings related to name-based SSL virtual hosts, such as the following, can be ignored:

[warn] Init: SSL server IP/port conflict: https-test1.example.com:443 (/etc/httpd/vhosts.d/000-https-test1.example.com.conf:22) vs. https-test2.example.com:443 (/etc/httpd/vhosts.d/001-https-test2.example.com.conf:20)
[warn] Init: You should not use name-based virtual hosts in conjunction with SSL!!
[warn] RSA server certificate CommonName (CN) `*.example.com' does NOT match server name!?