Use Plex Media Server with a Let's Encrypt Certificate
You can use a free Let’s Encrypt certificate for your self-hosted Plex Media Server VM. With Certbot and a simple Bash script, this will provide a secure connection without certificate warnings. It will also auto-renew certificates. I’m using Debian Bullseye, but this will work on any Linux distribution.
Motivation
There are two possible options how to secure the connection to your Plex server when exposing it to the public Internet:
- Use a reverse proxy like HAProxy or nginx that forwards the traffic and performs SSL offloading.
- Use Plex’s remote access feature and forward the port on your firewall directly to your Plex server.
Generally I would prefer the reverse proxy since I can use my existing reverse proxy which already has a valid Let’s Encrypt certificate. Also, I have more control on how the server is exposed to the public Internet. Unfortunately, a few Plex features like the Sonos integration and the mobile Plex apps are not working with this setup since they need direct access. So I chose the remote access (reverse proxy will work fine if those features are not important for you). The following guide will explain how to use a valid Let’s Encrypt certificate with Plex remote access.
Setup
First, install Certbot. The EFF provides installation guides for multiple operating systems. For Debian the official recommendation is using Snap:
sudo apt update
sudo apt install snapd
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
HTTP or DNS Let’s Encrypt Challenge
Verification of the domain can either be done via an HTTP challenge or a DNS challenge. I choose a DNS challenge because it doesn’t require opening port 80 to the public Internet. In the following, I use a DNS challenge using Cloudflare. The rest of this guide works the same, even when you choose to use a different type of challenge or a different DNS provider.
Install the DNS Cloudflare plugin:
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare
Create the file ~/.secrets/certbot/cloudflare.ini
with the API token you created in your Cloudflare account:
dns_cloudflare_api_token = SECRET_TOKEN
PKCS #12 Certificate
Certbot generates a private key file, a certificate file, and the CA file. By default, these files get created in
/etc/letsencrypt/live/plex.example.com/
. Plex however, expects a PKCS #12 certificate file that bundles all of these
together. I created a script that is triggered by Certbot’s renewal hook, which will convert the Certbot output into a
PKCS #12 certificate file that is compatible with Plex.
In the following, I’m using plex.example.com
as a domain, replace this with your own domain name. Also replace
PASSWORD
with a random password of your choice.
Create the /etc/letsencrypt/renewal-hooks/post/create_p12_file.sh
file with the following content:
#!/bin/sh
openssl pkcs12 -export \
-out /var/lib/plexmediaserver/plex_certificate.p12 \
-in /etc/letsencrypt/live/plex.example.com/cert.pem \
-inkey /etc/letsencrypt/live/plex.example.com/privkey.pem \
-certfile /etc/letsencrypt/live/plex.example.com/chain.pem \
-passout pass:PASSWORD \
-certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA256
chmod 755 /var/lib/plexmediaserver/plex_certificate.p12
The chmod
command is necessary because this Bash script will be executed as root and the Plex user has to be able to
access the file. After the creation of the script file, use sudo chmod +x /etc/letsencrypt/renewal-hooks/post/create_p12_file.sh
to make it executable.
Now you can initialize Certbot and obtain the first Let’s Encrypt certificate:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
-m [email protected] \
-d plex.example.com
Every time the certificate is close to experiation, Certbot should renew the certificate and regenerate the
/var/lib/plexmediaserver/plex_certificate.p12
file using the renewal hook. To achieve this, install a cronjob using
this command (see Certbot automated renewals
for details):
SLEEPTIME=$(awk 'BEGIN{srand(); print int(rand()*(3600+1))}'); echo "0 0,12 * * * root sleep $SLEEPTIME && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
For testing, you can use sudo certbot renew --force-renewal
to force a renewal and trigger the post renewal hook.
Use the Let’s Encrypt Certificate in Plex
Go to the “Network” tab of the Plex settings. Set the following configuration (replace PASSWORD
and plex.example.com
):
- Secure connections: Required
- Custom certificate location:
/var/lib/plexmediaserver/plex_certificate.p12
- Custom certificate encryption key:
PASSWORD
- Custom certificate domain:
plex.example.com
- Enable Strict TLS configuration
- Custom server access URLs:
https://plex.example.com:32400
DNS Resolution and Port Fowarding
The last step is to set up DNS resolution and port forwarding. I’m not going into great detail here because it depends on both your DNS provider and your firewall.
In summary, ensure that your domain plex.example.com
resolves to your public IP and forward port 32400 on the public
IP to port 32400 of the Plex VM. In case you use pfSense you have to
add a firewall rule on the WAN interface.
Make sure you are familiar with the security risks of opening a public port before configuring anything on your firewall.
Last Steps
Go to the “Remote Access” tab of the Plex settings and enable remote access. If you see the message
Fully accessible outside your network
your setup is working!
Update (April 20, 2023): OpenSSL 3.0
With Plex 1.32.0.6865, OpenSSL was updated to 3.0 which requires different encryption algorithms to be used. If the
create_p12_file.sh
script does not explicitly use stricter encryption algorithms, the Plex server will use the
default .plex.direct
certificate instead of the custom certificate. This will result in a browser security warning
and the following Plex server log lines:
ERROR - [CERT] PKCS12_parse failed: error:digital envelope routines::unsupported
ERROR - [CERT] Found a user-provided certificate, but couldn't install it.
Based on the article in https://forums.plex.tv/t/linux-tips/276247/25, it can be fixed by adding
-certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA256
to the openssl pkcs12
command – I updated the post above
accordingly.