Blog

Self signed certificate in Apache

I haven’t been able to update the Monocle Chronicles as much as I would like, so I’m trying to focus on shorter, more direct posts, rather than larger, multi-part tutorials, which is what I was previously trying to do.

Recently I’ve been working on a number of OSS web-based projects, using Apache on various Linux distros.  As with most of these projects, there’s a need for enabling SSL (HTTPS) for certain sections of the site (login, admin/user actions, etc.), if not the whole thing.  On a previous project, I worked through this and didn’t take great notes as to how to setup SSL, specifically with a self-signed certificate.  For these particular projects, self-signed was fine – and certainly cheaper – but this isn’t a great/ideal configuration, particularly for anything for widespread use.  The browser warnings alone are off-putting, and for good reason.

My general checklist for self-signed certificates are:

  • Need to secure a site, for small scale use – only needed/accessed by a handful of people.
  • 2048 bit key pair.  Pretty standard.  I’ve seen 4096 getting more popular as well.
  • 2 or 3 year expiry.  This helps ease maintenance.  Re-provisioning a self-signed cert is trivial if the key is compromised.

Lately, I’ve largely been working with Centos / Fedora / Amazon Linux, on Apache 2.4, so these instructions reflect that, but can easily extend to other versions/distros. This uses openssl in conjunction with Apache virtual hosts configuration (vhosts.conf). Without further ado, let’s fire up a terminal session and provision the certificate:

# openssl is often installed by default, if not:
yum install openssl

# generate the [rsa] key pair. use 2048 or 4096 key size. large key size is more cryptographically secure, but impacts performace
openssl genrsa -des3 -out private_key.pem 2048

# generate self-signed certificate signing request (CSR)
openssl req -new -key private_key.pem -out private_key_certificate_signing_request.csr

# next remove the password from the private_key. Otherwise apache will ask for the pass-phrase each time the web server is started
# note that if someone gets the unprotected key, it is effectively compromised and you'll need a new cert.
# make your pem readable only by root (chmod 600)
cp private_key.pem private_key.pem.orig
openssl rsa -in private_key.pem.orig -out private_key.pem

# generate the public self signed certificate. using 1095 days, which effectively will remain valid for 3 years.
# this is mainly for ease-of-use/administration.
openssl x509 -req -days 1095 -in private_key_certificate_signing_request.csr -signkey private_key.pem -out self_signed_public_certificate.crt

# now copy the private key (.pem file) and the public key (.crt) to your web server.
# apache on AWS EC2 (amazon linux/centos/fedora)
mkdir /etc/httpd/certs
cp self_signed_public_certificate.crt /etc/httpd/certs
cp private_key.pem /etc/httpd/certs

# optionally delete the CRT file. you don't need request anymore.
rm private_key_certificate_signing_request.csr

# if you don't have mod_ssl installed you need to install it.
# note: this is for apache/httpd 2.4. you may just need to install mod_ssl
yum install mod24_ssl

Now we need to configure Apache to use our shiny new certificate.  I typically do this via virtual hosts configuration (typically /etc/httpd/conf.d/vhosts.conf), as many times I’m working with multi-site (or multi-IP) configurations. This file specifies the port(s) (typically 443 for SSL) and what certificate to use.  Fire up vi, or your favorite editor, and create (or update) this file:


<VirtualHost *:80>
	ServerName yourdomain.com
	DocumentRoot /var/www/html/yourdomain.com
</VirtualHost>

<VirtualHost *:443>
	ServerName yourdomain.com
	DocumentRoot /var/www/html/yourdomain.com
	SSLEngine On
    SSLCertificateFile /etc/httpd/certs/self_signed_public_certificate.crt
    SSLCertificateKeyFile /etc/httpd/certs/private_key.pem
</VirtualHost>

<VirtualHost *:80>
	ServerName www.yourdomain.com
	DocumentRoot /var/www/html/yourdomain.com
</VirtualHost>

<VirtualHost *:443>
	ServerName www.yourdomain.com
	DocumentRoot /var/www/html/yourdomain.com
	SSLEngine On
    SSLCertificateFile /etc/httpd/certs/self_signed_public_certificate.crt
    SSLCertificateKeyFile /etc/httpd/certs/private_key.pem
</VirtualHost>

I’m sure there’s a more concise way to represent this configuration, which is basically 80/443 access for the www and non-www versions of a particular domain.  Once you’ve saved that file, restart apache:

service httpd restart

If all is well, you should be able to access the site using HTTPS.  You’ll be greeted with a prominent browser warning, but once dismissed, you will now browsing encrypted!

Leave Reply