How do I add a virtual host with self-signed SSL to my Apache2 web server, Mac OS X 10.5 (client) computer?

Instructions on how to host multiple self-signed SSL virtual hosts on a single certificate.

2-9-2010 by Tami Williams

Why

Here's why you might do this:

How

  1. Create a certificate for our own personal signing authority.
  2. Create a certificate request for a domain.
  3. Sign the certificate signing request, and generate a signed certificate.
  4. Make a copy of the signed certificate that doesn't need a password when apache starts.
  5. Turn on SSL.
  6. Add a new SSL virtual host.
  7. Create a virtual hosts "map file".
  8. Edit your SSL virtual host.

Steps

Open the Terminal application and create an "ssl" directory in /etc/apache2:
sudo mkdir /etc/apache2/ssl
cd /etc/apache2/ssl
  1. Generate your own CA. Make sure to remember the passphrase you're prompted for. This is what you use to sign certificates.
  2. sudo openssl genrsa -des3 -out ca.key 4096
    sudo openssl req -new -x509 -days 1825 -key ca.key -out ca.crt
    
  3. Generate a server key and request for signing (csr). When prompted for the Common Name (CN), enter the domain name you want the certificate for. For example xxx.lmc.xxx (if you want to use the URL http://xxx.lmc.xxx/). You can just hit return on your keyboard (to leave the entries blank) when prompted for Organizational Unit Name, Challenge Password, and Optional Company Name.
  4. sudo openssl genrsa -des3 -out lmc.key 4096
    sudo openssl req -new -key lmc.key -out lmc.csr
    
  5. Sign the certificate signing request with the self-created certificate authority that you made earlier:
  6. sudo openssl x509 -req -days 1825 -in lmc.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out lmc.crt
    
  7. Make a key which doesn't cause apache to prompt for a password.
  8. sudo openssl rsa -in lmc.key -out lmc.key.insecure
    sudo mv lmc.key lmc.key.secure
    sudo mv lmc.key.insecure lmc.key
    
    The /private/etc/apache2/ssl directory should look like this:
    ca.crt		lmc.crt		lmc.key
    ca.key		lmc.csr		lmc.key.secure
    
  9. Turn on SSL -
    Open /private/etc/apache2/httpd.conf and uncomment the line for SSL:
  10. # Secure (SSL/TLS) connections
    Include /private/etc/apache2/extra/httpd-ssl.conf
    
  11. Open /private/etc/apache2/extra/httpd-ssl.conf and comment out the entire <VirtualHost>...</VirtualHost> section. Then, open /private/etc/apache2/extra/httpd-vhosts.conf and add the new xxx.lmc.xxx SSL virtualhost to the bottom:
  12. #
    # SSL
    <VirtualHost 127.0.0.1:443>
      # General setup for the virtual host 127.0.0.1:443
        DocumentRoot "/Library/WebServer/Documents/lmc"
        
      #ServerName has to match the server you entered into the CSR
        ServerName xxx.lmc.xxx
        ServerAdmin tami@asktami.com
        ErrorLog /var/log/apache2/error_log
        TransferLog /var/log/apache2/access_log
    
    <Directory "/Library/WebServer/Documents/lmc">
      AllowOverride All
      Options
      Order allow,deny
      Allow from all
    </Directory>
    
    # SSL Configuration
    SSLEngine on
    SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
    SSLOptions +FakeBasicAuth +ExportCertData +StdEnvVars +StrictRequire
    
    #Self Signed certificates
        SSLCertificateFile /etc/apache2/ssl/lmc.crt
        SSLCertificateKeyFile /etc/apache2/ssl/lmc.key
        SSLCertificateChainFile /etc/apache2/ssl/ca.crt
    
    #DON'T DO ANY INTENSIVE SSL OPERATIONS UNLESS THE FILE IS html OR lasso
    <Files ~ "\.(html|lasso?)$">
      SSLOptions +StdEnvVars
    </Files>
    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
    </VirtualHost>
    
    To check for configuration errors and if none are found, restart the Web server, type (in Terminal):
    sudo apachectl configtest
    sudo apachectl graceful
    

    Check that your Web server (and Lasso, if you're using Lasso) are working correctly. Open a web browser and go to http://127.0.0.1/ and one of your virtual hosts, ex. http://xxx.test.xxx, and, if you're using Lasso, one of your Lasso web sites.

    At this point you have a single self-signed SSL virtual host. Whatever HTTPS URL you use, https://xxx.lmc.xxx/, https://xxx.test.xxx/, etc., will point to your /Library/Webserver/Documents/lmc directory.

    Continue on to create multiple self-signed SSL virtual hosts so that https://xxx.lmc.xxx/ will point to your /Library/Webserver/Documents/lmc directory and https://xxx.test.xxx/ will point to your /Library/Webserver/Documents/test directory.

  13. Use BBEdit to create a new file called "ssl.map" on your Desktop. Put in this file a list of your virtual hosts with their DocumentRoot:
  14. xxx.test.xxx	/Library/WebServer/Documents/test
    xxx.dev.xxx	/Library/WebServer/Documents/dev
    xxx.lmc.xxx	/Library/WebServer/Documents/lmc
    
    # You can even put comments!
    # Alias to test - you can do this IF you have a virtual host with the ServerName xxx.this.xxx
    # that points to /Library/WebServer/Documents/test
    xxx.this.xxx	/Library/WebServer/Documents/test
    

    Use Terminal to move this file to /private/etc/apache2/ssl.map:

    cd /Users//Desktop
    sudo mv ssl.map /private/etc/apache2/ssl.map
    
  15. Open /private/etc/apache2/extra/httpd-vhosts.conf and include the following code inside, at the bottom, of <VirtualHost 127.0.0.1:443>:
  16. ### 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}}]
    

    To check for configuration errors and if none are found, restart the Web server, type (in Terminal):

    sudo apachectl configtest
    sudo apachectl graceful
    

    Check that your Web server (and Lasso, if you're using Lasso) are working correctly. Open a web browser and go to http://127.0.0.1/ and one of your virtual hosts, ex. http://xxx.test.xxx, and, if you're using Lasso, one of your Lasso web sites.

    And check each of your virtual hosts (and Lasso sites) with HTTPS, ex: https://xxx.lmc.xxx/.

What to watch out for

Don't skip checking for configuration errors! If any errors are reported when you do sudo apachectl configtest your Web server probably won't run.

Because you are using a self-signed SSL certificate (created solely for the xxx.lmc.xxx virtual host) your web browser will display a message telling you:

"<yourURL> uses an invalid security certificate.

The certificate is not trusted because the issuer certificate is not trusted.
The certificate is only valid for xxx.lmc.xxx."

You will need to click on the button to "Add Exception".

A certificate authority tells your customers that this server information has been verified by a trusted source. The problem with using a self-signed certificate is that it will be flagged as potentially risky and error messages will pop up encouraging your customers to not trust the site.