Skip to content

openssl-https

This guide explains how to use OpenSSL to generate certificates that can be used by HTTPS webservers.

We will see both the Self-signed certificate and the CA-signed certificate scenarios.

Note: we will use *.lvh.me domains in the examples, as they always resolve to 127.0.0.1 (localhost).

Self-signed certificate

Although using a self-signed certificate for your web server is generally discouraged, creating one is actually quite simple, as it basically involves only a single command:

Bash
openssl req -x509 -newkey rsa:4096 -keyout server.key -nodes -out server.crt -days 365 -subj '/CN=example01.lvh.me' -addext 'subjectAltName=DNS:example01.lvh.me,DNS:*.example01.lvh.me' -addext 'basicConstraints=critical,CA:FALSE'

Note: see the Caveats section for more details about the certificate generation command.

Note that browsers always show a warning message like this one for self-signed certificates (e.g. Firefox):

See the Testing section to check that your certificate works as intended.

CA-signed certificate

In order to create a CA-signed certificate, let's create a CA (Certificate Authority) first:

Bash
openssl req -x509 -newkey rsa:4096 -keyout ca.key -nodes -out ca.crt -days 365 -subj '/CN=My CA'

Then we need to create a CSR (Certificate Signing Request):

Bash
openssl req -newkey rsa:4096 -keyout server.key -nodes -out server.csr -subj '/CN=example01.lvh.me'

We also need a ca.srl file, which will keep track of the serial numbers assigned to certificates issued by the CA:

Bash
openssl rand -hex 16 > ca.srl

Note: although the serial number maximum length is 20 bytes, we generate only 16 random bytes as the initial serial number, because the serial must always be positive, so we don't want the first byte to be in the 80-FF range.

Finally, we can sign the CSR and get the signed certificate:

Bash
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAserial ca.srl -out server.crt -days 365 -extfile <(echo 'subjectAltName=DNS:example01.lvh.me,DNS:*.example01.lvh.me'; echo 'basicConstraints=critical,CA:FALSE')

Note: see the Caveats section for more details about the certificate signing command.

Note: as you may have noticed, we need to specify the validity days and extensions in the final signing command instead of the CSR creation one.

See the Testing section to check that your certificate works as intended.

Testing

You can use the following commands to quickly analyze the generated files:

Bash
1
2
3
openssl x509 -in server.crt -noout -text
openssl rsa -in server.key -noout -text
openssl req -in server.csr -noout -text

You can also start a simple HTTPS web server to test a certificate, like this:

Bash
openssl s_server -cert server.crt -key server.key -accept 127.0.0.1:4433 -www

Then you can open a web browser and head over to https://example01.lvh.me:4433/.

Note: we are able to use the TCP port 4433 or any other port we want, because X.509 certificates aren't bound to specific ports, but to domain names (or IP addresses) instead.

For production environments, you may also want to generate and use custom Diffie-Hellman (DH) parameters instead of relying on default ones:

Bash
openssl dhparam -out dhparam.pem 4096
openssl s_server -cert server.crt -key server.key -dhparam dhparam.pem -accept 127.0.0.1:4433 -www

Caveats

We set the SANs (Subject Alternative Names) to create a wildcard certificate that also covers all the *.example01.lvh.me subdomains. You can also see that by inspecting the certificate details in a web browser (e.g. Firefox):

We create a leaf certificate by setting the CA basic constraint to FALSE. You can also see that by inspecting the certificate details in a web browser (e.g. Firefox):

That prevents users from adding the server certificate to their browsers as a trusted CA: