How to issue a self-signed SSL certificate and make your browser trust it

  • Tutorial


All major sites have long switched to the https protocol. The trend continues, and many of our customers want their site to work on a secure protocol. And if a backend is being developed for a mobile application, then https is required. For example, Apple requires the server to communicate with the application using a secure protocol. This requirement has been introduced since the end of 2016 .

There are no certificate issues on production. Typically, a hosting provider provides a convenient interface for connecting a certificate. Issuing a certificate is also not a complicated matter. But while working on a project, each developer must take care of the certificate himself.
In this article, I’ll show you how to issue a self-signed SSL certificate and make the browser trust it.

To issue a certificate for your local domain, you need a root certificate. On its basis, all other certificates will be issued. Yes, for each new top level domain you need to issue your own certificate. Obtaining a root certificate is quite simple.
First, create the private key:

openssl genrsa -out rootCA.key 2048

Then the certificate itself:

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

It will be necessary to enter a country , city , company , etc. As a result, we get two files: rootCA.key and rootCA.pem

We turn to the main issue of the self-signed certificate. As with the root, these are two commands. But the teams will have much more options. And we need an auxiliary configuration file. Therefore, we will arrange all this in the form of a bash script create_certificate_for_domain.sh

The first parameter is required, we will display a small instruction for the user.

if [ -z "$1" ]
then
  echo "Please supply a subdomain to create a certificate for";
  echo "e.g. mysite.localhost"
  exit;
fi

Create a new private key if it does not exist or use the existing one:

if [ -f device.key ]; then
  KEY_OPT="-key"
else
  KEY_OPT="-keyout"
fi

We ask the user for the domain name. Add the ability to specify a “common name” (it is used when generating the certificate):

DOMAIN=$1
COMMON_NAME=${2:-$1}

In order not to answer questions in an interactive mode, we will form a line with answers. And set the certificate validity period:

SUBJECT="/C=CA/ST=None/L=NB/O=None/CN=$COMMON_NAME"
NUM_OF_DAYS=999

The SUBJECT variable lists all the same questions that were asked when creating the root certificate ( country , city , company , etc.). All values ​​except CN can be changed at your discretion.

Will form a csr file (Certificate Signing Request) based on a key. Read more about the certificate request file in this article .

openssl req -new -newkey rsa:2048 -sha256 -nodes $KEY_OPT device.key -subj "$SUBJECT" -out device.csr

We form the certificate file . For this we need an auxiliary file with settings. In this file we will write the domains for which the certificate and some other settings will be valid. Let's call it v3.ext . Please note that this is a separate file, and not part of a bash script.

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = %%DOMAIN%%
DNS.2 = *.%%DOMAIN%%

Yes, true, our certificate will be valid for the main domain, as well as for all subdomains. We save the above lines to the v3.ext file. We

return to our bash script. Based on the auxiliary file v3.ext, we create a temporary file indicating our domain:

cat v3.ext | sed s/%%DOMAIN%%/$COMMON_NAME/g > /tmp/__v3.ext

We issue a certificate:

openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days $NUM_OF_DAYS -sha256 -extfile /tmp/__v3.ext

Rename the certificate and delete the temporary file:

mv device.csr $DOMAIN.csr
cp device.crt $DOMAIN.crt
# remove temp file
rm -f device.crt;

The script is ready. Run it:

./create_certificate_for_domain.sh mysite.localhost

We get two files: mysite.localhost.crt and device.key

Now we need to tell the web server the path to these files. Using nginx as an example, it will look like this:

nginx ssl

Launch a browser, open https: //mysite.localhost and see:



The browser does not trust this certificate. How to be

It is necessary to mark the certificate issued by us as Trusted. On Linux (Ubuntu and probably the rest of Debian-based distributions) this can be done through the browser itself. On Mac OS X, this can be done through the Keychain Access application. We launch the application and drag the file mysite.localhost.crt into the window . Then open the added file and select Always Trust: We



refresh the page in the browser and:



Success! The browser trusts our certificate.

The certificate can be shared with other developers so that they add it to themselves. And if you use Docker, then the certificate can be saved there. That is how it is implemented on all our projects.

Share in the comments, do you use https for local development?

Maxim Kovtun,
Head of Development

Also popular now: