Hosting multiple SSL vhosts on a single IP/Port/Certificate with Apache2
Posted by: drax in admin, linux, osxTags: apache, ssl, vhosts
But that’s impossible!!
HTTPS is just HTTP encapsulated inside an SSL tunnel. Apache’s virtual hosts are a clever “hack” whereby the Host header in the HTTP packet is verified. This alllows a single apache instance on a single IP/Port combination to serve a (not so) infinite number of differentes sites (aka vhosts).
Problem: The SSL tunnel is created before the first HTTP packet gets sent. Apache needs an SSL certificate but doesn’t have a Host header to match, hence cannot choose a virtual host.
Solution
This trick essentially does the matching of the Host header after the SSL connection has been established. How? Via some mod_rewrite magic!
Caveats
Although I said so, it’s not really that magical. There are a few things this trick does not solve.
- The SSL certificate used will be common to all SSL vhosts.
- Certain Apache directives may be common to all SSL vhosts (example: SuExecUserGroup). Basically anything you can’t override in a .htaccess file will be shared amongst vhosts.
The trick
The process is only 2 steps and involves modifying your Apache configuration. I assume you have a working SSL vhost configured.
- Create virtual hosts “map file”.
- Modify existing SSL vhost.
1. The virtual hosts map file
Create a new file in your Apache server root. Example:/etc/apache2/ssl.map
Write a list of virtual hosts and their respective DocumentRoot. Example:
foo.example.com /var/www/foo.example.com/ bar.example.com /var/www/bar.example.com/ # you can even put comments! # Alias to bar boar.example.com /var/www/bar.example.com/
2. Edit your SSL vhost
Open your Apache config, inside the <VirtualHost> section of your SSL vhost, include the following code or include this file: Mass SSL vhosts Apache config.
Important: Make sure to edit line 8 to include the correct path to your ssl.map file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ### Mass SSL Vhosts ### RewriteEngine on # define two maps: one for fixing the URL and one which defines # the available virtual hosts with their corresponding # DocumentRoot. RewriteMap lowercase int:tolower RewriteMap vhost txt:/etc/apache2/ssl.map # 1. make sure we don't map for common locations RewriteCond %{REQUEST_URI} !^/cgi-bin/.* RewriteCond %{REQUEST_URI} !^/icons/.* # 2. make sure we have a Host header RewriteCond %{HTTP_HOST} !^$ # 3. lowercase the hostname RewriteCond ${lowercase:%{HTTP_HOST}|NONE} ^(.+)$ # # 4. lookup this hostname in vhost.map and # remember it only when it is a path # (and not "NONE" from above) RewriteCond ${vhost:%1} ^(/.*)$ # 5. finally we can map the URL to its docroot location # and remember the virtual host for logging puposes RewriteRule ^/(.*)$ %1/$1 [E=VHOST:${lowercase:%{HTTP_HOST}}] |
Restart Apache and you’re done. You should be able to browse (in https) the vhosts you added to your ssl.map file.
Grandma says: You don’t need to reload Apache when you edit your map file. Just create the document root folder on the filesystem, add a new entry to your map and you’re good to go.

January 24th, 2008 at 6:25 pm
useful trick !
crystal explanations, simple howto… perfect
THANX !!
February 6th, 2008 at 6:00 pm
Sweet; thanks for the tip!
Is there any way this can work when each vhost also has its own separate virtualhosts.conf file? Or does this work only when they all are configured the same way within the main configuration file (and the server map)?
February 6th, 2008 at 11:12 pm
[...] Edit: Another way of achieving more or less the same is described here [...]
February 11th, 2008 at 5:27 pm
John DeStefano:
As I said, with this technique, any directive in the main configuration file for the SSL vhost, is shared amonst all the SSL vhosts.
However, you can have per-vhost directives if you move them from the configuration file (foo.conf) to a htaccess file in the corresponding DocumentRoot.
Most, but not all directives can be overidden via a htaccess file.
Hope this helped.
May 25th, 2008 at 4:19 am
very cool. thanks.
September 10th, 2008 at 1:32 am
[...] Hosting multiple SSL vhosts on a single IP/Port/Certificate with Apache2 [...]
September 12th, 2008 at 9:11 pm
Great trick, thanks!
Is it possible to also use this for virtual hosts using ProxyPass?
My config for a virtual host which I want to secure with ssl:
ServerName tomcat.mydomain.com
ProxyPreserveHost on
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://tomcat.mydomain.com:8080/
September 17th, 2008 at 6:32 pm
Tidy solution. I have one question: if the document root specifiers are located on a box other than the Apache host, does this have an impact on the workability of this solution ?
October 20th, 2008 at 7:46 pm
@Stephan:
As I stated in the Caveats: “anything you can’t override in a .htaccess file will be shared amongst vhosts.”
Apparently, ProxyPass will not work in the context of a .htaccess file. Look at the “Context:” of a directive to check where it can be used. See: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypass
@Steve Tee:
I don’t understand your question. If you are speaking about filesystems mounted from remote hosts, then no, it has no impact.
October 22nd, 2008 at 12:52 am
Quick question: Will this solution address the cert mismatch errors that the browser will pop up since all of your subdomains are now using just one cert?
October 22nd, 2008 at 10:54 am
@av
This depends on the subdomains you use, and the cert you use. If you have a look at my SSL cert (https://drax.sweon.net for instance) the “Common Name” is *.sweon.net
This allows me to use the same SSL cert on all my sweon.net domains.
So to answer your question, if your domains are different (ie: not subdomains of the same domain) then yes, you will get cert mismatch errors. If you use only one domain, and subdomains, you simply need a wildcard in the CN field of your cert.
November 6th, 2008 at 5:07 am
Impressa:) or as a Portuguese, vpechatlilso!
November 15th, 2008 at 3:09 am
I think I just came up with a clever solution. However web browsers will have to support srv records
the problem with virtual hosts is that you can have only one ssl certificate per port (443)
because ssl requires it encrypted before it sends any other information.
A solution is to run a different key on different ports thus it could distinguish via port what key to encrypt with
https://onedomain.com:443
https://twodomain.com:444
by default a web browser goes to port 443 for https
Now if a web browser followed the rules of svr records you could tell the web browser to go to a different port using srv records
_https._tcp.onedomain.com SRV 443
_https._tcp.twodomain.com SRV 444
then again if the web browser follows SRV records it should automatically go to the right port for ssl and you can have an ssl connection to a virtual host each host with its own certificate.
December 2nd, 2008 at 11:04 am
Hi, great trick. Whay about using it in an Apache+Tomcat environment? How can I map connections over mod_jk connector?
December 5th, 2008 at 9:24 am
Look here for more stuff like this, original rasta:
http://httpd.apache.org/docs/2.2/rewrite/rewrite_guide_advanced.html#mass-virtual-hosting