There are plenty of times when you are working on a website that uses SSL and you need to work on that site locally in your own development environment. Usually you just set things up not to run on SSL locally because it’s generally less trouble than getting SSL working on your local web server. Sometimes, however, you really need a local development environment that supports SSL. Here is how to do it for free with a self-signed SSL certificate.
UPDATED: April 22, 2017 – SubjectAltName
Chrome released an update recently that requires the SSL certificate to list the various domains you are using for your wildcard certificate under the Subject Alt Names section of your certificate. So, I’m updating this post to show you how to do that.
The Big Picture
I’m setting up a wildcard SSL certificate to use for local development with my wildcard virtual host configuration on nginx. This will let you spin up new sites using an SSL certificate without ever having to mess with /etc/hosts
file or server configurations. I’m going to be using the local development domain lee.dev. After completing this, to create a new development site, Just create a new directory and your site will be available at https://<dir_name>.lee.dev.
openssl Configuration
The trick to this whole thing lies in the openssl.cnf file. Set up a temporary directory to work in at ~/tmp/ssl
just too keep all these files together. Then, after generating the cert and key files, we’ll move them to where they need to be.
So… make a copy of your main openssl.cnf file to work with:
cp /etc/ssl/openssl.cnf ~/tmp/ssl/openssl.cnf
Now, open the copy of openssl.cnf and add (or uncomment) this line from the [v3_req] section of the file:
[v3_req] ... x509_extensions = v3_ca
Then, add this section to the end of the [v3_req] section:
[v3_ca] ... subjectAltName = @alt_names [alt_names] DNS.1 = *.lee.dev DNS.2 = lee.dev
Generate Self-Signed SSL Certificate
I am going to generate a key file and certificate for my local development domain lee.dev. You would replace lee.dev with whatever your domain is, or you could just use file names like server.key
and server.crt
– whatever fits your needs. The names of the files aren’t really very important other than for your own organizational needs.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout lee.key -out lee.crt -config openssl.cnf
The end result of all of this is your lee.key
file and your lee.crt
file which you will use in your nginx (or Apache) virtual host configuration. If you are creating a self-signed SSL certificate for a wildcard subdomain (like I am doing) then you will want to be sure to enter *.lee.dev when asked for your fully qualified domain name (FQDN) when creating your SSL certificate.
Here is what my nginx server block looks like. The key things to note, with regard to the SSL certificate, are:
- listen 443;
- ssl on;
- ssl_certificate /etc/ssl/lee.crt;
- ssl_certificate_key /etc/ssl/lee.key;
server { listen 443; ssl on; ssl_certificate /etc/ssl/lee.crt; ssl_certificate_key /etc/ssl/lee.key; server_name ~^(?<vhost>.+)\.lee\.dev$; root /home/lee/sites/$vhost; index index.php index.html index.htm index.nginx-debian.html; location / { try_files $uri $uri/ /index.php?q=$uri&$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass 127.0.0.1:9000; } }
Be sure to restart nginx to load your new configuration.
Getting Google Chrome To Accept Your Self-Signed Certificate on Ubuntu 16.04
This is done differently on different platforms. I am working on Ubuntu 16.04. If you are using any linux based setup you will need to use the certutil
command line tool for this. If you don’t have that command line tool, run this:
sudo apt-get install libnss3-tools
Now, navigate to your development website in your Google Chrome browser. You will see that the https: part of the URL is all red-X-ed out. Now we want to add our self-signed SSL certificate to Google Chrome so we can trust ourselves and not see the annoying security warnings for our local development.
Here’s what to do:
- click the lock icon with an X,
- choose Certificate Information
- go to Details tab
- Click on Export… (save as a file)
For me, the file saved as -.lee.dev
because I created a wildcard SSL certificate for the domain lee.dev
. It doesn’t matter what the file name is, just make note of what the file name is so you can use it in the next command.
The following command will add the certificate (where YOUR_FILE is your exported file):
certutil -d sql:$HOME/.pki/nssdb -A -t "P,," -n YOUR_FILE -i YOUR_FILE
To see if it actually worked, you can list all of your certificates with this command:
certutil -d sql:$HOME/.pki/nssdb -L
Now, when you go to your site you should see that Google Chrome trusts your self-signed SSL certificate.
Removing A Certificate
If you need to delete a certificate do the following:
certutil -D -d sql:$HOME/.pki/nssdb -n -.lee.dev
where -.lee.dev
is the name of your certificate. To see a list of all your certificates and their names use this command:
certutil -d sql$HOME/.pki/nssdb -L
Resources
I learned this series of steps from the following sources:
Very easy to follow instructions. Worked first time!
On CentOS the configuration file is here: “/etc/pki/tls/openssl.cnf”.
Getting error line saying: “certutil: function failed: SEC_ERROR_BAD_DATABASE: security library: bad database.”
Came here for this. This solution makes Chrome happy and works great for Debian and Apache 2 as well. Thanks for posting! For Apache, the conf file will look like:
SSLEngine on
SSLCertificateFile /etc/ssl/…/dev.lee.crt
SSLCertificateKeyFile /etc/ssl/…/dev.lee.key
Thank you for this. Awesome!
The database has migrated over the years from flat files to Berkeley DB to now SQLite in 3.12. Prefix the directory name with sql and enclose in quotes to get around spaces:
certutil -L -d sql:${HOME}/.pki/nssdb
For reference, here’s the Mozilla NSS roadmap.
This is interseting, but there’s no need to go to the trouble any more now that SSL certificates are available free:
Let’s Encrypt – Free SSL/TLS Certificates
https://letsencrypt.org/
AWS Certificate Manager
https://aws.amazon.com/certificate-manager/pricing/
Setup is not longer working with:
Google Chrome Version 65.0.3325.146 (Official Build) (64-bit)
On the other hand Opera does not seem to mind.
It works with Chrome 66, I just tried it.
Open the Security console, you will get more details
Thanks that worked nicely!
Thanks so much for a super clear write up. I spent a lot of hours trying to get this configured correctly and thanks to you it is. Really, really appreciated.
@Mark Alexa, that error, “certutil: function failed: SEC_ERROR_BAD_DATABASE: security library: bad database.” will arise if the database does not yet exist. You can create it first with the following commands:
$ mkdir -p $HOME/.pki/nssdb
$ certutil -N -d $HOME/.pki/nssdb –empty-password
Can I use this without adding an entry in /etc/hosts? I used apache and the procedure worked, but after adding an entry in /etc/hosts mapping my domain to 127.0.0.1
Firefox?
Thank you.
This took me quite some time to find. This is the only thing that works properly as it seems Chrome does not listen to the `update-ca-certificates` command.