This days, security and encryption is one of the most important topics and that’s why we need to have certain amount of knowledge about commonly used methods. TLS/SSL works by using a combination of a public certificate and a private key. The SSL key is kept secret on the server. It is used to encrypt content sent to clients. The SSL certificate is publicly shared with anyone requesting the content. It can be used to decrypt the content signed by the associated SSL key.
We can create a self-signed key and certificate pair with OpenSSL in a single command. However, new browsers complain about self signed certificates, so we need some additional configurations for them. We’ll create only one configuration file to keep steps as much as minimum.
First create a file named nginx-selfsigned.conf with the content of:
[req] default_keyfile = /etc/ssl/private/nginx-selfsigned.key distinguished_name = req_distinguished_name prompt = no x509_extensions = v3_ca [req_distinguished_name] C = DE ST = Berlin L = Berlin O = MYORG OU = MYTEAM CN = myapp.myteam.com emailAddress = email@example.com [v3_ca] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid basicConstraints = CA:true subjectAltName = @alt_names [alt_names] DNS.1 = myapp.myteam.com
Let’s talk about this configuration file in an abstract way. Normally, creating certificate requires few steps like, creating key, requesting intermediate certificate, signing and etc. Since we’ll create self signed certificate in single command, we just created a section for request parameters. In here, we defined the key file location to be created. During certificate request, there is few questions to identify signer. In
req_distinguished_name we answer these questions and in third line we create a reference to this section. Then we disabled the prompt questions since we already answered them in second section. New browsers like Chrome requires
subjectAltName information to validate certificate. We created a new section for those extensions and specify some necessary attributes over there. You can search the internet for detailed descriptions of attributes. However, be cautious with the Common Name (CN) field, which should be the exact Fully Qualified Domain Name (FQDN) or IP address of the host that you intend to use the certificate with.
After creating configuration file we run this command:
sudo openssl req -x509 -nodes -sha256 -days 1024 -newkey rsa:2048 -config nginx-selfsigned.conf -out /usr/local/share/ca-certificates/nginx-selfsigned.crt
It is basically saying that we want to create a x509 certificate with a key file valid for 1024 days using our configuration file. After this command runs successfully, you should be able to see certificate in
/usr/local/share/ca-certificates/nginx-selfsigned.crt. At this step, we actually created the certificate but we need additional steps to use it properly.
In order to OpenSSL to find the certificate, it needs to be looked up as its hash. Normally, you would create a symbolic link for a meaningful name of the CA to the hash value, rather than renaming the CA certificate. Ideally, create a symbolic link (or hard link if you must, but symbolic ones usually make spotting which hash is which certificate name that bit easier). The symbolic link must be for the hashed value above plus “.0” – if you forget the .0 then OpenSSL won’t detect it, and you’ll get lots of errors. But, to make it more with Linux utilities, you can use below command (assuming crt file in /usr/local/share/ca-certificates directory, otherwise you should use command in comment):
sudo update-ca-certificates ### sudo ln -s /usr/local/share/ca-certificates/nginx-selfsigned.crt /etc/ssl/certs/`openssl x509 -hash -noout -in /usr/local/share/ca-certificates/nginx-selfsigned.crt`.0 #backup if above command not working
We’re now to test this installation. To do so, we really want a certificate that’s been signed by the newly installed CA. Failing this, you can use the CA certificate, but this won’t always cause all the possible errors to show up. Run:
openssl verify /usr/local/share/ca-certificates/nginx-selfsigned.crt
If you’ve got it correct, you should see something like:
Which tells you that your CA certificate is correctly installed. If you want to see how certificate looks like, you can run:
openssl x509 -in /usr/local/share/ca-certificates/nginx-selfsigned.crt -text -noout
Create a Configuration Snippet Pointing to the SSL Key and Certificate For Nginx
First, let’s create a new Nginx configuration snippet in the
/etc/nginx/snippets directory. Within this file, we just need to set the ssl_certificate directive to our certificate file and the ssl_certificate_key to the associated key.
sudo vi /etc/nginx/snippets/self-signed.conf
In our case, this will look like this:
ssl_certificate /etc/ssl/certs/nginx-selfsigned.pem; ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
Adjust the Nginx Configuration to Use SSL
In default, Nginx configuration file is at
/etc/nginx/sites-available/default. Let’s open this file:
sudo vi /etc/nginx/sites-available/default
Comment out necessary lines and add new snippet. At the end of editing, below lines should be in configuration:
listen 443 ssl; listen [::]:443 ssl default_server; include snippets/self-signed.conf;
Now that we’ve made our changes, we can restart Nginx to apply our new changes.
First, we should make sure that there are no syntax errors in our files. We can do this by typing:
sudo nginx -t
If everything is successful, you should see:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
If your output matches the above, your configuration file has no syntax errors. We can safely restart Nginx to implement our changes:
sudo systemctl restart nginx
For testing, you can redirect the https domain to your localhost by adding the following to /etc/hosts:
Test that TLS is working as expected (especially the validation):
openssl s_client -connect myapp.myteam.com:443
The output should look like this at the beginning:
CONNECTED(00000003) depth=0 C = DE, ST = Berlin, L = Berlin, O = MYORG, OU = MYTEAM, CN = myapp.myteam.com, emailAddress = firstname.lastname@example.org verify return:1 --- Certificate chain 0 s:/C=DE/ST=Berlin/L=Berlin/O=MYORG/OU=MYTEAM/CN=myapp.myteam.com/emailAddressemail@example.com i:/C=DE/ST=Berlin/L=Berlin/O=MYORG/OU=MYTEAM/CN=myapp.myteam.com/emailAddressfirstname.lastname@example.org --- Server certificate -----BEGIN CERTIFICATE-----
To use this certificate in Chrome you should add your certificate to trusted directory:
certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "My Homemade CA" -i /etc/ssl/certs/nginx-selfsigned.pem
And check it is exist:
certutil -d sql:$HOME/.pki/nssdb -L