Set up a Self Signed Certificate on macOS's Built in Apache

Update 2019-01-29: A much simpler method using a tool called mkcert has come along and I have an updated walkthrough you may want to use instead. I would recommend the mkcert method unless you have a reason you explicitly need a self signed certificate.

I recently purchased a .app domain for a side project; .app domains are interesting as they require SSL at all times.

I like to set up my dev environments as subdomains of my actual domain, such as local.donatstudios.com. It makes working with CORS and cookies a lot simpler for applications with APIs on subdomains.

Doing this with .app however means having to get SSL working. I found a number of tutorials of varying quality online, but none of them did the full process from start to finish, particularly solving problems with Chrome 58.

This tutorial assumes you are using the built in version of Apache that comes with macOS, however you should be able to adjust paths for brew or otherwise installed versions.

Creating the Certificates

First off we'll make place to do our work. We need to do this outside of sudo requiring areas due to some bugs with the Apple version of openssl.

$ mkdir /tmp/crt && cd /tmp/crt

Next we will generate your key and certificate. Replace all four local.example.com entries with your full intended development subdomain.

The subjectAltName=DNS piece of this is required to get Chrome versions greater than 58 working.

$ openssl req -newkey rsa:2048 -x509 -nodes \
-keyout local.example.com.key \
-new \
-out local.example.com.crt \
-subj /CN=local.example.com \
-reqexts SAN \
-extensions SAN \
-config <(cat /System/Library/OpenSSL/openssl.cnf \
<(printf '[SAN]\nsubjectAltName=DNS:local.example.com')) \
-sha256 \
-days 3650

Apache requires a nopass key, so to generate this we do the following, again adjusting paths as nessessary:

$ sudo openssl rsa -in local.example.com.key -out local.example.com.nopass.key

Now that we have completed the key generation, we can move our certificates into the apache /etc directory:

$ sudo mkdir /etc/apache2/ssl
$ sudo mv *.key *.crt /etc/apache2/ssl

Apache Configuration

In your favorite editor open /etc/apache2/httpd.conf

Uncomment the following lines (line numbers may vary):

Near line 89:

LoadModule socache_shmcb_module libexec/apache2/mod_socache_shmcb.so

Near line 144:

LoadModule ssl_module libexec/apache2/mod_ssl.so

Near line 528:

Include /private/etc/apache2/extra/httpd-ssl.conf

Next open /etc/apache2/extra/httpd-ssl.conf, find <VirtualHost _default_:443> around line 121.

Either comment out using a # at the start of each line, or delete every single line between the opening <VirtualHost _default_:443> and the closing </VirtualHost> around line 290.

Presuming your sites VirtualHost is in /etc/apache2/extra/httpd-vhosts.conf either change <VirtualHost *:80> to <VirtualHost *:443>, or duplicate your VirtualHost entry using <VirtualHost *:443> if you'd like your VirtualHost accessible with and without SSL.

Next, inside your sites <VirtualHost *:443> block, append the following, adjusting the filenames accordingly.

SSLEngine on
SSLCertificateFile "/private/etc/apache2/ssl/local.example.com.crt"
SSLCertificateKeyFile "/private/etc/apache2/ssl/local.example.com.nopass.key"

Chrome / Safari Configuration

Next we will open your Apache ssl directory and the "Keychain Access" application:

$ open /etc/apache2/ssl
$ open /Applications/Utilities/Keychain\ Access.app

In the Keychain Access application, select the login Keychain and the Certificates Category.

Then from the open Finder window, drag and drop your .crt file.

Double click, and change the settings for the selected certificate to "Always Trust".

Lastly, repeat the process of dragging and giving access in the System Keychain.

You may need to reboot, but your certificate should now work in Chrome and Safari on your local machine.