Making Self-signed Certificates Work
Colin J. Ihrig
Sometimes you need to configure HTTPS locally using a self-signed certificate. Here is a quick step by step guide. Note: this guide does not rely on "insecure" options such as curl's --insecure
flag.
Ensure that OpenSSL is installed. The following commands will rely on OpenSSL.
We are going to act as a Certificate Authority (CA). Create a private key for the CA.
openssl genrsa -out ca.key.pem 2048
- Create the root certificate for the CA. This cert will be valid for roughly ten years (3,650 days). You will be prompted to provide some values. Feel free to just press
Return
/Enter
until the prompting ends.
openssl req -x509 -new -nodes -key ca.key.pem -sha256 -days 3650 -out ca.cert.pem
- Create a key for our server.
openssl genrsa -out server.key.pem 2048
- Create a certificate signing request (CSR) for our server. Again, you will be prompted to provide some values. Again, feel free to press
Return
/Enter
until the prompting ends.
openssl req -new -key server.key.pem -out server.csr
- Create an X509 v3 certificate extension. Create a file named
server.cert.ext
with the following contents. Thealt_names
section can be configured as needed.
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = localhost
- Create a certificate for the server.
openssl x509 -req -in server.csr \
-CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial \
-days 3650 -sha256 -extfile server.cert.ext \
-out server.cert.pem
- Use the server certificate and key somehow. The following example creates a Node.js server, which can be run via the command
node server.js
:
'use strict';
const https = require('node:https');
const fs = require('node:fs');
const options = {
key: fs.readFileSync('server.key.pem'),
cert: fs.readFileSync('server.cert.pem'),
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(4000);
- Make a request to the server. You should see "hello world" printed. The
--cacert
flag tells curl to use our CA. Our CA is not expected to be used by anything else such as a web browser, so you will still see an insecure warning if your navigate your browser to the same URL.
curl https://localhost:4000 --cacert ca.cert.pem