How to configure HTTPS on Apache 2

Introduction

Setting up several VirtualHost’s on an Apache2 server is easy.

Setting up several VirtualHost’s on an Apache 2 server, some of them using SSL (HTTPS) is considerably less easy. The main problem is the documentation, not really easy to find, with examples of such configurations.

Here, we will intend to give all the steps to get there, remaining at a minimal level of complexity.

If you want more details, I suggest you have a look at this nice article by Artur Maj. This is where most of the inspiration comes from for the current article, together with real tests on a Debian Etch server. Thanks to his article, We will allow ourselves to skip the HTTPS, SSL and TLS definitions and prerequisites. We will consider that you have already installed SSL on your server installation, but haven’t enabled it with VirtualHost’s just yet.

Generating a key

To get things started, you will need a key. This key will be used by the VirtualHost you will define, only if you ask it to.
To generate the key, create an ssl directory in your /etc/apache2/ directory (on a Debian Etch, that is)
Then move inside that directory (cd ssl) and do the following:

mkdir crt
mkdir key
openssl req -new -x509 -days 365 -keyout key/vhost1.key -out crt/vhost1.crt -nodes -subj  ‘/O=VirtualHost Website Company name/OU=Virtual Host Website department/CN=www.virtualhostdomain.com’

This operation will create two files, crt/vhost1.crt and key/vhost1.key, that you will use in your VirtualHost definition to enable SSL encryption using that key.

Changing the VirtualHost config

Now move on to your Apache sites configuration. In most cases, you should have something like an /etc/apache2/sites-available/ and an /etc/apache2/sites-enabled directory. As sites-enabled should only contain links to sites-available, we are only interested in sites-available. So go there.

Now you should have one default file there, as well as one file that defines the configuration of the VirtualHost you would like to setup to use HTTPS.

Open the default config file. It should start with something like

NameVirtualHost *:80

or

NameVirtualHost *

Either way, change it to:

NameVirtualHost *:80
NameVirtualHost *:443

Now you have just told your webserver to accept both requests on port 443 and 80. *if* you restart your webserver at this point, you should get a warning message saying that no host is using the port 443. This is normal for me: I never really got around how to configure the whole thing correctly to avoid it throwing warnings at reload, but it is definitely not a big problem. Now let’s proceed to the config of the VirtualHost itself.

Open your VirtualHost config file. You should have something along the lines of:

<VirtualHost *>
ServerAdmin webmaster@yourdomain.com
DocumentRoot /var/www/vhost1
ServerName vhost1.yourdomain.com
DirectoryIndex index.php
ErrorLog /var/log/apache2/vhost1-error.log
CustomLog /var/log/apache2/vhost1-access.log combined
<Location />
Options Indexes FollowSymLinks
AllowOverride All
</Location>

</VirtualHost>

Together with the new config, this should look like that:

<VirtualHost *:80>
ServerAdmin webmaster@yourdomain.com
DocumentRoot /var/www/vhost1
ServerName vhost1.yourdomain.com
DirectoryIndex index.php
ErrorLog /var/log/apache2/vhost1-error.log
<Location />
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R]
</Location>
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmaster@yourdomain.com
DocumentRoot /var/www/vhost1
ServerName vhost1.yourdomain.com
DirectoryIndex index.php
ErrorLog /var/log/apache2/vhost1-error.log
CustomLog /var/log/apache2/vhost1-access.log combined
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/crt/vhost1.crt
SSLCertificateKeyFile /etc/apache2/ssl/key/vhost1.key
<Location />
SSLRequireSSL On
SSLVerifyClient optional
SSLVerifyDepth 1
SSLOptions +StdEnvVars +StrictRequire
</Location>

</VirtualHost>

Now if you restart your web server, you should be able to make it work straight away.

Note that if you do that on a fresh server, you might receive a “Configtest failed” error message. This is most likely to be due to the Rewrite or SSL modules not being enabled. Just enable them:

sudo a2enmod rewrite

sudo a2enmod ssl

sudo /etc/init.d/apache2 restart

 

2012-10-15 edit: as indicated by Gerard H. Pille in the comments to this article, Apache needs to be configured to answer on port 443 as well. This is generally a default setting in Debian/Ubuntu, but if you need to enable it, just locate the “Listen 80″ in your Apache configuration directory and add a “Listen 443” on the next line. Restart Apache, and you should be done with it.

2016-03-18 edit: although this article is quite old, the main principles are still valid for Apache 2.2 and 2.4. If you need to generate a self-signed SSL certificate, we recommend this article which only diverts a little regarding the path where the certificates are stored.

It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInShare on TumblrEmail this to someone

