How to create a self-signed certificate
Tags: ssl, tls, https, certificate
Published: 2019-07-09 23:25:12

---
title: How to create a self-signed certificate
series: squid-cache
published: true
description: How to create a self-signed certificate with OpenSSL
cover_image: https://www.linode.com/docs/security/ssl/create-a-self-signed-tls-certificate/create-a-self-signed-tls-certificate-title-graphic.jpg
tags: ssl,tls,https,certificate
---

### Prefix

All previous [squid caching server](http://www.squid-cache.org/) series  talk about SSL bumping, and include steps on creating a self-signed certificate. I.e., it has been overly-discussed -- 

- You can find many other blog/articles talking about this all over the Internet. Besides,
- There is a [question on stackoverflow](https://stackoverflow.com/questions/10175812/) with over a thousand up votes. 

So why another one? 

- First, many such blog/articles just talk about it, giving some commands but without explaining the parameters in details (just like the first two articles we covered in this series). E.g., the comment _`-nodes` doesn't mean "nodes"_ have received over four hundred up-votes before the explanation is added to the above accepted answer. 
- You will find that each of them, of all those blog/articles on the Internet, are doing it _a little bit_ differently. So why the differences? And again, is any of them outdated?
- And most importantly, the accepted answer is not the only answer there, and if you scroll down, you'd realized that there are much more things to be cautious on than the accepted answer. For example, 
- _"Modern browsers now throw a security error for otherwise well-formed self-signed certificates ..., so many developers' tutorials and bookmarks are suddenly outdated."_ A comment can be easily missed because it is buried within all the other answers and resides at the very low part of them, you have to scroll a long way to get to it. 

This is part of my fact-collecting blog of the [squid caching server](http://www.squid-cache.org/) series, extending on the creating self-signed certificate part, which combines the image & writing from Linode's [Create a Self-Signed TLS Certificate](https://www.linode.com/docs/security/ssl/create-a-self-signed-tls-certificate/) and the answers from above [stackoverflow question](https://stackoverflow.com/questions/10175812/).


### What is a Self-Signed TLS Certificate?

Self-signed TLS certificates are suitable for personal use or for applications that are used internally within an organization. If you intend to use your SSL certificate on a website, see our (linode.com) guide on enabling TLS for [NGINX](https://www.linode.com/docs/web-servers/nginx/enable-tls-on-nginx-for-https-connections/) once you’ve completed the process outlined in this guide.

### Create the Certificate - Getting Started

Again, reposting from linode's [article](https://www.linode.com/docs/security/ssl/create-a-self-signed-tls-certificate/),

1.  Change to the `root` user and change to the directory in which you want to create the certificate and key pair. That location will vary depending on your needs. Here we'll use `/root/certs`:

        su - root
        mkdir /root/certs && cd /root/certs

2.  Create the certificate:

        openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out MyCertificate.crt -keyout MyKey.key

You will be prompted to add identifying information about your website or organization to the certificate. Since a self-signed certificate won't be used publicly, this information isn't necessary. If this certificate will be passed on to a certificate authority for signing, the information needs to be as accurate as possible.

The following is a breakdown of the OpenSSL options used in this command. There are many other options available, but these will create a basic certificate which will be good for a year. For more information, see `man openssl` in your terminal.

* `-newkey rsa:4096`: Create a 4096 bit RSA key for use with the certificate. `RSA 2048` is the default on more recent versions of OpenSSL but to be sure of the key size, you should specify it during creation.
* `-x509`: Create a self-signed certificate.
* `-sha256`: Generate the certificate request using 265-bit SHA (Secure Hash Algorithm).
* `-days`: Determines the length of time in days that the certificate is being issued for. For a self-signed certificate, this value can be increased as necessary.
* `-nodes`: Create a certificate that does not require a passphrase. If this option is excluded, you will be required to enter the passphrase in the console each time the application using it is restarted.


3.  Restrict the key's permissions so that only `root` can access it:

        chmod 400 /root/certs/MyKey.key

4.  Back up your certificate and key to external storage. **This is an important step. Do not skip it!**


### Create the Certificate - The whole nine-yard

That's quite clear. Unfortunately it is now fallen into those _"suddenly outdated"_ developers' tutorials and bookmarks, because _"Modern browsers now throw a security error"_. So the following are the summary of the above stackoverflow question, to the best of my knowledge. 

To create a self-signed certificate, which does not chain back to a trusted anchor, involves:

1. Create your own authority (i.e., become a CA)
1. Create a certificate signing request (CSR) for the server
1. Sign the server's CSR with your CA key

But the devil is in the details:

- The above may take several steps, for each of them, but it may also be done in one command.
- Some command in the out-dated articles uses `SHA-1` hash algorithm which in many browsers throws warnings in console, because now "SHA-1 certificates" are considered not secure. So remember to use `-sha256` to generate SHA-256-based certificates.
- However, there is a saying that, using `SHA-2` does not add any security to a self-signed certificate (updated May 2018). If it concerns you, check the details [here](https://stackoverflow.com/a/26462803/2125837). 
- _"You will be prompted to add identifying information"_, so use `-subj '/CN=localhost'` (replace `localhost` with your desired domain) to suppress  the whole list of questions about the contents of the certificate. However, be aware that using `CN` is now deprecated, because of the following point.
- Modern browsers now throw a security error for otherwise well-formed self-signed certificates if they are missing a `SAN` (Subject Alternate Name), so many developers' tutorials and bookmarks are suddenly outdated.  There has been a while that OpenSSL had not been able to provide a command-line way to specify `SAN`, and you had to create a short, stand-alone conf file first. Many examples are doing that way, however, 
- As of 2019, all can be done in one single command, including `SAN`.
- Note that to complicate things up, browsers follow the CA/Browser Forum policies; and not the IETF policies. That's one of the reasons a certificate created with OpenSSL (which generally follows the IETF) sometimes does not validate under a browser (browsers follow the CA/B). They are different standards, they have different issuing policies and different validation requirements.
- Thus, it's important to put DNS name in the `SAN` and not the `CN`, because both the IETF and the CA/Browser Forums specify the practice. They also specify that DNS names in the `CN` are deprecated (but not prohibited). If you put a DNS name in the `CN`, then it must be included in the `SAN` under the `CA/B` policies. So you can't avoid using the Subject Alternate Name `SAN`.
- The self-signed certificate provides the same level of encryption as a  certificate signed by a trusted authority ([costing around $1000 ~ $2000 per year](https://www.websecurity.symantec.com/buy-renew?ef_id=Cj0KCQiAwc7jBRD8ARIsAKSUBHL3u_wl0kyXRrvQM3Fj2H9j9T6FogZsQVjmxinnw6KIf9xVvUP9O64aAj0KEALw_wcB:G:s&s_kwcid=AL!6100!3!225648135095!e!!g!!symantec%20ssl%20certificate&gclid=Cj0KCQiAwc7jBRD8ARIsAKSUBHL3u_wl0kyXRrvQM3Fj2H9j9T6FogZsQVjmxinnw6KIf9xVvUP9O64aAj0KEALw_wcB)), however it is not validated with any third party unless you import it to the browsers, once.




### Create the Certificate - [The actual command](https://stackoverflow.com/a/41366949/2125837)


As of 2019, the following command serves all your needs, including SAN:

    openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -extensions san -config <(echo "[req]"; echo distinguished_name=req; echo "[san]"; echo subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1) -subj /CN=example.com

Further, with OpenSSL ≥ 1.1.1, this can be shortened to:

    openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj /CN=example.com -addext subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1

It creates a certificate that is

* valid for the domains `example.com` and `example.net` (SAN),
* also valid for the IP address `10.0.0.1` (SAN),
* relatively strong (as of 2019) and
* valid for `3650` days (~10 years).

It creates the following files:

* Private key: `example.key`
* Certificate: `example.crt`

All information is provided at the command line. There is no annoying interactive input. There is no messing around with config files. All necessary steps are executed by this single OpenSSL invocation: from private key generation up to the self-signed certificate.

**Remark #1: Crypto parameters**

Since the certificate is self-signed and needs to be accepted by users manually, it doesn't make sense to use a short expiration or weak cryptography.

In the future, you might want to use more than `4096` bits for the RSA key and a hash algorithm stronger than `sha256`, but as of 2019 these are sane values. They are sufficiently strong while being supported by all modern browsers.

**Remark #2: Parameter "`-nodes`"**

Theoretically you could leave out the `-nodes` parameter (which means "no DES encryption"), in which case `example.key` would be encrypted with a password. However, this is almost never useful for a server installation, because you would either have to store the password on the server as well, or you'd have to enter it manually on each reboot.

**Remark #3: MinGW**

On Windows in the MinGW bash, you should prefix the command with `MSYS_NO_PATHCONV=1`:

    MSYS_NO_PATHCONV=1 openssl ...

Alternatively, run the command in the plain `cmd.exe` Windows command prompt.

**Remark #4: See also**

* [Provide subjectAltName to openssl directly on command line][1]
* [How to add multiple email adresses to an SSL certificate via the command line?][2]
* [More information about MSYS_NO_PATHCONV][3]


  [1]: https://security.stackexchange.com/a/198409/133603
  [2]: https://unix.stackexchange.com/a/333325/20407
  [3]: https://stackoverflow.com/a/34386471/19163


To combine the two (Private key `.key` & Certificate `.crt`) into a `.pem` file:

`cat server.crt server.key > cert.pem`

Moreover, in order to use the self-signed certificate, you have to

- Install the server certificate on the server
- Install the CA certificate on the client

which we've already covered in the previous articles. 




### Create the Certificate - Parameter explained

Here are the [options][diegows] described in more detail, from [the documentation][docs]:

    openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX

>     req
> PKCS#10 certificate request and certificate generating utility.

>     -x509
> this option outputs a self signed certificate instead of a certificate request.
> This is typically used to generate a test certificate or a self signed root CA.
>
>     -newkey arg
> this option creates a new certificate request and a new private key. The argument
> takes one of several forms. **rsa:nbits**, where **nbits** is the number of bits,
> generates an RSA key **nbits** in size.
>
>     -keyout filename
> this gives the filename to write the newly created private key to.
>
>     -out filename
> This specifies the output filename to write to or standard output by default.
>
>     -days n
> when the **-x509** option is being used this specifies the number of days to certify
> the certificate for. The default is 30 days.
>
>     -nodes
> if this option is specified then if a private key is created it will not be encrypted.

The documentation is actually more detailed than the above summary. 

[diegows]: https://stackoverflow.com/a/10176685/456814
[docs]: https://www.openssl.org/docs/apps/req.html




### Create the Certificate - For the public

Should you want to get a real certificate that will be recognizable by anyone on the public Internet then the procedure is below.

1. Generate a private key
1. Use that private key to create a CSR file
1. Submit CSR to CA (Verisign or others, etc.)
1. Install received cert from CA on web server
1. Add other certs to authentication chain depending on the type cert

check the details [here](https://stackoverflow.com/a/29406186/2125837).