Solved

Configuring Apache for forced SSL with Virtual Hosts on a multi-homed box

Posted on 2010-08-12
9
1,387 Views
Last Modified: 2013-12-02
Okay, I am incredibly frustrated.  While I can get individual aspects of this working beautifully, I can't seem to put it all together.   I have a box -- dmz.app.com -- that will host an instance of Apache that is intended to sit in front of three distinct sites -- call them a.app.com, b.app.com and c.app.com.  dmz.app.com is multi-homed, with three public IP addresses (outside.100, outside.101 and outside.102), each of which maps to a unique internal IP address (inside.10, inside.11, inside.12).  The distinct sites are configured through DNS so that a.app.com = outside.100, b.app.com = outside.101 and c.app.com = outside.102.  For each site, there is a dedicated Tomcat server -- call them a-tomcat, b-tomcat and c-tomcat.  The idea is simple; for any request on any of the three *.app.com domains, force the request to use SSL (HTTPS over port 443) and route it to the appropriate *-tomcat server.

Forcing SSL seemed to work with the following rules:

RewriteCond %{SERVER_PORT} !^443$
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R,L]

Open in new window


Mapping the requests to the appropriate Tomcat seems to sort of work with the following approach:

# This was needed because Apache couldn't resolve the host uniquely due to the triple-homing
ServerName dmz.app.com

NameVirtualHost inside.11
NameVirtualHost inside.12
NameVirtualHost inside.13

<VirtualHost inside.11>
RewriteEngine On
RewriteOptions Inherit

DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/a"
ServerName a.app.com
ErrorLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/error.log"
TransferLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/access.log"
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/my.crt"
SSLCertificateKeyFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/my.key"
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>
BrowserMatch ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/ssl_request.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
<Location "/*/WEB-INF/*">
     deny from all
</Location>

