在NixOS上设置Plex
Posted on February 22, 2022 from Nanyang,China几周前,我家实验室的硬盘(是的,我知道)坏了。 这是一个悲伤的时刻,特别是因为我在上面运行Plex,并且我依赖它来满足我的音乐和有声书需求。
好处是,这给了我重新考虑我的Plex配置的机会。 在家中托管它对于存储成本和控制方面很好,但是很难与朋友共享或在外出时访问,特别是对于具有NATed IPv4的情况,所以我决定转移到云端。
目录
选择服务器和存储方法
我选择了Hetzner Cloud,因为我喜欢他们的服务,并且他们使用清洁能源。
最大的挑战是存储。Hetzner的1TB的卷大约收费50欧元/月(其他提供商的定价相当)。
然而,后来我的朋友Eric告诉我了rclone以及它作为虚拟磁盘挂载Blob存储(价格便宜)的能力。 这意味着Plex将所有文件都视为实际存在,如果它尝试读取一个文件,如果它没有被缓存,它会在需要时下载。
在掌握了这个知识后,我开始设置服务器。
设置NixOS
NixOS是一个声明式和可复现的操作系统。
你有一个配置文件在 /etc/nixos/configuration.nix
,定义了你安装的应用程序、配置和系统设置。
如果你搞砸了,你总是可以回滚。
我首先创建了一个在Hetzner上的服务器,使用了任何发行版(我选择了一个 CPX11 和Ubuntu),然后按照 Hetzner Cloud 的安装脚本的指示操作。
如果您沿着这样做,请确保选择至少 40GB 的磁盘空间的服务器。
在引导NixOS之后,我通过运行 passwd
更改了root密码,并升级了NixOS(请参阅NixOS升级)。
如果你想进一步保护你的NixOS安装,Christine Dodrill有一个很好的指南,名为Paranoid NixOS Setup。
设置存储
我决定使用Backblaze B2,因为我以前用过它,它比S3便宜,而且我不支持亚马逊。 如果你想使用其他存储服务,rclone支持很多提供商。
在为媒体创建存储桶之后,我创建了一个应用密钥,并记录了 keyID
和 applicationKey
。
然后,我在我的Nix配置文件 /etc/nixos/configuration.nix
中添加了以下行,以安装rclone并创建一个用于存储桶的 /etc/rclone/rclone.conf
:
environment.systemPackages = [ pkgs.rclone ];
environment.etc = {
"rclone/rclone.conf" = {
text = ''
[b2]
type = b2
account = <keyID>
key = <applicationKey>
hard_delete = true
versions = false
'';
mode = "0644";
};
};
如果你按照这样做,请确保将 <keyID>
和 <applicationKey>
替换为正确的值。
顺便说一句,NixOS预先安装了nano,所以如果你想使用一个真正的编辑器,你可以使用以下命令获取它:
$ nix-shell -p vim
对于磁盘挂载,我创建了一个Systemd服务,它在启动时挂载存储桶,并在启动时自动启动。
systemd.services.plex_media = {
enable = true;
description = "挂载媒体目录";
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStartPre = "/run/current-system/sw/bin/mkdir -p /mnt/media";
ExecStart = ''
${pkgs.rclone}/bin/rclone mount 'b2:<bucket name>/' /mnt/media \
--config=/etc/rclone/rclone.conf \
--allow-other \
--allow-non-empty \
--log-level=INFO \
--buffer-size=50M \
--drive-acknowledge-abuse=true \
--no-modtime \
--vfs-cache-mode full \
--vfs-cache-max-size 20G \
--vfs-read-chunk-size=32M \
--vfs-read-chunk-size-limit=256M
'';
ExecStop = "/run/wrappers/bin/fusermount -u /mnt/media";
Type = "notify";
Restart = "always";
RestartSec = "10s";
Environment = ["PATH=${pkgs.fuse}/bin:$PATH"];
};
};
如果你按照这样做,请确保将 <bucket name>
替换为正确的值。
--vfs-*
参数用于配置虚拟文件系统。
我只有40GB的本地磁盘空间,所以我将缓存大小设置为20GB(使用 --vfs-cache-max-size
)。
然后我执行 nixos-rebuild switch
来应用配置,将一些数据上传到存储桶,并列出 /mnt/media
,以确保一切正常工作。
配置Plex
NixOS预定义了一个Plex服务,我像这样使用它:
nixpkgs.config.allowUnfree = true; # Plex是非自由的
services.plex = {
enable = true;
dataDir = "/var/lib/plex";
openFirewall = true;
user = "plex";
group = "plex";
};
通过这个配置,Nix将在防火墙中打开正确的端口,创建一个名为 plex
的用户,带有一个名为 plex
的组,并在 /var/lib/plex
中安装Plex Media Server。
添加Audiobooks插件
我想使用 Audiobooks.bundle 元数据代理以获得更好的匹配效果,所以我将下面的代码添加到 plex.nix
顶部的 let
部分:
let
audiobooksPlugin = pkgs.stdenv.mkDerivation {
name = "Audiobooks.bundle";
src = pkgs.fetchurl {
url = https://github.com/macr0dev/Audiobooks.bundle/archive/9b1de6b66cd8fe11c7d27623d8579f43df9f8b86.zip;
sha256 = "539492e3b06fca2ceb5f0cb6c5e47462d38019317b242f6f74d55c3b2d5f6e1d";
};
buildInputs = [ pkgs.unzip ];
installPhase = "mkdir -p $out; cp -R * $out/";
};
in
# ...
这段代码将获取 9b1de6b
commit 的 audiobooks 插件,并确保 SHA256 正确。
然后,我告诉Plex使用这个插件:
services.plex.managePlugins = true;
services.plex.extraPlugins = [audiobooksPlugin];
如果你看到错误提示,说 services.plex.managePlugins
不再起效果了,请删除那行。
在这一点上,再次运行 nixos-rebuild switch
之后,我就能够在 https://<域名或IP>:32400
访问Plex界面了。
Plex需要进行初始配置,但只允许本地连接。 一种方法是使用SSH隧道,可以像这样打开它:
$ ssh -L 32400:localhost:32400 user@domain-or-ip
然后在本地浏览器中打开 http://localhost:32400/web 并设置Plex。
配置Nginx
我想要一个漂亮的域名,并且使用443端口上的HTTPS(而不是32400端口上的HTTP),所以我接下来设置了Nginx和Let's Encrypt。
首先,我在Plex配置中将 openFirewall
设置为false。
然后,我允许80端口和443端口的HTTP和HTTPS,以及除了32400端口之外的所有Plex端口,因为我们希望通过Nginx来代理Web界面。
services.plex = {
openFirewall = false;
# ...
};
networking.firewall = {
allowedTCPPorts = [ 3005 8324 32469 80 443 ];
allowedUDPPorts = [ 1900 5353 32410 32412 32413 32414 ];
};
然后,我配置了ACME:
security.acme.acceptTerms = true;
security.acme.defaults.email = "<你的电子邮件>";
默认的提供商是Let's Encrypt,您可以在此处找到他们的服务条款: Policy and Legal Repository。
现在,是时候添加Nginx服务了。 我使用推荐的设置,只使用支持PFS的AES256密码。 由于这是用于代理Plex请求,因此我还转发了一些标头。 以下是代码:
services.nginx = {
enable = true;
# 推荐的设置
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
# 仅允许使用支持PFS的AES256密码
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
virtualHosts = {
"<你的域名>" = {
forceSSL = true;
enableACME = true;
extraConfig = ''
# 某些播放器不会重新打开套接字,播放暂停时间较长后并不会继续播放,而是完全停止
send_timeout 100m;
# Plex标头
proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier;
proxy_set_header X-Plex-Device $http_x_plex_device;
proxy_set_header X-Plex-Device-Name $http_x_plex_device_name;
proxy_set_header X-Plex-Platform $http_x_plex_platform;
proxy_set_header X-Plex-Platform-Version $http_x_plex_platform_version;
proxy_set_header X-Plex-Product $http_x_plex_product;
proxy_set_header X-Plex-Token $http_x_plex_token;
proxy_set_header X-Plex-Version $http_x_plex_version;
proxy_set_header X-Plex-Nocache $http_x_plex_nocache;
proxy_set_header X-Plex-Provides $http_x_plex_provides;
proxy_set_header X-Plex-Device-Vendor $http_x_plex_device_vendor;
proxy_set_header X-Plex-Model $http_x_plex_model;
# 缓冲关闭,当数据从 Plex 接收时,立即将其发送到客户端
proxy_redirect off;
proxy_buffering off;
'';
locations."/" = {
proxyPass = "http://localhost:32400";
proxyWebsockets = true;
};
};
};
};
如果你在按照这个进行操作,请确保将 <你的域名>
替换为正确的值。
为了进一步增强安全性,我为每个请求设置了一些头部:
services.nginx.commonHttpConfig = ''
# 添加带有预加载的HSTS头部到HTTPS请求。
# 不鼓励在HTTP请求中添加此头部
map $scheme $hsts_header {
https "max-age=31536000; includeSubdomains; preload";
}
add_header Strict-Transport-Security $hsts_header;
# 为您的服务启用CSP。
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
# 最小化泄露给其他域名的信息
add_header 'Referrer-Policy' 'origin-when-cross-origin';
# 禁止作为框架的嵌入
add_header X-Frame-Options DENY;
# 防止在其他MIME类型中注入代码(XSS攻击)
add_header X-Content-Type-Options nosniff;
# 启用浏览器的XSS保护。
# 当CSP配置得当时可能是不必要的(见上文)
add_header X-XSS-Protection "1; mode=block";
'';
最后,我再次运行了 nixos-rebuild switch
来应用配置。
然后我在浏览器中打开 https://my-domain
并开始创建Plex库。
成本如何?
CPX11的成本为每月4.75欧元(启用备份),B2的成本为每月0.005美元/GB的存储费用 + 每GB下载的0.01美元。 存储费用严重依赖于存储的媒体数量和下载的媒体数量。 我的设置每月支付大约10欧元。
总结
现在,只剩下进一步配置NixOS来设置主机名、时区、安装 htop
等软件包,并启用自动升级。
如果对你有用,这里是我测试这篇博客文章时的configuration.nix。
如果你发现问题或有问题,请随时让我知道,我非常乐意帮助!