Cory Aitchison
Sep 6 · 6 min read

0. Prerequisites

  1. Fully patched version of OS X®(1)
  2. Homebrew


(1) OS X is a registered trademark of Apple Inc.


1. Install and configure example.com to run locally

The domain example.com is reserved for testing and documentation. As such, it is a great domain to set up to run locally. There is a site hosted at example.com and by following these steps, you won’t be able to access it without reverting back.

For this article I’ve chosen to use the popular webserver Nginx™(2). You can use any http server, but the configuration will vary.

$ brew install nginx
$ cat /usr/local/etc/nginx/nginx.conf # Notice the line “include servers/*”
$ brew services start nginx
$ curl http://localhost:8080

By running the curl command above, you can see that you have Nginx running and serving content. If this is your first time running a webserver, I caution you to not get drunk with power at this point. There are a couple more steps before you can truly bask in the glow of your own awesomeness(3).

As our goal is to server the site example.com from our instance of Nginx, we’ll now configure our host to do just that. As an aside, the technique I use to do this is based, in no small part, on personal preference. Once you have things set up and understand what is going on, you should play with, and tweak this process.

We need to make some directories to hold webpages, certificates, and logs. We also need to add some configuration to Nginx and add our new shiny domain to /etc/hosts. Below are the commands I use to do so.

$ sudo mkdir /usr/local/sites
$ sudo chown <your username> /usr/local/sites
$ sudo chgrp <your group> /usr/local/sites
$ cd /usr/local/sites
$ mkdir example.com
$ cd example.com
$ mkdir www log certs
$ vi /usr/local/etc/nginx/servers/example.com #add the following lines
server {
listen 80;
server_name example.com *.example.com;
root /usr/local/sites/example.com/www;
error_log /usr/local/sites/example.com/log/error_log;
}
$ nginx # or nginx -s reload if nginx is already running

$ sudo vi /etc/hosts # Add the following
127.0.0.1 example.com

The last step is creating a webpage, so you see something when you curl example.com. Obviously, you want to put something cool in there as we’re going to look at it a few times. My personal favorite is “Boom goes the dynamite!”(4)

After you’ve created your test webpage you can execute the following command and see that everything is working.

Congratulations, you now have a webserver running and serving content from your computer. Remember the warning above: Don’t get too drunk with power yet.


(2) Nginx is a trademark of Nginx Software Inc.
(3) Be aware that the author has an unusual sense of humor.
(4) The author’s life was changed forever when he came across this video featuring Jeremy Goldman:
https://youtu.be/W45DRy7M1no


2. Setting up SSL

NOTE: Before we setup SSL and all this power goes to your head, a warning: We’re about to delve into the fast-moving world of security. While we won’t get into specifics, it is important that you understand that the examples below, while reasonable at the time this post was published, certainly will not be secure forever. Please don’t use this configuration in production and assume you have a secure instance running.

Now that we have a webserver running, let’s setup SSL(5). The first thing to do is setup a Certificate Authority (CA). To do this we’ll take the following steps:

  1. Create a cryptographic key
  2. Create a CA configuration
  3. Create a CA
  4. Add our CA to the keychain in OSX

$ openssl genrsa -des3 -out rootCA.key.orig 2048 # 1. create a key
$ openssl rsa -in rootCA.key.orig -out rootCA.key # remove the passphrase
$ vi rootCA.conf # 2. Add the following to create our root CA config
[req]
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
C = <Two letter country code>
ST = <Full name of your state/province>
L = <Full name of your city/town/locality/etc.>
O = <Your organization name>
OU = My Root CA
$ openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt -config rootCA.conf # 3. create the CA
$ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain rootCA.crt # 4. add the CA to keychain

By following these steps, you have created a CA, installed that CA into the OS X keychain, and trusted the CA. Thus, any certificates you create with this CA will automatically be trusted saving you time and frustration later on!

As mentioned above, you can now create your own trusted certificates. Again, there are a few steps needed to do this:

  1. Generate a server key
  2. Create a Certificate Signing Request (CSR)
  3. Create a server Certificate (cert)
  4. Install your cert
  5. Configure Nginx to use your cert

