If you just need encryption for internal server connections or non-user facing sites, signing your own SSL certificates is an easy way to avoid dealing with an external certificate authority. Here’s how to set it up in nginx.
If you are more interested in getting free SSL certificates, you can always use LetsEncrypt, which is more suitable for public servers with user-facing websites because it will show up as coming from a recognized certificate authority in user’s browsers. However, it can’t be used to encrypt private IP addresses, which is why you must sign a cert yourself.
Generate and Self-Sign an SSL Certificate
To do this, we’ll use the openssl utility. You likely have this installed already, as it’s a dependency of Nginx. But if it’s somehow missing, you can install it from your distro’s package manager. For Debian-based systems like Ubuntu, that would be:
After openssl is installed, you can generate the certificate with the following command:
You’ll be asked for some info about your organization. Because this is self-signed, the only one that really matters is “Common Name,” which should be set to your domain name or your server’s IP address.
This will take a second to generate a new RSA private key, used to sign the certificate, and store it in /etc/ssl/private/nginx.key. The certificate itself is stored in /etc/ssl/certs/nginx.crt, and is valid for an entire year.
We’ll also want to generate a Diffie-Hellman group. This is used for perfect forward secrecy, which generates ephemeral session keys to ensure that past communications cannot be decrypted if the session key is compromised. This isn’t entirely necessary for internal communications, but if you want to be as secure as possible you shouldn’t skip this step.
This does take a while—about an hour depending on how fast your server is. Grab some lunch, and come back to your terminal in a bit to configure Nginx.
RELATED: What Is a PEM File and How Do You Use It?
Configure Nginx to Use Your Private Key and SSL Certificate
To make things easy, we’ll put all the configuration in a snippet file that we can include in our nginx server blocks. Create a new configuration snippet in nginx’s snippets directory:
Open it up in your favorite text editor, and paste the following in:
The first two lines of this snippet configure nginx to use our self-made certificate and our own private key. The next block is general SSL settings, and finally the last two lines configure nginx to use our Diffie-Hellman group for forward security. You can omit this if you didn’t feel like waiting.
The only other thing to enable would be HTTP Strict Transport Security, which configures your site to always use SSL. This would require a permanent redirect from HTTP to HTTPS, so you should verify that SSL works before enabling it.
Now, modify your primary nginx configuration (usually located at /etc/nginx/nginx.conf for single sites, or under your domain name in /etc/nginx/sites-available for multi-site servers), and source the snippet:
You’ll also want to set up a redirect from HTTP to HTTPS, which you can do with an additional server block listening on port 80:
This is a 302 redirect, which is only temporary. You’ll want to switch this to 301 if everything works properly.
Test your configuration by restarting nginx:
Because HTTPS traffic uses port 443, you’ll need to configure your firewalls to allow transport over that port. If you’re using iptables or UFW, you’ll need to open ports from the command line. If you’re using a hosting service like AWS that has a built in firewall, you’ll need to also open them from their web interface.
If your service is operating entirely within your LAN, you might want to whitelist your specific subnet of IP addresses to disable access from outside the LAN, and access your servers through a VPN connection.
If everything works correctly, you should now be able to access your server over HTTPS. Your web browser may display a warning like this:
Don’t worry, this is expected, and the reason why you can’t use these certificates for client-facing websites. You’ll have to manually confirm that you trust the server in order to access it.
The warning displayed here is slightly misleading—your site is secure so long as the private key is not compromised, and it’s perfectly secure if you set up Diffie-Hellman forward secrecy. The problem lies in identity, as Chrome can’t verify that your server is who it says it is, because you signed the cert yourself.
Once you’ve verified that there are no issues with SSL, you can switch the HTTP redirect to a 301 redirect:
And restart nginx to apply the changes.