SSL + Apache2.2 + VirtualHost + Debian with automatically HTTPS forwarding

i am now working on an internal project, about a webmail system. after most work is done, i hope to setup a HTTP to HTTPS forwarding for the webmail interface. let's say that if user access http://webmail.example.com, they will be automatically forward to https://webmail.example.com, in order to protect all of their private information. the idea is quite simple and strict forward.

else this will be too funny: we can use SSMTP + TLS, POP3S and IMAPS to access email, but the connection for web user management interface (for changing password and user profile) and webmail are keep in plan text... transferring password in plan text let all other protection just become a joke...

first let's see how to implement SSL with Apache2.2 and Debian:

  1. generate a certification:
    apache2-ssl-certificate

    for debian etch, apache2-ssl-certificate is no longer available, use make-ssl-cert instead:

    make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/apache2/ssl/apache.pem
  2. edit /etc/apache2/ports.conf:
    Listen 80
    Listen 443
  3. copy /etc/apache2/sites-available/default to /etc/apache2/sites-available/default-ssl, and change /etc/apache2/sites-available/default:
    NameVirtualHost *:80
    <VirtualHost *:80>
    ...
    </VirtualHost>

    and also /etc/apache2/sites-available/default-ssl:

    NameVirtualHost *:443
    <VirtualHost *:443>
    ...
            SSLEngine on
            SSLCertificateFile /etc/apache2/ssl/apache.pem
    ...
    </VirtualHost>
  4. symbolic link the ssl file:
    ln -s /etc/apache2/sites-available/default-ssl /etc/apache2/sites-enabled/000-default-ssl
  5. don't forget to symbolic link the ssl module:
    ln -s /etc/apache2/mods-available/ssl.* /etc/apache2/mods-enabled/
  6. restart apache and test the connection (e.g. https://localhost/):
    /etc/init.d/apache2 restart

if all seems ok, we can move to the next section: the automatically forwarding of HTTP to HTTPS in virtual hosting. let's see how to do so if we hope to implement it for virtual host (e.g. http://webmail.example.com):

  1. copy the default ssl setting as the base of new configure:
    cp /etc/apache2/sites-available/default-ssl \
    /etc/apache2/sites-available/webmail.example.com
  2. edit the file /etc/apache2/sites-available/webmail.example.com and add the following part. don't forget to configure a correct ServerName for <VirtualHost *:443>:
    <VirtualHost *:80>
            ServerName webmail.example.com
            ServerAdmin webmaster@example.com

            RewriteEngine   on
            RewriteCond     %{SERVER_PORT} ^80$
            RewriteRule     ^(.*)$ https://%{SERVER_NAME}$1 [L,R]
            RewriteLog      "/var/log/apache2/rewrite.log"
            RewriteLogLevel 2

    </VirtualHost>

    you may also hope to generate another SSL certification for the new virtual host. this is up to you, but keep in mind about changing the necessary setting under section <VirtualHost *:443>.

    Apache allows one server to service several websites through its Virtual Hosts feature. When multiple virtual hosts exist, Apache must determine which host should serve each request. It does this in one of two ways: based on the host IP address or the host name. When using the host IP address, the server must have multiple IP addresses, one for each virtual host. When using name-based virtual hosts, all sites use the same IP address and the browser sends the name of the site with each request and Apache uses the name to determine which host should serve the request.

    With name-based virtual hosts, the host name is contained in the data stream, which is encrypted by SSL. To access the name, Apache must first decrypt the stream, which requires a certificate. Thus, it must choose a certificate before it knows the virtual host. For this reason, when using name-based virtual hosting there can only be one certificate. Apache uses the certificate mentioned first in its configuration file. If you specify multiple certificates, one for each virtual host, Apache will use the one for the first host without generating any errors or warnings.

    If instead you use IP address-based virtual hosts, Apache can determine which certificate to use without first decrypting the stream based on the IP address used by the address. In this way, each virtual host can have its own certificate.

    » http://www.nurdletech.com/https.html

  3. again, create the symbolic link of the new virtual host file (i call it 002-webmail.pacmobile.com so it will be included after default and default-ssl):
    ln -s /etc/apache2/sites-available/webmail.example.com \
    /etc/apache2/sites-enabled/002-webmail.example.com
  4. for sure, as we will use mod_rewrite, we need to enable it:
    ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/
  5. restart apache and test the connection with HTTP (e.g. http://webmail.example.com/):
    /etc/init.d/apache2 restart

you will found that the connection is forwarded to HTTPS version (e.g. https://webmail.example.com/). great! job done!

i think you should know that a correct DNS setup is required, right? else you can't access the virtual host...


Anonymous's picture
Anonymous (not verified)

There are helper scripts to enable/disable sites and modules that is a bit more generic an easier to use. Would probably be a good idea to suggest them in your guide.
See the a2enmod, a2dismod, a2ensite, a2dissite commands...

//fatal

hswong3i's picture
hswong3i

thank you very much. i know these command, but i feel that they are not flexible enough, and so handle this manually :)

----------------------------------------
Edison Wong

Anonymous's picture
Anonymous (not verified)

ln -s /etc/apache2/sites-available/ssl /etc/apache2/sites-enabled/000-default-ssl

should really be

ln -s /etc/apache2/sites-available/default-ssl /etc/apache2/sites-enabled/000-default-ssl

because in step 3,
copy /etc/apache2/sites-available/default to /etc/apache2/sites-available/default-ssl

Anonymous's picture
Anonymous (not verified)

Excellent guide, but I did run into one issue... despite the fact that both my NameVirtualHost and VirtualHost entries contained wildcards, I received the following error message:

[Mon Aug 27 10:58:02 2007] [error] VirtualHost *:443 -- mixing * ports and non-* ports with a NameVirtualHost address is not supported, proceeding with undefined results
[Mon Aug 27 10:58:02 2007] [error] VirtualHost *:80 -- mixing * ports and non-* ports with a NameVirtualHost address is not supported, proceeding with undefined results
[Mon Aug 27 10:58:02 2007] [warn] NameVirtualHost *:443 has no VirtualHosts
[Mon Aug 27 10:58:02 2007] [warn] NameVirtualHost *:80 has no VirtualHosts

From default config:
NameVirtualHost *:80
VirtualHost *:80

And default ssl:
NameVirtualHost *:443
VirtualHost *:443

According to http://raibledesigns.com/wiki/Wiki.jsp?page=ApacheSSL:
"When using SSL with multiple Virtual Hosts, you must use an ip-based configuration. This is because SSL requires you to configure a specific port (443), whereas name-based specifies all ports (*)."

Once I switched to IP based configuration everything worked fine (ie NameVirtualHost X.X.X.X:80 etc).

Note: This was running out of the box Debian etch w/ apache2 (2.2.3-4+etch1)

Anonymous's picture
Anonymous (not verified)

According to
http://httpd.apache.org/docs/2.0/ssl/ssl_faq.html#vhosts2
it not possible to use Name-Based Virtual Hosting to identify different SSL virtual hosts.

When you have several hosts pointing to the same ip address, and rewrite is set to automatically change it to https connection, they will all use the default 443 port, which in this case would use the default-ssl configuration.

If you have multiple ip addresses to use, you can use separate IP addresses for different SSL hosts. Otherwise, using different port numbers for different SSL hosts works too.

Thus, one might have

# SSL enabled virtual host 1
...

# SSL enabled virtual host 2
...

Anonymous's picture
Anonymous (not verified)

I've seen lots of people doing this rewrite trick and I've always wondered why instead of:

        RewriteEngine   on
        RewriteCond     %{SERVER_PORT} ^80$
        RewriteRule     ^(.*)$ https://%{SERVER_NAME}$1 [L,R]
        RewriteLog      "/var/log/apache2/rewrite.log"
        RewriteLogLevel 2

Why not do:

Redirect / https://webmail.example.com
hswong3i's picture
hswong3i

Actually... you don't need to ask why: just simply apply both case and test it, so you will have a better idea about the different between each handling.

For the rewrite rules handling, it will forward ALL 80 port access of this virtual host into SSL version.

For your cases, will redirect user ONLY IF they are accessing document root: so they will able to access NONE SSL version by simply type in the URL DIRECTLY (paths other than document root).

So yours handling will not restrict ALL 80 port traffic to SSL version, and that's not what we are hoping for, within this cases ;)

----------------------------------------
Edison Wong

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <h1> <h2> <h3> <h4> <h5> <h6> <em> <strong> <code> <del> <blockquote> <q> <sub> <p> <br> <ul> <ol> <li> <dl> <dt> <dd> <a> <b> <u> <i> <sup> <acronym> <pre> <img>
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Web page addresses and e-mail addresses turn into links automatically.
  • You may quote other posts using [quote] tags.
  • Lines and paragraphs break automatically.
  • You may insert [hidden]text[/hidden] into your text.

More information about formatting options

Captcha
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Copy the characters (respecting upper/lower case) from the image.

Recent comments

Who's online

There are currently 0 users and 2 guests online.