Unraid 通过 Nginx 加速 Docker pull 及 Apps 应用下载速度 & 解决插件页面加载时间过长

4.8
(4)

前言

Unraid 是一个由 Lime Technology, Inc. 开发的买断制家庭 NAS 系统。因其活跃的社区支持、美观易用的WebUI、相比 RAID 更适合家庭 NAS 的奇偶校验保护,在很早之前就受到了大量玩家的喜爱,包括 Linus Media Group 的 Linus 在 LTT 的不少项目中都介绍、使用了 Unraid ,国内 NAS 玩家圈中也有小范围关于 Unraid 的介绍。

自从 Unraid 6.9 版本添加了多国语言、支持了简体中文之后,在国内 NAS 玩家中的用户量逐渐增长。

但众所周知,Unraid 系统安装插件、下载 Docker 镜像、检查更新等各项功能都依赖良好的网络连接,受限于网络环境,国内玩家常常面临下载速度慢的问题。并且,Unraid 也没有办法方便地设置代理,在社区中相关的问题也因需求不足,大多没有下文。

目前对于这种难以设置代理的设备,常见的方案是在网关设置透明代理,或利用软路由、旁路由的相关插件。

对于不想折腾网关的朋友,本文将介绍如何通过 Nginx,实现加速 Docker 及 Apps 的方法。

Unraid WebUI 插件页加载时间长的原因和解决方案

有部分用户可能会注意到,在 Unraid WebUI 进入插件页时,每次都需要等待很久才能加载完成,且安装的插件数量越多,加载时间越久。

这是因为,Unraid 默认每次进入插件页时,都会对所有插件检查更新,检查更新需要访问 raw.githubusercontent.com,若恰逢网络环境不佳,则可能长时间无法完成。

要解决这个问题,可以简单通过关闭每次的自动检查更新,在有需要的时候自行点击检查更新。

在通知设置中 将插件更新通知 修改为永不检查即可

如果想通过代理彻底解决网络连接问题,请继续往下看。(请务必全文浏览后再进行操作

方法一:在 VPS 上配置 Nginx 通过 SNI 分流转发流量

通过 Nginx 加速有两种操作方法

  1. 直接在你拥有的 VPS 上配置 Nginx 通过 SNI 分流转发流量
  2. 在 Unraid 中配置 Nginx 搭配 socat 及自签名证书通过 HTTP 代理转发流量
  • 方法一需要:一台你拥有 root 权限的、到你本地 NAS 线路优良的 VPS,相关 Nginx 知识。

方法一的流量路径为:Unraid 系统 → | → VPS 上的 Nginx → 实际访问网站;在这之中,Nginx 仅对 TLS 流量进行转发,不会进行加密解密,配置较为简单。

  • 方法二需要:一个部署在本地的、可通过 HTTP 传入连接的代理工具,相关 Nginx 知识,相关 OpenSSL 知识。

方法二的流量路径为:Unraid 系统 → Nginx → socat → HTTP 代理入 → | → HTTP 代理出 → 实际访问网站;在这之中,Nginx 需要建立两段 TLS 连接,需要自签名证书。

首先说明为什么会有两种方法,实际上,笔者先想到的是方法一,但在操作中发现,raw.githubusercontent.com 因为 SNI 信息中包含 GitHub 关键字,连接质量会受到劣化,且 VPS 的 IP 段常常会有人扫描,有被偷流量的可能,故在方法一的基础上进一步改出了方法二。

所以,方法一只适合加速 Docker 不适合加速 GitHub,在这一节简单介绍,不做推荐,如果使用该方法,请密切关注 VPS 的流量使用情况,谨防流量盗贼。

第一步:在 VPS 上安装 Docker

直接通过系统包管理器安装 Nginx 可能不包含需要用到的 ngx_stream_ssl_preread_module 模块,为了避免自行编译 Nginx 的复杂,用到 Docker。

已有 Docker 或编译好的 Nginx 可跳过。以下命令均以 Ubuntu 系统 root 用户下操作为例。

# 更新软件包索引
apt update
# 安装必要软件包
apt install apt-transport-https ca-certificates curl gnupg lsb-release

# 添加 Docker 官方 GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加稳定版 Docker 软件源
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker
apt update
apt install docker-ce docker-ce-cli containerd.io

# 安装成功则输出版本号
docker -v

第二步:在 Docker 中安装 Nginx

用到 linuxserver/nginx 镜像,已安装可跳过。

# 拉取镜像
docker pull linuxserver/nginx
# 创建容器 (/path/to/config 替换为你喜欢的配置文件存放路径)
docker run -d --name="nginx" -e PUID="1000" -e PGID="1000" -e TZ="Asia/Shanghai" -v /path/to/config:/config --net="host" --restart=always linuxserver/nginx

第三步:配置 Nginx

找到 Nginx 的配置文件(上例中为 /path/to/config/nginx/nginx.conf ),在 http 块前添加以下内容。

stream {
	map $ssl_preread_server_name $backend_pool {
		example.com				127.0.0.1:6443;
		
		#raw.githubusercontent.com		raw.githubusercontent.com:443;
		~^(?<ns1>.+).amazonaws.com		$ns1.amazonaws.com:443;
		
		hub.docker.com				hub.docker.com:443;
		docker.io				docker.io:443;
		~^(?<ns1>.+).docker.io			$ns1.docker.io:443;
		~^(?<ns1>.+).hub.docker.com		$ns1.hub.docker.com:443;
		
		unraid.net				unraid.net:443;
		~^(?<ns1>.+).unraid.net			$ns1.unraid.net:443;
		lime-technology.com			lime-technology.com:443;
		~^(?<ns1>.+).lime-technology.com	$ns1.lime-technology.com:443;
		
		default					block;
	}
	
	upstream block {
		server 127.0.0.1:1;
	}
	
	server {
		listen 443 reuseport;
		ssl_preread on;
		resolver 208.67.222.222;
		proxy_pass $backend_pool;
		proxy_connect_timeout 15s;
		proxy_timeout 15s;
		proxy_next_upstream_timeout 15s;
	}
}

map $ssl_preread_server_name $backend_pool 将读取 SNI 中的 Server Name 并映射到对应后端,如果你在 Nginx 中已经部署有其他 HTTPS 网站,可以让你的它监听另一个端口(如上例中的 6443,该端口无需暴露在公网),然后修改 example.com 为你的网站域名,即可不影响原有网站。

resolver 使用的是 Unraid 官方推荐的 DNS,你也可以更改为如 8.8.8.8 等其他可用 DNS。

# 重启 Nginx 容器使配置生效
docker restart nginx

有关 Nginx 的其他配置问题,本文不做详细介绍。

第四步:修改 Unraid 中的 hosts

让 Docker 相关地址解析到你的 VPS IP 最简单的方法是直接修改 hosts,Unraid 的 hosts 文件在 /etc/hosts,修改后应该是立即生效的,注意先备份原 hosts 文件。以下列表供参考,0.0.0.0 替换为你 VPS 的 IP 地址。

127.0.0.1 UNRAID localhost

0.0.0.0	s3.amazonaws.com
0.0.0.0	unraid.net
0.0.0.0	forums.unraid.net
0.0.0.0	wiki.unraid.net
0.0.0.0	registration.unraid.net
0.0.0.0	registration-dev.unraid.net
0.0.0.0	lime-technology.com
0.0.0.0	keys.lime-technology.com
# 54.149.176.35	keys.lime-technology.com

0.0.0.0	hub.docker.com
0.0.0.0	docker.io
0.0.0.0	index.docker.io
0.0.0.0	registry-1.docker.io

另外,hosts 文件中无法使用通配符,可能存在域名遗漏,你也可以通过自建 DNS 等方法,达到相同的目的。

方法二:在 Unraid 中配置 Nginx 搭配 socat 及自签名证书通过 HTTP 代理转发流量

本方法相比方法一具有更好的稳定性、隐私性,但配置过程较繁琐,请务必全文阅读后再进行操作。

第一步:创建私有 CA 根证书、用户证书

创建一个私有 CA 根证书,然后使用它创建出 raw.githubusercontent.com 的用户证书。如果需要代理更多域名,则创建对应域名的证书即可。

碍于篇幅,本文不再赘述证书创建方法,你可以查看这篇文章(https://www.cnblogs.com/sparkdev/p/10369313.html)获得相关指南。

第二步:在 Docker 中安装 Nginx 及 socat

因 Nginx proxy_pass 似乎无法直接配置为通过 HTTP 代理,笔者在此选择搭配 socat 使用。这里用到以下两个镜像。

docker pull linuxserver/nginx
docker pull alpine/socat

注意,你既可以在 WebUI 操作,也可以 SSH 连接终端操作,因 Unraid WebUI 管理 Docker 容器需要创建 xml 文件,如果直接在终端创建容器,就无法在 WebUI 中编辑,也无法为容器设置图标,所以笔者个人习惯于在终端 pull 好镜像后,再到 WebUI 创建容器。上述 linuxserver/nginx 镜像在 Unraid Apps 中也可以找到,你也可以在 Apps 中获取。

进入 Unraid WebUI Docker 页,点击下方添加容器按钮,再点击右上角开关进入高级视图。Nginx 容器创建参数与方法一所述大同小异,不再赘述。

socat 容器创建参数如下图。

这里建议将 Nginx、socat 以及可能存在的代理工具容器,网络类型都设置为 Host,避免不必要的复杂性。当然你也可以根据自身需要进行个性化配置。

这里假设你拥有的可顺畅访问 GitHub 的 HTTP 代理地址为 127.0.0.1:10808,则在发布参数中,填写

TCP4-LISTEN:4443,reuseaddr,fork PROXY:127.0.0.1:raw.githubusercontent.com:443,proxyport=10808

上例中的 4443 端口为稍后需要 Nginx 转发到的端口,也可以根据需要修改。配置完成后,直接运行 socat 容器。

==2021-04-05 追记==

如果需要代理多个网站,可以写一个脚本映射入容器内,例如将以下内容写入 run.sh 映射入容器 /run/run.sh

#!/bin/sh
/usr/bin/socat TCP-LISTEN:10000,reuseaddr,fork PROXY:127.0.0.1:raw.githubusercontent.com:443,proxyport=10808 & /usr/bin/socat TCP-LISTEN:10001,reuseaddr,fork PROXY:127.0.0.1:github.com:443,proxyport=10808 & /usr/bin/socat TCP-LISTEN:10002,reuseaddr,fork PROXY:127.0.0.1:s3.amazonaws.com:443,proxyport=10808 &
while true; do sleep 300; done

然后在额外参数处填入 –entrypoint=”/run/run.sh”,发布参数留空即可

==追记结束==

第三步:使 Unraid 信任私有 CA 根证书

证书创建后,将私有 CA 根证书或证书链文件,放入 Unraid 系统 /usr/local/share/ca-certificates 目录内,如果没有 ca-certificates 目录,自行建立即可。

若证书文件后缀为 pem,改为 crt,例如 /usr/local/share/ca-certificates/FakeCA.crt

根证书放入后,在 Unraid 终端执行

# 添加和删除证书都需要执行
update-ca-certificates

若看到提示 1 added, 0 removed; done. 输出,则说明添加成功。

注意:添加信任根证书为高危操作,意味着该根证书颁发的任何网站的证书都会被系统信任,请务必妥善保管好你生成的私钥文件,泄露可能导致你面临中间人攻击。

第四步:配置 Nginx

找到 Nginx 的配置文件,在 http 块前添加

stream {
	map $ssl_preread_server_name $name {
		raw.githubusercontent.com	web;
		default				block;
	}
	upstream web {
		server 127.0.0.1:3443;
	}
	upstream block {
		server 127.0.0.1:8144;
	}
	server {
		listen 443 reuseport;
		resolver 208.67.222.222;
		proxy_pass $name;
		ssl_preread on;
		proxy_connect_timeout 15s;
		proxy_timeout 15s;
		proxy_next_upstream_timeout 15s;
	}
}

在 http 块中添加 server

server {
		listen 8144 default_server;
		return 444;
}

server {
		listen 3443 ssl http2;
		server_name raw.githubusercontent.com;
		#==========SSL相关设置==========
		ssl_certificate /path/to/gitraw.cert.pem;
		ssl_certificate_key /path/to/gitraw.key.pem;
		ssl_session_cache shared:SSL:10m;
		ssl_session_timeout 1d;
		ssl_session_tickets off;
		ssl_prefer_server_ciphers off;
		ssl_early_data on;
		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;
		#===============================
		location / {
			proxy_set_header Host raw.githubusercontent.com;
			proxy_pass https://127.0.0.1:4443/;
		}
}

上例中的 3443 8144 端口为 SNI Name 分流用,可自定义为其他端口,但 443 端口不得更改,若有端口冲突,请更改冲突服务的端口。

这里不直接在 server 监听 443 是为了留出拓展空间,你可以在 stream 块 map 中添加多个域名映射到 3443,添加多个监听 3443 端口的 server 后,Nginx 会自动匹配 server_name 选择合适的 server。

上例中 /path/to/gitraw.cert.pem 及 /path/to/gitraw.key.pem 为第一步创建的 raw.githubusercontent.com 用户证书和私钥存放路径,修改到你的存放位置即可,其他参数也可以参照 Nginx 相关文档进行个性化修改。

特别提醒:如果你不了解相关风险,国内家庭宽带用户请不要将上例任何端口转发到公网,特别是具有公网 IP 的用户,被运营商误认为私开 Web 服务可能导致严重后果。

第五步:修改 Unraid 中的 hosts

在 Unraid 系统 /etc/hosts 文件中添加

127.0.0.1	raw.githubusercontent.com

第六步:验证

在 Unraid 终端执行以下命令,尝试下载一个文件测试

wget https://raw.githubusercontent.com/jellyfin/jellyfin/master/README.md && rm README.md

若没有提示证书错误,下载成功,则说明配置正确。你可以尝试在 WebUI 中为插件检查一下更新,应该能看到速度明显提升。

第七步:设置开机自动添加证书、hosts

Unraid 系统重启后大部分系统更改不会保留,需要设置一下。

首先将你的根证书 FakeCA.crt 和修改好的 hosts 文件复制一份到 U 盘根目录(在 Unraid 系统中是 /boot )。

然后找到 /boot/config/go 文件,在 /usr/local/sbin/emhttp & 之前添加以下内容

mkdir -p /usr/local/share/ca-certificates && cp /boot/FakeCA.crt /usr/local/share/ca-certificates/
chmod 755 /usr/local/share/ca-certificates && chmod 644 /usr/local/share/ca-certificates/FakeCA.crt
update-ca-certificates
mv /etc/hosts /etc/hosts.bak && cp /boot/hosts /etc/hosts

现在,每次开机都会自动执行添加信任证书和替换 hosts 了。注意打开所需 Docker 容器的自动启动开关,如有需要,在设置——磁盘设置——启用自动启动,打开阵列自动启动开关(阵列启动前,Docker 不会启动)。

参考资料

《Install Docker Engine on Ubuntu | Docker Documentation》https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
《Module ngx_http_map_module | nginx documentation》https://nginx.org/en/docs/http/ngx_http_map_module.html#map
《Regular expressions names | nginx documentation》https://nginx.org/en/docs/http/server_names.html#regex_names
《Nginx TLS SNI routing, based on subdomain pattern》https://gist.github.com/kekru/c09dbab5e78bf76402966b13fa72b9d2
《使用 OpenSSL 创建私有 CA - sparkdev》https://www.cnblogs.com/sparkdev/p/10369313.html

这篇文章有用吗?

点击星号为它评分!

平均评分 4.8 / 5. 投票数: 4

到目前为止还没有投票!成为第一位评论此文章。

很抱歉,这篇文章对您没有用!

让我们改善这篇文章!

告诉我们我们如何改善这篇文章?

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注