Skip to content

Instantly share code, notes, and snippets.

@sftsk
Last active June 17, 2022 12:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sftsk/25643abf5fa06d88419a5a6a5f0ce5f7 to your computer and use it in GitHub Desktop.
Save sftsk/25643abf5fa06d88419a5a6a5f0ce5f7 to your computer and use it in GitHub Desktop.
Let's Encrypt macOS Server

Taken from https://community.letsencrypt.org/t/complete-guide-to-install-ssl-certificate-on-your-os-x-server-hosted-website/15005?source_topic_id=33254&source_topic_id=40061

Introduction

If like me you are, among other many tasks, a system administrator of a website hosted on OS X server, chances are your are not fully comfortable with what to do precisely in order to get your website running with a valid SSL certificate. After some struggle, I would like to share my experience on the installation of let’s encrypt certificate.

The target audience of this article is people with a minimum IT skills (I assume you know how to open the terminal and some basic knowledge of shell commands), already having a configured and running website hosted on OS X and managed with the Server App. Also this article assumes you will generate the certificate on the machine hosting the server itself.

Note: The following procedure was successfully installed on two similar server, both are Mac mini running on OS X Mavericks (10.9.5) with the Server app installed, configured and running. Also I have done several installation on those servers (they are not freshly packed out of the box), which means that you may need to install other piece of software in the first step in order to make it work.

This article extend the following articles: Mac OSX (Server): import LE certificate?156 and Installing and Configuring LetsEncrypt on a Mac OS X Client Server

Overview

So, here is the plan:

install let’s encrypt client ; (test and) generate the certificates ; import the certificate into OS X’s KeyChain ; configure your website in order to make it work with https ; (test and) automate the renewal. enjoy…

Step 1 Install let’s Encrypt client

The first step is to instal Homebrew. Here is the official documentations on how to install homebrew http://brew.sh/. Basically you just have to launch

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" then

brew doctor and

brew update Once Homebrew is installed you can install Let’s Encrypt Client. The “client” is a terminal command tool that allow you to retrieve the certificates. Do not expect a nice and sleek UI, it will be command line. But it is quite simple to use and is perfect for automation. So here is the command line in order to retrieve the source code for the client:

brew install certbot

First locate your website directory (the web root). If you didn’t change anything it should be under /Library/Server/Web/Data/Default. There, you must create the folders .well-known and acme-challenge inside .well-known. In order to do so launch :

mkdir PATH_TO_WEB_FOLDER/.well-known and

mkdir PATH_TO_WEB_FOLDER/.well-known/acme-challenge You should test that with a test file (echo "Success" > PATH_TO_WEB_FOLDER/.well-known/acme-challenge/test.html) and check if you can access it with your browser “http://example.com/.well-known/acme-challenge/test.html”.

When you are sure this folder is accessible, you can start with the actual certificate generation.

It is not mandatory but I suggest you create a folder containing two scripts, one config file and logs (I tried to use the standard logs but for access issue I gave up). To do so you have to do :

mkdir ~/letsencrypt/my_script
mkdir ~/letsencrypt/my_script/logs

Then create the following files:

cert.ini

# Use a 4096 bit RSA key instead of 2048
rsa-key-size = 4096 
# Register with the specified e-mail address
email = YOUR_EMAIL
# Generate certificates for the specified domains.
domains = LIST_OF_DOMAINS_AND_SUBDOMAINS
# Uncomment to use a text interface instead of ncurses
# text = True
# To use the webroot authenticator.
authenticator = webroot
webroot-path = WEB_ROOT_FOLDER

Of course you have to change YOUR_EMAIL with your actual email address, LIST_OF_DOMAINS_AND_SUBDOMAINS with the list of domains ex:(example.com, www.example.com, example.org, www.example.org) and WEB_ROOT_FOLDER with the folder of your web page, where you created the .well-known folder

get_cert.sh

#!/bin/sh

DOMAIN_DEFAUT= YOUR_DOMAIN
PEM_FOLDER="/etc/letsencrypt/live/${DOMAIN_DEFAUT}/" 
LOG_FOLDER="/Users/YOUR_USER/letsencrypt/my_script/logs" 
DATE=$(date +"%d-%m-%y")
LOG_FILE="${LOG_FOLDER}/${DATE}.log"

# Retrieve certificate - DELETE --dry-run AFTER THE TEST RUN WORKED
sudo certbot certonly -c cert.ini --dry-run

# Check that everything went fine
LE_STATUS=$?

if [ "$LE_STATUS" != 0 ]; then
    echo Automated Get certificate failed:
    cat $LOG_FILE
    exit 1
fi
 
# Generate a passphrase - UNCOMMENT THE NEXT LINE AFTER THE TEST RUN WORKED
#PASS=$(openssl rand -base64 45 | tr -d /=+ | cut -c -30)

# Transform the pem files into a OS X Valid p12 file - UNCOMMENT THE NEXT LINE AFTER THE TEST RUN WORKED
#sudo openssl pkcs12 -export -inkey "${PEM_FOLDER}privkey.pem" -in "${PEM_FOLDER}cert.pem" -certfile "${PEM_FOLDER}fullchain.pem" -out "${PEM_FOLDER}letsencrypt_sslcert.p12" -passout pass:$PASS

# import the p12 file in keychain - UNCOMMENT THE NEXT LINE AFTER THE TEST RUN WORKED
#sudo security import "${PEM_FOLDER}letsencrypt_sslcert.p12" -f pkcs12 -k /Library/Keychains/System.keychain -P $PASS -T /Applications/Server.app/Contents/ServerRoot/System/Library/CoreServices/ServerManagerDaemon.bundle/Contents/MacOS/servermgrd
Again, here you have to change YOUR_DOMAIN with the first domain name you entered (in our previous example it would be example.com). You also have to change YOUR_USER twice with your current user.
You may have noted that we are using the webroot method, which will automatically place a temporary file in the .well-knwon/acme-challenge folder to check that the website you declare is yours indeed. You could do that manually by omitting the -webroot flag, but it is problematic later for the automatic renewal.

Now, is time to try it. Don’t worry we will be using a test environement, so you won’t reach the 5-7 certificate a day authorized by Let’s Encrypt. Simply launch:

~/letsencrypt/my_script/get_cert.sh If everything went well (or after fixing the issue the script arose) you can remove, in the get_cert.sh script, the --dry-run flag and the commented line after “UNCOMMENT THE NEXT LINE AFTER THE TEST RUN WORKED”

Launch again the script:

~/letsencrypt/my_script/get_cert.sh This time it should have done several things: created under /etc/lets-encrypt/live/YOURSITE/ 3 .pem files, generate a .p12 file and add in the Keychain and Server app your certificate.

To check that everything went fine open the Server app and under “Certificates” you should see your shiny brand new certificate. Screen Shot 2016-04-27 at 2.10.38 PM.png1069x733 119 KB If it is not the case, check in Keychain that you have two new entries under “System” and “Certificates”, one for your domain and one for “Let’s Encrypt Authority X3”.

If that is still not the case check that the .pem and .p12 files were generated. do the following commands:

sudo ls /etc/letsencrypt/live/ You should see your domain. Then do

sudo ls /etc/letsencrypt/live/YOUR_DOMAIN You should see 5 files:

cert.pem
fullchain.pem
privkey.pem
chain.pem
letsencrypt_sslcert.p12

if letsencrypt_sslcert.p12 is not there then you probably didn’t provide the right domain in the ~/letsencrypt/my_script/get_cert.sh file. If the .pem files are not there then you didn’t receive from let’s encrypt the certificate. Now is a good time to have a look at the log file created under ~/letsencrypt/my_script/logs.

Step 3 configure your website

Now you should have a working certificate in the server app. The next thing to do is to bind this certificate to sour web site. Go to Server app under Sites. If you use the default configuration (“Server Website”), you simply have to report your setting from “Server Website” to “Server Webstie (SSL)”. If you have another site, I suggest you to duplicate it (I mean create a new one and report the setting of the original), set the port to 443 and choose your certificate.

Now you should be able to access your website with https://example.com and see a lock next to the URL 😄 But it is by far not finished. You have to consider the following:

Are all your subdomains included? Are all the internal link in your website made without the explicit http:// Are all images referred without the explicit http:// (could be the reason why you don’t have the green lock next to the URL) Do you want to make a full redirection from http://example.com to https://example.com or are simply some parts? Unfortunately I cannot help you there…

Step 4 (test and) automate the renewal

The renewal script is almost the same as the get_cert.sh script. Therefore I propose you to duplicate get_cert.sh:

cp ~/letsencrypt/my_script/get_cert.sh ~/letsencrypt/my_script/renew.sh simply change in renew.sh the line

sudo certbot certonly -c cert.ini by

sudo certbot renew --manual-public-ip-logging-ok --agree-tos --force-renew > $LOG_FILE 2>&1 To test the renewal launch

~/letsencrypt/my_script/renew.sh The expiration date & time of your certificates should have changed.

For production remove the --force-renew flag! In order to automate it you can add this script in the cron. To do so launch:

crontab -e  
add the line

0 0 * * * /Users/YOUR_USER/letsencrypt/my_script/renew.sh

This would make the script run every midnight and check if the renewal date is close, then renew it.

Step 5 Enjoy…

Congratulation! You now deserve a beer or any drink you fancy!

@dsgrnt
Copy link

dsgrnt commented Jul 15, 2018

This is excellent, thank you! One comment, you might consider showing hot to make the crontab job execute at a random time.

crontab -e  

add the line

0 0 * * *  sleep $[ ( $RANDOM % 60 )  + 1 ]s && /Users/YOUR_USER/letsencrypt/my_script/renew.sh

I don't know if this works for everyone, but seems to be working for me. Thanks again!

@jlg89
Copy link

jlg89 commented Apr 4, 2022

What this DOESN'T do is update the website configuration to make it use the updated certificate. You end up with two versions of the SSL cert in Server Admin: the expiring one, that the website is using, and the new one, that isn't tied to anything. Is there a way to automate the process of assigning the updated cert to the website's SSL configuration?

@aleczdr
Copy link

aleczdr commented Jun 17, 2022

What this DOESN'T do is update the website configuration to make it use the updated certificate. You end up with two versions of the SSL cert in Server Admin: the expiring one, that the website is using, and the new one, that isn't tied to anything. Is there a way to automate the process of assigning the updated cert to the website's SSL configuration?

If you renew the certificate within a couple of days of the previous one's expiry date, it should automatically switch to the new one. I set mine to renew 3 days before, and have had no issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment