It is possible with Apache to host multiple websites with a single static IP address. However, you can only have one SSL certificate per static IP. This post describes setting up Apache with multiple secure virtual hosts and a single self-signed wildcard certificate. To learn about creating the certificate, check out
Creating Self-Signed Certs on Apache 2.2.
Here's a table of our example hosts:
| Domain | Force SSL? | Trusted? | Valid Domain? |
| www.site-a.com | No | No | Yes |
| secure.site-a.com | Yes | No | Yes |
| test.site-a.com | No | No | Yes |
| www.site-b.com | No | No | No |
| secure.site-b.com | Yes | No | No |
In order for the certificate to be trusted, you need to obtain the certificate from a trusted
certificate authority. Since we are using self-signed certificates, they are not trusted and we will see some warning messages. The data will still be encrypted.
For this to work, we are going to use
name-based virtual hosts.
The name and location of Apache's configuration files vary based on which platform you use. This post assumes Ubuntu in which case the configuration files in the
/etc/apache2 directory.
For starters, we need to tell Apache which ports to listen on by editing the file
/etc/apache2/ports.conf.
Listen 80
<IfModule mod_ssl.c>
Listen 443
</IfModule>
Next we need to add our virtual hosts. They are kept in the
/etc/apache2/sites-available directory. For organization purposes, separate your sites into separate config files, then run
a2ensite for each site to generate a symbolic link in the
/etc/apache2/sites-enabled directory.
Here is the configuration for the sites:
NameVirtualHost 192.168.1.200:80
NameVirtualHost 192.168.1.200:443
# http://site-a.com
# https://site-a.com -- Throws warning because cert is for *.site-a.com... see bottom
# http://www.site-a.com
# https://www.site-a.com
<VirtualHost 192.168.1.200:80 192.168.1.200:443>
ServerName site-a.com
ServerAlias www.site-a.com
DocumentRoot /path/to/www.site-a
# Note: SSL settings only need to be defined once!
SSLEngine On
SSLCertificateFile /path/to/thecert.crt
SSLCertificateKeyFile /path/to/thecert.key
</VirtualHost>
# Not SSL, redirect to https://secure.site-a.com
<VirtualHost 192.168.1.200:80>
ServerName secure.site-a.com
Redirect / https://secure.site-a.com/
</VirtualHost>
# https://secure.site-a.com
<VirtualHost 192.168.1.200:443>
ServerName secure.site-a.com
DocumentRoot /path/to/secure.site-a
</VirtualHost>
# http://test.site-a.com
# https://test.site-a.com
<VirtualHost 192.168.1.200:80 192.168.1.200:443>
ServerName test.site-a.com
DocumentRoot /path/to/test.site-a
</VirtualHost>
# http://www.site-b.com
# https://www.site-b.com -- Throws warning because cert is for *.site-a.com
<VirtualHost 192.168.1.200:80 192.168.1.200:443>
ServerName www.site-b.com
DocumentRoot /path/to/secure.site-b
</VirtualHost>
# Not SSL, redirect to https://secure.site-b.com
<VirtualHost *:80>
ServerName secure.site-b.com
Redirect / https://secure.site-b.com/
</VirtualHost>
# https://secure.site-b.com -- Throws warning because cert is for *.site-a.com
<VirtualHost 192.168.1.200:443>
ServerName secure.site-b.com
DocumentRoot /path/to/secure.site-b
</VirtualHost>
Despite having a wildcard certificate for
*.site-a.com, you will get an invalid domain message when you don't supply the subdomain (i.e. http://site-a.com). The only way I know of to solve this is with 2 static IPs and 2 certs where one cert is for
site-a.com and the other is for
*.site-a.com.
I'm using 192.168.1.200 for the server's IP address behind the firewall. You could try using * instead of 192.168.1.200 in the
<VirtualHost> blocks, but I haven't tested this. Leave a comment if you happen to test this. :)
Assuming the stars have aligned, you should have several secured virtual hosts!
Comments
If you want browsers to be happy with the certificate when hitting the base domain (site-a.com), you might want to look at signing the certificate with a subjectAlternativeName set to the base domain as well.
My openssl.conf has "subjectAltName=${ENV::SAN}" in the [ usr_crt ] section, and I set the environment variable (eg "export SAN='DNS:'") before running the openssl commands to create the certificate.
The "export" command was truncated in the post above. Should have been:
export SAN='DNS:[base-domain-name]'
Eg,
export SAN='DNS:site-a.com'
Post new comment