DO encrypt
This is a reminder for myself, on how I setup an Let's Encrypt SSL/TLS certificate on a macOS server test machine. Because we are in 2017, and I got tired of getting web browser warnings due to use of self-signed certificates.
I considered which Let's Encrypt client to use on my machine : certbot, the currently recommended client, or dehydrated, the formerly recommended one ?
I was tempted by dehydrated because :
- it's lighter;
- it has supported the dns-01 challenge for a longer time, with support for automatic renewal through AnalogJ/lexicon and this hook script;
- this could be handy for intranet setups which aren't accessible from the internet;
- Gandi is the DNS provider I use, and it has an API which supports this well.
Certbot also supports these kinds of setups, but automatic renewal seems less mature for the moment.
Being lazy, I chose certbot as it seemed easier to setup, and hopes it will continue to mature.
Installation of certbot
Quite easy, since I already had Homebrew installed.
brew update
brew install certbot
Setting up a certificate
I tested first:
sudo certbot certonly --webroot -w /Library/Server/Web/Data/Sites/Default -d test.example.com --test-cert
Once this seemed OK, I generated a real certificate:
sudo certbot certonly --webroot -w /Library/Server/Web/Data/Sites/Default -d test.example.com
Then, I converted the certificate for macOS:
sudo openssl pkcs12 -export -inkey /etc/letsencrypt/live/test.example.com/privkey.pem -in /etc/letsencrypt/live/test.example.com/cert.pem -certfile /etc/letsencrypt/live/test.example.com/fullchain.pem -out /etc/letsencrypt/live/test.example.com/letsencrypt_sslcert.p12 -passout pass:topsecret
and imported the certificate into macOS keychain :
sudo security import /etc/letsencrypt/live/test.example.com/letsencrypt_sslcert.p12 -f pkcs12 -k /Library/Keychains/System.keychain -P topsecret -T /Applications/Server.app/Contents/ServerRoot/System/Library/CoreServices/ServerManagerDaemon.bundle/Contents/MacOS/servermgrd
Afterwards, I launch Server.app, went to the Certificates section, and selected the new certificate.
Autorenewal
Afterward, I thought I could trust Cyril Picard's script found at https://gist.github.com/cyrilpic/4504527de3a7b08ed84e :
This script can be used two ways :
- getting a new certificate :
sudo certbot4osx new test.example.com /Library/Server/Web/Data/Sites/Default
- renewing a certificate :
sudo certbot4osx renew
To automate the renewal process, I setup a launch daemon. Here is the content of the /Library/LaunchDaemons/com.github.cyrilpic.certbot4osx.plist
file I got.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<false/>
<key>Label</key>
<string>com.github.cyrilpic.certbot4osx</string>
<key>ProcessType</key>
<string>Background</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Server.app/Contents/ServerRoot/usr/bin:/Applications/Server.app/Contents/ServerRoot/usr/sbin</string>
</dict>
<key>Program</key>
<string>/usr/local/bin/certbot4osx</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/certbot4osx</string>
<string>renew</string>
</array>
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>20</integer>
<key>Minute</key>
<integer>37</integer>
</dict>
<dict>
<key>Hour</key>
<integer>6</integer>
<key>Minute</key>
<integer>48</integer>
</dict>
</array>
</dict>
</plist>
For security reason, the involved files (the .plist and certbot4osx) must be set with owner root
, group owner wheel
, and mod 755.
The daemon must be launched for the first time this way :
sudo launchctl load -w /Library/LaunchDaemons/com.github.cyrilpic.certbot4osx.plist
and one can ensure that the result is OK by peeking certbot's log :
sudo cat /var/log/letsencrypt/letsencrypt.log
If the daemon has problem launching, adding entries like these ones in the .plist can help understanding the issue :
<key>StandardErrorPath</key>
<string>/tmp/com.github.cyrilpic.certbot4osx.stderr</string>
<key>StandardOutPath</key>
<string>/tmp/com.github.cyrilpic.certbot4osx.stdout</string>