20 Comments

    • Hi. It is very unlikely that you can enable https on a shared hosting if you don’t have that option in your contract. This being said, their is generally a possibility to add the option to the cost of additional services.

  1. Thanks for a great article!
    Would you happen to know how this should work for multiple ssl virtual hosts (name based not IP based)?

    • I think it doesn’t (you have to have at least different virtual public addresses). You *can* have several subdomains of the same domain, using a multiple subdomains SSL feature, but having SSL for multiple domains on the same machine (or same IP) is still a problem, as far as I am aware…
      Now with all the cloud stuff and the virtualization of machines, it is kind of a little less problematic, but that is still kind of a technical headache (afaik)…

  2. Hi,

    I am using Apache Tomcat server version 5, i want to change HTTP connection to HTTPS connection. Can any one please suggest me how to do in clear.

    Thanks in Advance..

    Praveen.

  3. Hi,

    Currently i try to setup localhost with https function. I have apache in my pc and and openssl. I using Window Xp But, up till now i still unable to UP the https function. Wish you can help me. Thanks.

    • Sorry Hasanul, we don’t support non-open technologies stacks (i.e. Windows) for a lot of reasons. You might want to have a look at the microsoft knowledge base for that (I hear they are doing a “big effort” of interoperability these days).
      Good luck!

  4. Hi

    Im searching how to use https only in login page. This is because is a web that if not I can’t use mysql cache. Do you know the apache rule?

    Thanks

  5. This looks strange:

    SSLRequireSSL On
    SSLVerifyClient optional
    SSLVerifyDepth 1
    SSLOptions +StdEnvVars +StrictRequire

    You open a location tag and then immediately close it, then some directives and then closing the location tag again – you do this with all location tags

    Is this Apache syntax, or just a typo on your part?

    I tried both as prescribed and with

    SSLRequireSSL On
    SSLVerifyClient optional
    SSLVerifyDepth 1
    SSLOptions +StdEnvVars +StrictRequire

    and no matter what i get:

    SSL received a record that exceeded the maximum permissible length.

    (Error code: ssl_error_rx_record_too_long)

    Any tips on what this could be?

    • Probably just a typo on my part (for the opening and closing location tags), but I probably left it at the time to remember where to put it (at which level) later if needed. Thanks for pointing it out.

  6. Hmmm … I must’ve bungled it up

    I re-instated the weird tags and now I get what I expected. A warning that the certificate cannot be trusted and access after that

    Gotta say it out loud: APACHE IS WEIRD!

    a convention like: open tag = – closing tag = – openandclosetag = should not be messed with :)

    • You shouldn’t confuse the Apache configuration file syntax with XML. It is not XML.
      In Apache config files,

      actually means “the start of the section regarding location ‘/’ ” (the document root at the top of the pages hierarchy).
      Just like
      means “the start of the section regarding location ‘/abc’ “. And the end of any Location section is indicated by a

      It’s not weird; it’s only that it was invented before XML became popular.

  7. Good job with me.

    Just two small issues: I’ve tested it today on ubuntu desktop 10.04 and I get just a pair of easy-to-solve errors. Both in this step:
    openssl req -new -x509 -days 365 -keyout key/vhost1.key -out crt/vhost1.crt -nodes -subj ‘/O=VirtualHost Website Company name/OU=Virtual Host Website department/CN=www.virtualhostdomain.com’

    The first is “unknown option Website” and I fixed it by changing in this way:
    /etc/apache2/ssl$ sudo openssl req -new -x509 -days 365 -keyout key/vhost1.key -out crt/vhost1.crt -nodes -subj ‘/O=VirtualH/OU=Virtual/CN=www.virtualhostdomain.com’

    Now I get another error “Subject does not start with ‘/’.” and I fixed it by doing this way:
    sudo openssl req -new -x509 -days 365 -keyout key/vhost1.key -out crt/vhost1.crt -nodes -subj /O=VirtualH/OU=Virtual/CN=127.0.0.1’

  8. The problem with “Unknown option Webisite” is fixed by replacing the matched single quotes in the openssl command with ordinary single quotes. You probably cut and pasted the code into your console, right? WordPress blogs automatically translate single and double quotes into matched quotes, and it can screw up code.

    Great tutorial Yannick! I’ve generated my keys, but I’m going to have to go to bed before trying the rest tomorrow.

    • Interesting question. The Listen directive is usually enabled on port 443 on Debian/Ubuntu installations (/etc/apache2/ports.conf), so the process to enable it is not really necessary on that architecture, but yes, technically, there needs to exist a “Listen 443″ somewhere so that Apache can tell inetd that it will answer to port 443 (generally it also already answers to port 80). Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *