edd mann

Self-Signed SSL Certificates with Nginx and Apache

Since having the opportunity to discuss web application security (part 1, part 2) recently on the podcast, I thought it was a good time to have a deeper look into SSL/TLS (Transport Layer Security). There are plenty of good resources online discussing the technical side of the topic, however, at a high-level point-to-point encryption and server identification are the two problems it attempts to solve.

Self-signed SSL certificates are an inexpensive (free) means of taking advantage of point-to-point encryption on non-production, development server setups. The caveat to this is that visiting browsers will warn the user that the certificate should not be trusted, as it has been self-signed. If you require a trusted certificate for a production application, you are required to purchase a certificate from a reputable CA (Certificate Authority) to verify your identity.

Creating the Self-Signed Certificate

The examples in this post will directed at a CentOS setup, however, they should not differ much for other distributions. First we are required to create a private key to sign the certificate that will be used for visiting users. I have decided to use strong encryption (4096 bits, this can be lowered) and make the certificate valid for a year from creation. So as to allow the command to run in non-interactive mode I have supplied the certificate details that are required using the 'subj' option.

$ openssl req -newkey rsa:4096 -days 365 -nodes -x509 \
    -subj "/C=GB/ST=London/L=Fulham/O=Local/OU=Development/CN=local.dev/emailAddress=email@local.dev" \
    -keyout local.dev.key \
    -out local.dev.crt

We can now move the certificate and private key to the desired location and tighten up file permissions on the two files.

$ cp local.dev.crt /etc/ssl/certs/
$ cp local.dev.key /etc/ssl/private/
$ chmod 600 /etc/ssl/certs/local.dev.crt /etc/ssl/private/local.dev.key

Apache Configuration

Now that we have generated the private key and certificate we must next make sure that the SSL module is present and enabled in the Apache installation.

$ yum install mod_ssl

With the prerequisites out of the way we are now able to direct access through port 443 (HTTPS) to use the generated certificate.

<VirtualHost *:443>

    SSLEngine On
    SSLCertificateFile /etc/ssl/certs/local.dev.crt
    SSLCertificateKeyFile /etc/ssl/private/local.dev.key

    # ...

</VirtualHost>

Optional, we can also force all traffic sent and received be over HTTPS by redirecting HTTP requests to use the secure connection.

<VirtualHost *:80>

   Redirect permanent / https://www.example.com/

   # ...

</VirtualHost>

Nginx Configuration

With a similar process as the Apache configuration we can configure Nginx to use the generated certificate when accessed over port 443.

server {

    listen 443;

    ssl on;
    ssl_certificate /etc/ssl/certs/local.dev.crt;
    ssl_certificate_key /etc/ssl/private/local.dev.key;

    # ...

}

Optional, if you wish all traffic to be transported through HTTPS we can setup a permanent redirect on port 80.

server {

    listen 80;

    return 301 https://$host$request_uri;

}