Step 1: create a self-signed root certificate
First, let’s create a self-signed root certificate:
openssl req -x509 -nodes -new -sha256 -days 390 -newkey rsa:2048 -keyout "RootCA.key" -out "RootCA.pem" -subj "/C=de/CN=localhost.local" openssl x509 -outform pem -in "RootCA.pem" -out "RootCA.crt"
-days 390 sets the number of days, this certificate is valid. Starting on September 1st (2020), SSL/TLS certificates cannot be issued for longer than 13 months (397 days), see https://stackoverflow.com/a/65239775.
If this time is too long, you will receive an
NET::ERR_CERT_VALIDITY_TOO_LONG error. In the command above, this value was set to 390 days, which works for me.
Step 2: define domains and subdomains that should be included in the certificate
For this, just create a text file named
vhosts_domains.ext and insert the following contents:
authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = localhost DNS.2 = *.mixable.blog.local DNS.3 = mixable.blog.local
This example includes subdomains for a local development environment for the domain
mixable.blog.local and all subdomains like
If you plan to use a more general certificate e.g. to include all subdomains under
*.*.blog.local, this will not work. The definition only supports ‘first level’ subdomains. It would be great, because this saves a lot of additional setup, but unfortunately this is note supported.
Step 3: create the certificate
Now let’s create the certificate:
openssl req -new -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/C=de/ST=State/L=City/O=Organization/CN=localhost.local" openssl x509 -req -sha256 -days 1024 -in localhost.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -extfile vhosts_domains.ext -out localhost.crt
Calling the two commands above will create the localhost certificate that includes all the provided domains and subdomains. Your file listing should look like this:
Step 4: make the certificate available for Apache
Depending on your system, copy all those files into the the configuration folder of the Apache installation. In my case, the installation was done with the help of
brew, so the local path is:
At the end, it’s not important where those files are located, because we no add this path to the vhost definitions. For this, open your vhosts file and link the
crt and the
key file as follows:
# mixable.blog.local <VirtualHost *:80> ServerAdmin email@example.com DocumentRoot "/Users/mathias/Sites/mixable.blog.local" ServerName mixable.blog.local ServerAlias mixable.blog.local ErrorLog "/usr/local/var/log/httpd/localhost-error.log" CustomLog "/usr/local/var/log/httpd/localhost-access.log" common </VirtualHost> <VirtualHost *:443> DocumentRoot "/Users/mathias/Sites/mixable.blog.local" ServerName mixable.blog.local SSLEngine on SSLCertificateFile "/usr/local/etc/httpd/cert/localhost.crt" SSLCertificateKeyFile "/usr/local/etc/httpd/cert/localhost.key" </VirtualHost>
If you have additional vhost definitions, you can add the
<VirtualHost *:443> part to every server name entry and use the correct paths to
After changing the vhost settings, it is required to restart your Apache server!
Step 5: add the certificates to macOS
When opening a local website, the certificate should be used but you might see a
NET::ERR_CERT_INVALID error. This is the case, because modern browsers/systems do not trust self-signed certificates by default. to overcome this issue, we have to add the created certificates to the macOS Keychain Access. For this, open the
*.crt files in Keychain Access:
So that they are know by macOS:
And finally, update the trust settings of each certificate to “Always trust”:
You should now be able to use a secure connection between your browser and your local server:
Step 6: additional fixes
The steps above might already work for Chrome and Safari. If you have problems with Firefox, just open settings and go to Privacy & Security. Then you have to import the root certificate file
RootCA.crt, so that Firefox knows about your certificate.