Setting up Self Signed SSL on localhost and 192.168.0.*

Lately, I've been experimenting with Service Workers to create a Progressive Web App. One of the requirements of Service Workers is that the host domain has an SSL certificate (or just be on localhost). That's not a problem when I'm working locally on my desktop, but I often test applications on my phone as well. To do that, I setup port forwarding on my network so I can access my localhost server using 192.168.0.* on my phone. That introduces two problems that I've never ran into before...

  1. Because I'm on my phone, I need the development server to use a self signed certificate that is valid for localhost and 192.168.0.*
  2. I need to import the self signed certificate onto my Android phone.

To solve #1, I spent the morning digging through stackoverflow and finally found this gem: https://stackoverflow.com/a/41366949/176108

To generate a self-signed certificate that works on localhost, 127.0.0.1, and 192.168.0.100, I ran this command in git bash.

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
  -nodes -keyout dev.private.key -out dev.certificate.crt \
  -subj "//CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:192.168.0.100"

Which generated dev.private.key and dev.certificate.crt.

I then plugged the key and cert into my BrowserSync development server. I added them to the "https" field of the BrowserSync config file.

"https": {
    key: "env/dev.private.key",
    cert: "env/dev.certificate.crt",
}

After that, I had to import the dev.certificate.crt file as a trusted certificate in Windows. That was done via Internet Options > Content > Certificates > Import.

Then I copied dev.certificate.crt to the SD card of my phone. On Android version 9, I then went to Settings -> Security & Location -> Advanced -> Encryption & Credentials and selected "Install from SD Card". I navigated to the folder where I put the .crt file and then selected it. Android then asked for the name of the certificate and I gave it a name and chose "VPN and Apps" for the "Credential Use" field. I selected OK. Then I went to the "User Credentials" group and saw that the new certificate was added.

I then started my local server and I had a good certificate that worked locally and on my phone and allowed me to use the Service Worker in all locations.

Additional Notes

Along the way, I learned a few details about SSL Certificates and Open SSL.

Subject Alternative Names (SAN)

This line of the command we ran added Subject Alternative Names to the certificate.

-addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:192.168.0.100"

The SAN list indicates what domain names and IP addresses are secured by the certificate. In the OpenSSL Config file (which I didn't have to use), these are defined in the "alternate_names" section.

[ alternate_names ]
DNS.1      = localhost
IP.1       = 127.0.0.1
IP.2       = 192.168.0.105

There are a large number of configuration fields in the OpenSSL Config file. Thankfully, I did not have to set one up.

Remote Browser Inspection

When I was working on this, it was helpful to do some remote debugging. See here for how to do that: https://developer.chrome.com/docs/devtools/remote-debugging In short, you'll need to enable developer mode on your phone, then go to chrome://inspect/#devices and find the browser tab that you want to inspect on your phone.