JkMount /* a-worker

JkMount /myapp/ a-worker
JkMount /myapp/* a-worker
JkMount /myapp* a-worker
</VirtualHost>                                  

<VirtualHost inside.12>
RewriteEngine On
RewriteOptions Inherit

DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/b"
ServerName b.app.com
ErrorLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/error.log"
TransferLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/access.log"
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/my.crt"
SSLCertificateKeyFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/my.key"
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>
BrowserMatch ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/ssl_request.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
<Location "/*/WEB-INF/*">
     deny from all
</Location>

JkMount /* b-worker

JkMount /myapp/ b-worker
JkMount /myapp/* b-worker
JkMount /myapp* b-worker
</VirtualHost>                                  

<VirtualHost inside.13>
RewriteEngine On
RewriteOptions Inherit

DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/c"
ServerName c.app.com
ErrorLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/error.log"
TransferLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/access.log"
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/my.crt"
SSLCertificateKeyFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/my.key"
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>
BrowserMatch ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog "C:/Program Files/Apache Software Foundation/Apache2.2/logs/ssl_request.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
<Location "/*/WEB-INF/*">
     deny from all
</Location>

JkMount /* c-worker

JkMount /myapp/ c-worker
JkMount /myapp/* c-worker
JkMount /myapp* c-worker
</VirtualHost>                                  

Open in new window


The worker.properties file looks like:

workers.java_home="/Program Files/Java/jdk1.6.0_21"

# The advanced router LB worker
worker.list=a-worker, b-worker, c-worker

# Define workers using ajp13
worker.a-worker.port=8009
worker.a-worker.host=a-tomcat
worker.a-worker.type=ajp13

worker.b-worker.port=8009
worker.b-worker.host=b-tomcat
worker.b-worker.type=ajp13

worker.c-worker.port=8009
worker.c-worker.host=c-tomcat
worker.c-worker.type=ajp13

Open in new window


Putting all of these pieces together yields really inconsistent, funky results.  When I point my browser to https://b.app.com/myapp/ or https://b.app.com/myapp, life is wonderful and happy.  When I point my browser to http://b.app.com/myapp/ or http://b.app.com/myapp, I get a 400 Bad Request (Your browser sent a request that this server could not understand.  Reason: You're speaking plain HTTP to an SSL-enabled server port.  Instead use the HTTPS scheme to access this URL, please.).  But if I point my browser to http://b.app.com or http://b.app.com/ or https://b.app.com or https://b.app.com/, I wind up at https://a.app.com/myapp/!

This cannot possibly be as hard as I seem to have made it.  Can somebody please point me in the direction toward sanity?  Thank you!
0
Comment
Question by:arktech
  • 5
  • 2
  • 2
9 Comments
 

Author Comment

by:arktech
ID: 33433795
To clarify what I mean by "point me in the direction toward sanity", answers to the following will be awarded points:

* The outside.10x -> inside.1x -> y.app.com structure was somewhat unintentional.  Originally, I thought unique external IP addresses were required to support SSL; our hosting provider thought we needed unique internal IP addresses.  Are we overcomplicating this?  Is there a better way?  Would we sacrifice any scalability/flexibility by using a different approach?

* What mod_rewrite techniques have you successfully used to force SSL with multiple virtual hosts?

Thanks!
0
 
LVL 50

Expert Comment

by:Steve Bink
ID: 33435505
0
 

Author Comment

by:arktech
ID: 33435983
I did play with SSLRequireSSL, but it's not really the behavior I was after.  In our current configuration (in which Apache is only sitting in front of one of the three environments), attempts to connect via http: are automatically redirected to the https: URL.  We managed that by including a simple redirect index.html in .htdocs.  Unfortunately, that's where the multi-domain/multi-homed complications are causing problems.  I set up a separate subdirectory for each domain (.htdocs/a, .htdocs/b, .htdocs/c) with an index.html in each that redirects to the https: URL for http: connections.  Unfortunately, attempts to connect to b.app.com get redirected to https://a.app.com, no doubt due to some misconfiguration, but I can't seem to figure it out.
0
 
LVL 26

Accepted Solution

by:
arober11 earned 500 total points
ID: 33436912
Hi, for a start change the "SERVER_NAME", what you get from a "uname -n"  to "HTTP_HOST", the site name passed in the URL, in you Rewrite, and make the re-direct permanent e.g.

RewriteCond %{SERVER_PORT} !^443$
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

I take it the rules are in the body of the httpd.conf, as they don't appear your Virtualhost definitions.

Once tweaked let us know what's not working.
0
Free Gift Card with Acronis Backup Purchase!

Backup any data in any location: local and remote systems, physical and virtual servers, private and public clouds, Macs and PCs, tablets and mobile devices, & more! For limited time only, buy any Acronis backup products and get a FREE Amazon/Best Buy gift card worth up to $200!

 
LVL 50

Expert Comment

by:Steve Bink
ID: 33439240
The normal rule I use:

RewriteCond %{HTTPS} off
# or
# RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
0
 

Author Comment

by:arktech
ID: 33440719
arober11, you are a shining example of why I love Experts Exchange!  Everything is working perfectly now for all four flavors of https: URLs (https://b.app.com, https://b.app.com/, https://b.app.com/myapp and https://b.app.com/myapp/).  Using the http: form of all four yields the same result as before:

---------------------------------------------------
Bad Request

Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.

    Hint: https://b.app.com/
---------------------------------------------------

Now, given that this response includes a hyperlink to a valid URL, I can live with this.  That said, if you know of an easy fix for it, I'm all ears!
0
 

Author Comment

by:arktech
ID: 33441107
Found it; fixed it!  I changed my NameVirtualHost and VirtualHost directives to explicitly specify a.app.com:443 etc. instead of just a.app.com.  Now all eight permutations are working as intended!  Thank you again for the help!  It's amazing how such a little oversight -- HTTP_HOST vs. SERVER_NAME -- can cause so much hair-pulling.
0
 

Author Closing Comment

by:arktech
ID: 33441113
Fantastic!  Exactly the tip I needed.  Once I had this in place, the rest came together quickly.  Thank you, arober11, for spotting the subtle little mistake that was causing me so much frustration!
0
 
LVL 26

Expert Comment

by:arober11
ID: 33447610
Thanks
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

If you've heard about htaccess and it sounds like it does what you want, but you're not sure how it works... well, you're in the right place. Read on. Some Basics #1. It's a file and its filename is .htaccess (yes, with a dot in the front). #…
Microservice architecture adoption brings many advantages, but can add intricacy. Selecting the right orchestration tool is most important for business specific needs.
This video discusses moving either the default database or any database to a new volume.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now