-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9722033
commit e9b762d
Showing
1 changed file
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
--- | ||
title: "Let's Encrypt and Emby" | ||
date: "Fri Sep 13 15:14:54 -0400 2024" | ||
category: dev | ||
--- | ||
|
||
I finally got around to setting up SSL with Let's Encrypt on my Emby instance. | ||
|
||
I use [`acme.sh`][acme.sh] for managing my Let's Encrypt certificates. It's a | ||
simple shell script that Just Works™. I use DigitalOcean for my DNS on my main | ||
network domain, `priddle.network`. `acme.sh` supports DigitalOcean DNS out of | ||
the box. | ||
|
||
[acme.sh]: https://github.com/acmesh-official/acme.sh | ||
|
||
Emby's SSL setup is a little different than a traditional web server like | ||
Nginx. Namely, you use a `.pfx` file instead of a `.crt` and `.key` pair. I | ||
suppose this isn't _that_ uncommon, since again, `acme.sh` supports it out of | ||
the box. | ||
|
||
A lot of setups recommend using Nginx as a reverse proxy to you regular Emby | ||
host---which would be `http://emby.priddle.network:8096` in my case. I tried | ||
this with Plex a while back and it was a pain. You have to setup a lot of | ||
different things to make websockets work correctly. | ||
|
||
Emby (and Plex, which I've obviously moved away from) has a built-in SSL | ||
support. You can just point it to your `.pfx` file and it works. Infuse and my | ||
other clients work perfectly. | ||
|
||
Since I'll have the certs, I can also setup `http://emby.priddle.network` and | ||
`https://emby.priddle.network` (without ports) to redirect to the Emby server | ||
running on SSL. We'll get back to that in a bit. | ||
|
||
First, install `acme.sh`. They recommend running it as root, so I'll do that. | ||
|
||
``` | ||
sudo -i | ||
curl https://get.acme.sh | sh -s [email protected] | ||
``` | ||
|
||
I like getting notifications when my certs renew. I use Slack for this. For | ||
simplicity, I just used a webhook URL. `acme.sh` also supports this out of the | ||
box. | ||
|
||
``` | ||
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx" | ||
acme.sh --set-notify --notify-hook slack | ||
``` | ||
|
||
We need a directory to store the certs that Emby and Nginx will use. Create it | ||
with: | ||
|
||
``` | ||
sudo mkdir -p /usr/local/etc/ssl/emby.priddle.network/ | ||
``` | ||
|
||
We'll need a script to generate the `.pfx` file from the Let's Encrypt certs. | ||
It'll also need to restart Emby and Nginx. Save it as `/root/reload-emby.sh`: | ||
|
||
```sh | ||
#!/usr/bin/env bash | ||
set -e | ||
|
||
/root/.acme.sh/acme.sh \ | ||
--to-pkcs12 \ | ||
--password 'real-password' | ||
--domain emby.priddle.network | ||
|
||
cp /root/.acme.sh/emby.priddle.network_ecc/emby.priddle.network.pfx \ | ||
/usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.pfx | ||
|
||
chmod 644 /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.pfx | ||
|
||
systemctl restart emby-server.service | ||
nginx -s reload | ||
``` | ||
|
||
Don't run this script yet. It'll be run automatically by `acme.sh` when we get the certs. | ||
|
||
Make sure to replace `real-password` with a real password. This is the | ||
password that Emby will use to decrypt the `.pfx` file. You also need to | ||
`chmod +x /root/reload-emby.sh` so `acme.sh` can run it. | ||
|
||
|
||
Next, let's enable SSL on Emby. Go to | ||
<http://emby.local:8096/web/index.html#!/network> and make sure to enable | ||
"Allow remote connections to this Emby Server." Enter your domain name (i.e | ||
`emby.priddle.network`) in "External | ||
domain" and set the "Custom ssl certificate path" to | ||
`/usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.pfx`. Enter the | ||
certificate password (i.e. "real-password"). Save these settings, but | ||
don't restart Emby. We'll do that when we get the certs. | ||
|
||
Let's hop over to Nginx and set that up. For me, I'm only using Nginx on my | ||
Ember server to redirect to the real Emby URLs, so I just replaced everything | ||
in `/etc/nginx/sites-enabled/default` with: | ||
|
||
```nginx | ||
server { | ||
listen 80; | ||
server_name _; | ||
return 301 https://$host:8920$request_uri; | ||
} | ||
server { | ||
listen 443 ssl; | ||
server_name _; | ||
ssl_certificate /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.cert.pem; | ||
ssl_certificate_key /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.key.pem; | ||
ssl_trusted_certificate /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.fullchain.pem; | ||
return 301 https://$host:8920$request_uri; | ||
} | ||
``` | ||
|
||
I also dropped this in `/etc/nginx/nginx.conf` in the `http { ... }` block: | ||
|
||
```nginx | ||
http { | ||
# ^ other stuff that was already there | ||
# Disable server tokens (i.e. Nginx) in response headers | ||
server_tokens off; | ||
# SSL session settings | ||
ssl_session_timeout 1d; | ||
ssl_session_cache shared:SSL:10m; | ||
ssl_session_tickets off; | ||
# Diffie-Hellman parameter for DHE ciphersuites | ||
ssl_dhparam /etc/nginx/dhparam.pem; | ||
# Mozilla Intermediate configuration | ||
ssl_protocols TLSv1.2 TLSv1.3; | ||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; | ||
# OCSP Stapling | ||
ssl_stapling on; | ||
ssl_stapling_verify on; | ||
resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s; | ||
resolver_timeout 2s; | ||
} | ||
``` | ||
|
||
On my system, I had to create `/etc/nginx/dhparam.pem` with: | ||
|
||
``` | ||
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048 | ||
``` | ||
|
||
Test the Nginx config with: | ||
|
||
``` | ||
sudo nginx -t | ||
``` | ||
|
||
Now we're ready to create the certs. See | ||
<https://github.com/acmesh-official/acme.sh/wiki/dnsapi> for info on different | ||
DNS providers. I'm using DigitalOcean, so I'll set the `DO_API_KEY` | ||
environment variable to my DigitalOcean API key. | ||
|
||
``` | ||
export DO_API_KEY="key" | ||
``` | ||
|
||
Next, issue the certs: | ||
|
||
``` | ||
acme.sh --issue --dns dns_dgon -d emby.priddle.network | ||
``` | ||
|
||
Install the certs: | ||
|
||
``` | ||
acme.sh --install-cert -d emby.priddle.network \ | ||
--cert-file /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.cert.pem \ | ||
--key-file /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.key.pem \ | ||
--fullchain-file /usr/local/etc/ssl/emby.priddle.network/emby.priddle.network.fullchain.pem \ | ||
--reloadcmd '/root/reload-emby-ssl.sh' | ||
``` | ||
|
||
If everything worked, you should see the certs in | ||
`/usr/local/etc/ssl/emby.priddle.network/`. The `reloadcmd` will have run | ||
`/root/reload-emby.sh` after the certs were generated. Emby should have | ||
restarted and Nginx should have reloaded. | ||
|
||
To test run the following `curl` commands: | ||
|
||
``` | ||
curl -vs https://emby.priddle.network 2>&1 | grep Location | ||
curl -vs http://emby.priddle.network 2>&1 | grep Location | ||
curl -vs https://emby.priddle.network:8920 2>&1 | grep 'private-network-access-name' | ||
``` | ||
|
||
And you should see something like: | ||
|
||
``` | ||
< Location: https://emby.priddle.network:8920/ | ||
< Location: https://emby.priddle.network:8920/ | ||
< private-network-access-name: Media Server | ||
``` | ||
|
||
Give it a try in your web browser to make sure everything worked. | ||
|
||
Finally, you can test everything fully with: | ||
|
||
``` | ||
acme.sh --cron --force | ||
``` |