IMPORTANT: It's critical to select the correct type of processor your mac is using so the instructions below will be accurate. This is because Homebrew uses
different paths for Apple Silicon and Intel based hardware.
My mac is using an processor.
Part 3: macOS 14.0 Sonoma Web Development Environment
In Part 1 of this 3-part series, we covered configuring Apache on macOS Big Sur 11.0 to work better with your local user account, as well as the installation process for installing multiple versions of PHP. In Part 2, we covered installing MySQL, Virtual Hosts, APC caching, YAML, and Xdebug.
In this Part 3, we will cover getting your site setup with LetsEncrypt SSL support for this setup.
10/20/2023 Updated to reflect macOS 14.0 Sonoma
12/25/2022 Updated to reflect the release of macOS 13.0 Ventura
11/27/2021 Added self-signed section back + vhost configuration
11/13/2021 Updated to reflect the release of macOS 12.0 Monterey + switch from self-signed to LetsEncrypt Certificates
This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.
SSL Introduction & Requirements
In order to get SSL setup and running properly four our Homebrew-powered Apache setup, we need to first create an SSL Certificate. This used to be a pain and cost money for a valid SSL certificate, but thankfully we now have Let's Encrypt, a non-profit Certificate Authority that provides certificates to 225 million websites!
This does require that you have registered a domain name with a company such as Hover, GoDaddy, Network Solutions, etc. You should configure this so that a valid host is available to point to your local webserver. You will probably also need to setup port forwarding so your external IP address is routed internally to your webserver. Usually this consists of setting up a port forward for
HTTPS with ports
443 to the internal IP address of your computer.
This is a process that depends on several factors:
- Domain Registrar used to purchase your domain
- DNS services used which could be the same as the registrar, or another provider such as CloudFlare
- Type of internet connection be it static or dynamic IP address
- The actual external IP address of your internet connection
- Make and model of your router which will need to be setup to configure port forwarding
I'll leave this process up to you as it might require some Googling to get the this process setup depending all the factors listed above. A quick way to test if you have things setup is to try reaching host via your phone or some other device that is not on your internal network.
Let's assume you have registered the domain
grav.rocks (p.s. I already own this one, you need to use your own!), and you have configured the host
dev.grav.rocks to be port-forwarded to your local development machine. You have tested this and you can confirm that when you browse to
http://dev.grav.rocks on your phone, you are indeed seeing the webserver of your internal network. You have successfully configured remote access, but now you want to get SSL working.
Throughout this guide I use
dev.grav.rocks as an example host. You will need to replace this with your own hostname
Let's Encrypt + Certbot
Now you have a valid host that is accessible from the internet, we need to generate a valid LetsEncrypt SSL certificate. First we should install the
certbot tool that will facilitate this process:
brew services stop httpd brew update brew upgrade brew install certbot
To be able to use
certbot in a non-root setup (like we have with Brew), we need to create a
cli.ini file so that the
certbot command will use local paths rather than
root access-only system paths:
Create a Certbot Config
mkdir -pv ~/.config/letsencrypt code ~/.config/letsencrypt/cli.ini
This assumes you have Visual Studio Code installed and have enabled the CLI
code command. See the first part of this series to find out more about this.
In this new file paste the following:
work-dir = /opt/homebrew/etc/certbot logs-dir = /opt/homebrew/etc/certbot/logs config-dir = /opt/homebrew/etc/certbot/certs
Save the file.
Create the Certificate
Now we can run
certbot without requiring
sudo which would limit our ability to run Apache as a non-root user.
certbot certonly --standalone
This kicks off a process that requires your response in a few places. Enter
email address, agree to Terms of Services, Choose
N to join mailing list. Lastly when prompted, enter the name of the host you want to use, e.g.
Certbot will then try to authenticate by challenging the domain names provided:
Obtaining a new certificate Performing the following challenges: http-01 challenge for dev.grav.rocks Waiting for verification... Cleaning up challenges Non-standard path(s), might not work with crontab installed by your operating system package manager
If successful, certbot will generate a
fullchain.pem and a
privkey.pem file that we can use to configure our SSL certificate in the Apache configuration. The output should look something like this:
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /opt/homebrew/etc/certbot/certs/live/dev.grav.rocks/fullchain.pem Your key file has been saved at: /opt/homebrew/etc/certbot/certs/live/dev.grav.rocks/privkey.pem Your cert will expire on 2021-02-12. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /opt/homebrew/etc/certbot/certs. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by:
The important parts to jot down are the full paths to the
.pem files which we'll use in the following section:
Apache SSL Configuration
The first step is to make some modifications to your
In this file you should uncomment both the
ssl_module, and also the include for the
httpd-ssl.conf by removing the leading
# symbol on those lines:
LoadModule socache_shmcb_module lib/httpd/modules/mod_socache_shmcb.so ... LoadModule ssl_module lib/httpd/modules/mod_ssl.so ... Include /opt/homebrew/etc/httpd/extra/httpd-ssl.conf
Next we need to change the default
8443 port to the more standard
443 and comment out some sample code. So we need to open the SSL config file:
replace it with:
<VirtualHost _default_:8443> # General setup for the virtual host DocumentRoot "/opt/homebrew/var/www" ServerName www.example.com:8443
and replace the
8443 references with
443 and update the
ServerName based on the values you setup in your
<VirtualHost _default_:443> # General setup for the virtual host DocumentRoot "/Users/your_user/Sites" ServerName dev.grav.rocks:443
Next locate the
Server Certificate: section add the location of your
SSLCertificateFile you obtained above:
Lastly, locate the
Server Private Key: section add the location of your
SSLCertificateKeyFile you obtained above:
Save the file at this point. Then all you need to do now is double check your Apache configuration syntax:
If all goes well, restart Apache:
brew services stop httpd brew services start httpd
tail -f /opt/homebrew/var/log/httpd/error_log, the Apache error log while you restart to see if you have any errors.
Now simply point your browser at
https://dev.grav.rocks and you should see the page loading and a comforting message in the browser address bar about how secure your site is.
Maintenance & Renewal
By their nature LetsEncrypt certificates are short-lived that are valid for 90 days only. This means that you need to renew them. The simplest way to accomplish this is to simply run:
certbot renew brew services restart httpd
However, you can only run this when you are close to renewal (within 30 days). The best solution is to automate this process by using a cron-job to run the process weekly. First we need to add an entry to the crontab that will run the renewal script every sunday at 3am::
(crontab -l 2>/dev/null; echo "0 3 * * 0 certbot renew --post-hook 'brew services restart httpd' > /dev/null 2>&1") | crontab -
You can check this looks correct by running:
You should see:
0 3 * * 0 certbot renew --post-hook 'brew services restart httpd' > /dev/null 2>&1
Sometimes there are scenarios where you want to mimic an existing site during development, or you don't have a spare domain name but just need to test under SSL. Either way there are still occasions where a valid SSL certificate is not required, and you just need to get a self-signed SSL certificate in place.
mkcert to serve as our certificate authority (CA), and also
nss to ensure firefox can use certificate authority sever.
brew install mkcert nss
Next we have to install the server and run it (enter your password when prompted):
Let's create a good location for the certificates:
cd /opt/homebrew/etc/httpd mkdir certs && cd certs
Now all we have to do is generate a certificate for any domain we wish to use. For example, you could create one for
or one for
These commands will create
-key.pem files for each domain.
Setting up Apache for Self-Signed SSL certificate
Follow exactly the same steps as the Apache SSL Configuration section above to enable SSL in Apache.
When you get to the part where you set the
SSLCertificateKeyFile use the files we just generated rather than the LetsEncrypt
SSLCertificateFile "/opt/homebrew/etc/httpd/certs/grav-admin.test.pem" SSLCertificateKeyFile "/opt/homebrew/etc/httpd/certs/grav-admin.test-key.pem"
Check the syntax:
Restart the server to have the configuration changes take effect:
brew services restart httpd
SSL in Apache Virtual Hosts
The configuration we've outlined in this article focuses on setting a root-level SSL certificate. You can of course generate multiple unique certificates for various domains and sites. When you do this, you need to enable SSL for a virtual host via editing the
If you already have a vhost entry for
http on port
80 for a particular site, you can just copy this and replace
443 then add the entries for your key and certificate.
Let's assume we have created a self-signed certificate for
grav-admin.test, and we already have a working vhost configuration for
80 that we setup in Part 2 of the guide:
<VirtualHost *:80> DocumentRoot "/Users/your_user/Sites/grav-admin" ServerName grav-admin.test </VirtualHost>
Then we simply copy and paste this and change the port to
443 and add references to turn on SSL and use the generated SSL files:
<VirtualHost *:80> DocumentRoot "/Users/your_user/Sites/grav-admin" ServerName grav-admin.test </VirtualHost> <VirtualHost *:443> DocumentRoot "/Users/your_user/Sites/grav-admin" ServerName grav-admin.test SSLEngine on SSLCertificateFile "/opt/homebrew/etc/httpd/certs/grav-admin.test.pem" SSLCertificateKeyFile "/opt/homebrew/etc/httpd/certs/grav-admin.test-key.pem" </VirtualHost>
Check the syntax:
Restart the server to have the configuration changes take effect:
brew services restart httpd