$ openssl genrsa -out example.com.key 2048 # 1. create a key
$ cp /etc/ssl/openssl.cnf example.com.conf # 2. Create CSR
$ echo “[SAN]” >> example.com.conf
$ echo “subjectAltName=DNS:example.com,DNS:*.example.com” >> example.com.conf
$ openssl req -new -sha256 -key example.com.key -subj “/C=US/ST=UT/O=Adobe/CN=example.com” -reqexts SAN -config example.com.conf -out example.com.csr
$ openssl x509 -req -sha256 -in example.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out example.com.crt -days 1000 -extfile example.com.conf -extensions SAN # 3. Create your cert
$ cp example.com.key example.com.crt /usr/local/sites/example.com/certs/ # 4. Install your cert
$ vi /usr/local/etc/nginx/servers/example.com # 5. Configure Nginx by adding the following to server object in the conf file
listen 443 ssl;
ssl_certificate /usr/local/sites/example.com/certs/example.com.crt;
ssl_certificate_key /usr/local/sites/example.com/certs/example.com.key;
ssl_protocols TLSv1.2;
ssl_ciphers ‘ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256’;
ssl_prefer_server_ciphers on;
$ nginx -s reload # restart nginx
$ curl https://example.com

There you have it, an instance of Nginx that serves content over SSL, all running from your local computer. The best part about this is, you don’t ever have to manage your certs again. All you need do is use your CSR to generate them and they are automatically trusted, no more browser warnings(6).


(5) SSL is a wonderful invention that makes the internet useful for many interesting tasks. It is also a little complicated. The author encourages you to read more about SSL to fully understand what is going on here, but it is beyond the scope of this article to provide more than the required steps.
(6) It is difficult to describe the feelings of joy the author felt when he finally figured this out. Let’s just say, the sun felt warmer, the air smelled sweeter, and there was an almost overwhelming sense of wellbeing.


3. Setting up wildcard domains

Remember way back at the beginning of this article when we added example.com to /etc/hosts? That is the fastest, easiest way to get a simple domain working, but, what about www.example.com, or happy.go.lucky.example.com? Adding an entry to /etc/hosts only works for the domain as exactly written. If you want to configure subdomains, you have to manually add every subdomain you want to use. Trouble is, I rarely know what subdomains I want in advance(7).

This is the last piece of the puzzle to get fully functioning domains on your computer, and as luck would have it, this step is much simpler than the SSL step(8). The steps are:

  1. Install dnsmasq
  2. Add configuration for our domain
  3. Teach the OS X DNS resolver about our domain

$ brew install dnsmasq # 1. Install dnsmasq
$ vi /usr/local/etc/dnsmasq.conf # uncomment the following line
conf-dir=/usr/local/etc/dnsmasq.d/,*.conf
$ echo address=/example.com/127.0.0.1 > /usr/local/etc/dnsmasq.d/example.com.conf # 2. Add configuration for our domain
$ sudo brew services start dnsmasq $ sudo mkdir -p /etc/resolver # 3. Teach OS X about our domain
$ echo nameserver 127.0.0.1 | sudo tee /etc/resolver/example.com
$ curl example.com
$ curl https://example.com
$ curl https://www.example.com
$ curl https://boom-goes-the-dynamite.example.com

(7) The author barely knows what he wants in advance, like ever. It’s true, ask his family.
(8) You may ask: If it is so much easier, why didn’t you do this step before SSL. Answer is the author is presenting this information in the order in which it was discovered by the author.

Conclusion

There you have it folks, three “easy” steps to getting subdomain-supported SSL enabled and running on your local computer. Once you have this working, there are any number of possibilities. I use this system to front Docker containers running on my laptop all the time by setting up Nginx to forward various URLs to said containers.

I’ve published some scripts at https://github.com/cory-work/local_site_tools that automate a lot of this work. Once you’ve gone through this exercise, you can use them to bring up and tear down local domains with one easy command.

I hope this was useful, if you find errors or have suggestions, please feel free to let me know.

Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Cory Aitchison

Written by

I’ve been a software engineer with Adobe for 12 years and consider Adobe to be the best company ever. That said, opinions expressed are my own.

Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade