vertner.net

New and Improved With SSL

FINALLY. After months of intermittently pounding my head and trying to figure this out, I finally got SSL (Secure Socket Layers) working on nginx (this blog’s web server) alongside the SSL-based OpenVPN Access Server. It was quite an adventure and took a bit of trial and error since most of the sites I found out there are pretty good at detailing some of the steps, but there was always something lacking.

Preparing OpenVPN

First things first, I needed to change the way OpenVPN presented its web GUI. Normally, connecting a browser to https://private.vertner.net (my VPN’s subdomain) would present OpenVPN’s client login page. I don’t support any external clients and don’t really have a need to download OpenVPN client configuration files when I’m away from my local network, so I switched the OpenVPN client login page over to port 943 (where the administrator login page resides). Just look under the Server Network Settings page and set the Client Web Server to Use the same address and port as the Admin Web Server. While on that same page, make sure that your Protocol is set to TCP. Why TCP? Because the default UDP port is sometimes filtered on networks and – as I learned the hard way – multi-daemon mode isn’t supported with port-sharing.

OpenVPN’s port-sharing feature is for doing exactly what we’re trying to accomplish. Basically, it allows OpenVPN to monitor port 443 (the default SSL port) and pass any non-VPN traffic heading into port 443 to another port. Simply go to Advanced VPN Settings and add port-share 127.0.0.1 4343 or whatever unused port number you want to the Server Config Directives.

Configuring nginx

Heading over to my server configuration file, I changed my primary server configuration block from this:

1
2
3
4
5
6
7
8
9
10
11
server {
        server_name vertner.net;
        listen 80;
        root /home/user/html;
        index index.html;

        location / {
                try_files $uri $uri/ =404;
        }
      #... other settings down here...
}

…to this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
        server_name vertner.net;
        listen 4343 ssl;

        ssl_certificate /etc/nginx/ssl/ssl-unified.crt;
        ssl_certificate_key /etc/nginx/ssl/ssl.key;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4;
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve secp384r1;

        root /home/user/html;
        index index.html;

        location / {
                try_files $uri $uri/ =404;
        }
      #... other settings down here...
}

Now, instead of listening for vertner.net traffic on port 80, it’s listening on the port 4343 that I defined earlier in OpenVPN. I’m purposefully only allowing certain protocols and cyphers to eliminate the security holes created by using older deprecated encryption methods.

I could generate self-signed certificates, but most browsers will generate errors instead of trust for doing so. Instead, I headed over to StartSSL and registered for a free SSL certificate and in order to get the following files:

  • An encrypted private key file (ssl.key)
  • The SSL/TLS certificate with a public key (ssl.crt)
  • An intermediate and root certificates which identify StartCom as a CA (certificate authority) (sub.class1.server.ca.pem and ca.pem)

I copied the ssl.key and ssl.crt over the server, created a new directory for nginx to store these files, then moved them into my new directory using the following commands:

1
2
3
4
5
mkdir /etc/nginx/ssl
scp ssl.key username@webserver:~
scp ssl.crt username@webserver:~
sudo mv ssl.crt /etc/nginx/ssl/
sudo openssl rsa -in ssl.key -out /etc/nginx/ssl/ssl.key

That last command should prompt you for your certificate password to decrypt the key. Next, I secured the decrypted key a bit by entering the following commands:

1
2
sudo chown root:root /etc/nginx/ssl/ssl.key
sudo chmod 400 /etc/nginx/ssl/ssl.key

This way if the site is compromised, the exploiter will only be able to read the contents of the key if they also get root access. Next, I downloaded the CA certificates with my old friend wget and squeezed all of the certificates together using cat.

1
2
3
4
cd /etc/nginx/ssl
sudo wget http://www.startssl.com/certs/ca.pem
sudo wget http://www.startssl.com/certs/sub.class1.server.ca.pem
sudo cat ssl.crt sub.class1.server.ca.pem ca.pem > /etc/nginx/ssl/ssl-unified.crt

With my certificates installed and ready, I made some minor additional tweaks to my server configuration file. First, I altered my “stop trying to go to www.vertner.net” block like so:

1
2
3
4
5
server {
        server_name vertner.net *.vertner.net;
        listen 80;
        return 301 https://vertner.net$request_uri;
}

This makes it so anybody who comes to the site on regular unsecured port 80 (http) will be automatically redirected to the secure site. Next, I wanted to make sure that anybody who tried to go to my VPN subdomain for a web page would also get pushed over to https://vertner.net by adding the following:

1
2
3
4
5
6
7
8
9
server {
        server_name private.vertner.net;
        listen 4343 ssl;

        ssl_certificate /etc/nginx/ssl/ssl-unified.crt;
        ssl_certificate_key /etc/nginx/ssl/ssl.key;

        return 301 https://vertner.net$request_uri;
}

I saved my work and reloaded nginx with a quick sudo /etc/init.d/nginx restart.

Testing My Work

Finally, I wanted to verify the security of my SSL implementation. The number of very aggressive SSL exploits coming out in the last few years should be a cautionary tale for anybody looking to secure their sites. I headed over to Qualys SSL Labs Server Test and put it to the test. I’m making a note here: huge success.

It’s hard to overstate my satisfaction.It’s hard to overstate my satisfaction.

Comments