The other day I blogged about using LetsEncrypt with FreeNAS. There were another two things around the house that I wanted to have proper SSL certificates on: my Plex server and the Unifi Controller. The latter looks like far too much effort to go through, but I did get it up and running for Plex pretty quickly this morning. Since I also used the same CloudFlare-based API updates for DNS, this one goes through a bit more detail than the previous post simply because I had to go through it again and could capture the steps along the way.
One thing to keep in mind is that my Plex server runs in an iocage jail on FreeNAS so if you’re running Plex on Linux it will look a bit different since this is FreeBSD-based. One notable thing is that md5sum, which I needed to use, is apparently not something that FreeBSD provides by default (who knew?) so you’ll need to pkg install coreutils
and use gmd5sum if you happen to be using FreeBSD (on most Linux distros you simply get md5sum as part of the base install).
First step is to install the acme.sh client that will obtain the LetsEncrypt certificates. We’ll checkout from git since I prefer to see shellscripts before I run them, particularly when doing so as root.
# cd /root
# git clone https://github.com/Neilpang/acme.sh.git
# cd acme.sh
# ./acme.sh --install
You now want to exit the shell or reload the environment to get the new environment that the installer setup. At this point you’ll also want to get your CloudFlare API key. Below we’ll assume the hostname for the Plex server is “plex.hostname.com”. Once you’ve reloaded your environment (logout then login works):
# export CF_KEY="[API key from CloudFlare]"
# export CF_Email="[CloudFlare login email address]"
# cd /root/.acme.sh
# ./acme.sh --issue --dns dns_cf -d plex.hostname.com
This will take a little over two minutes to run. Once it has completed, if it is successful, your certificates will be in /root/.acme.sh/plex.hostname.com/
. Also note that these commands are not run in the git repo we checked out; you can remove that repo if you want to, you won’t use it again unless you want to keep the acme.sh script up to date. The directory to run the script is /root/.acme.sh
(note the initial dot in the directory name).
The next step is to create a PKCS #12 certificate file, which is an archive file format used to store the server certificate, private key, and any intermediate certificates in a single encrypted binary file. These files often have a p12 or or pfx extension, however Plex seems to like pkfx for the extension. We will need to use openssl to combine the files that acme.sh provided for us into one for Plex to use. Since it is encrypted, we need to provide it with a passphrase, which we will tell Plex about later. In this example, the passphrase is “foo”.
# openssl pkcs12 -export -out plex-certificate.pkfx \
-inkey plex.hostname.com.key \
-in plex.hostname.com.cer \
-certfile fullchain.cer \
-passout pass:foo
This will create a plex-certificate.pkfx
file in the current directory. I moved this file to /usr/local/etc/
although you can put it anywhere that the Plex server will be able to get at. Next, go to the Plex web UI and navigate to Settings -> Server -> Network and then click Show Advanced. You will be able to enter the following values as per our example above:
- Custom certificate location: /usr/local/etc/plex-certificate.pkfx
- Custom certificate encryption key: foo (the password)
- Custom certificate domain: https://plex.hostname.com:32400
I would also suggest keeping Secure connections to Preferred, at least for now, to ensure you don’t get locked out if something goes wrong.
At this point, you should be able to navigate to your Plex web UI using HTTPS rather than HTTP. You shouldn’t have to restart the Plex server. If all works well and you get no errors or insecure warnings in your web browser, we can then turn to automating certificate renewals.
The acme.sh install put an entry into cron which runs daily:
16 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
We want to change this because we have to create the PKCS #12 file out of the acme.sh output. We’ll create a wrapper that will run the above command and if we find any changes, will create the needed certificate file, put it in place, and restart the Plex server. Because we’re using CloudFlare and doing updates via the API key (which acme.sh dutifully stored for us as part of the configuration information for this host), this will be a very simple script to write.
You can call the script whatever you like and put it wherever you like, I created /root/update-plex-cert.sh
with the following contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/sh HOST="plex.hostname.com" ACMEHOME=/root/.acme.sh CERTDIR=${ACMEHOME}/${HOST}/ CERTPASS="foo" DESTDIR="/usr/local/etc/" PKFXFILE="plex-certificate.pkfx" TMPFILE=$(mktemp) gmd5sum ${CERTDIR}/${HOST}.cer >${TMPFILE} ${ACMEHOME}/acme.sh --cron --home ${ACMEHOME} gmd5sum -c ${TMPFILE} if [ "$?" == "0" ]; then # nothing has changed rm -f ${TMPFILE} exit 0 fi openssl pkcs12 -export -out ${DESTDIR}/${PKFXFILE} \ -inkey ${CERTDIR}/${HOST}.key \ -in ${CERTDIR}/${HOST}.cer \ -certfile ${CERTDIR}/fullchain.cer \ -passout pass:${CERTPASS} chmod 644 ${DESTDIR}/${PKFXFILE} rm -f ${TMPFILE} service plexmediaserver_plexpass restart |
Once the script is saved, make it executable and then edit the crontab entry to point to the new script. You may need to tweak a few things based on your operating system (using FreeBSD it uses gmd5sum
but on Linux you’d use md5sum
; also the service likely needs to be changed depending on the Plex media server’s service name).
# chmod 700 /root/update-plex-cert.sh
# crontab -e
# crontab -l
16 0 * * * /root/update-plex-cert.sh > /dev/null
That’s it! You can give it a try to see how it would work by modifying the script to force the update by using:
${ACMEHOME}/acme.sh --cron --force --home ${ACMEHOME}
and running the script (using sh -x /root/update-plex-cert.sh
is a great way to see what it is doing). You should see it obtain a new certificate and everything that follows. Re-start your browser and connect to the Plex web UI, examine the certificate details and you should see a later date than the first time you did it. If that works, be sure to remove --force
or you’ll be updating the certificate every day.
All told, this is pretty straightforward and hopefully helpful to someone out there (including future-me).