详情见 MeTube 主页,我这里流水账一下:
#安装、升级 npm / n apt install npm npm -g install n n lts cd metube/ui # 安装 Angular,构建 UI npm install node_modules/.bin/ng build # 安装 Python 依赖 cd .. pip3 install pipenv pipenv install python3 -m pip install aiohttp pipenv install aiohttp #安装 ffmpeg,合并音频视频,Youtube 新视频基本都需要合并 apt install ffmpeg # 自定义环境文件测试运行 export DOWNLOAD_DIR=/home/wwwroot/metube export URL_PREFIX=/metube pipenv run python3 app/main.py
正常会输出:
INFO:ytdl:waiting for item to download
======== Running on http://0.0.0.0:8081 ========
(Press CTRL+C to quit)
可以浏览器连接: http://VPS-IP:8081,测试一下下载,没问题往下走。
配置 Nginx 转发:
#主转发代码 location /metube/ { proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } #没有问题这一块可以不要 location ~* .(css|js)$ { proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }
添加到开机自动运行:
systemctl edit metube --full --force
粘贴如下代码,metube 源码路径,下载路径,反代目录,改成自己的:
[Unit] Description=Metube Web Service After=network.target [Service] Environment=DOWNLOAD_DIR=/home/wwwroot/metube Environment=URL_PREFIX=/metube Restart=always Type=simple WorkingDirectory=/root/src/metube ExecStart=/usr/local/bin/pipenv run python3 /root/src/metube/app/main.py [Install] WantedBy=multi-user.target
然后执行:
systemctl enable --now metube
metube 就启动了,并且下次开机也会自己启动。
追加:
添加简单的密码认证:
#生成密码文件,添加用户名 sudo sh -c "echo -n 'sammy:' >> /etc/nginx/.htpasswd" #为此用户设置密码 sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"
然后添加到 metube 反代中:
location /metube/ { auth_basic "Administrator’s Area"; auth_basic_user_file /etc/nginx/.htpasswd"; ... }
这里试过反代 ifile share,cloudreve,metube 等都出现这个问题,主页面可以显示,表示反代是没有问题的,但是所有 css,js 文件都是 404,界面显示不完全,很奇怪,你说都是静态文件,但 favicon.ico 那些没问题。
原本反代代码,css/js 404 出错:
location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; proxy_pass http://127.0.0.1:808; add_header X-Cache $upstream_cache_status; add_header Cache-Control no-cache; }
添加以下代码,则正常:
location ~* \.(gif|png|jpg|css|js|woff|woff2)$ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; proxy_pass http://127.0.0.1:808; expires 12h; }
这里有个问题,如果反代不是在 / 下,而是子目录下,比如 /metube,按照上面的写法就会影响到 / 下主站,导致主站找不到一些资源文件,我这里就出现修改后主站找不到 favicon.png 的问题,所以我就只添加 css|js 添加子目录匹配:
location /metube/ { proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } location ~ ^/metube/.*\.(css|js)$ { proxy_pass http://127.0.0.1:8081; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }
主站 PHP 脚本都是远程调用 CDN 的 css|js,没有本地的,所以没出问题。至少这样暂时能用。
没找到问题的根本!
SNI 分流后获取客户端 IP 一般通过 proxy_protocol 来实现,但分流后的某些程序不能识别 proxy_protocol 怎么办?比如我的 DoH 服务器要 IP 地址,但某木头马并不支持,我开启 proxy_protocol 这马就死了。
我们看代码片段,注意注释。
nginx.conf 主配置文件片段:
stream { # 这里就是 SNI 识别,将域名映射成一个配置名 map $ssl_preread_server_name $backend_name { 我的域名.坑 web; 马.我的域名.坑 马; # 域名都不匹配情况下的默认值 default web; } # 转发到 web 服务器 upstream web { server 127.0.0.1:444; } # 转发到 马 前置服务器 upstream 马 { server 127.0.0.1:446; } # 为 马 去除 proxy_protocol server { #nginx server 443 开启 proxy_protocol 后,分流后的所有服务也必须开启 proxy_protocol,否则会报错 listen 127.0.0.1:446 proxy_protocol so_keepalive=on; proxy_protocol off; #然而,我们在这儿把 proxy_protocol 关闭掉,因为 马 不支持!这是关键 proxy_connect_timeout 300s; proxy_timeout 300s; proxy_pass 127.0.0.1:445; #这就是 马 实际吃草的地方 } # 监听 443 并开启 ssl_preread server { listen 443 reuseport; listen [::]:443 reuseport; proxy_pass $backend_name; ssl_preread on; #开启了分流 proxy_protocol on; #开启了 proxy_protocol } }
虚拟站点配置文件代码块,大致如下:
server { #nginx server 443 开启 proxy_protocol 后,分流后的所有服务也必须开启 proxy_protocol,否则会报错 listen 127.0.0.1:444 ssl http2 reuseport proxy_protocol; #下面三行给反代的 DoH 服务器传递了客户端 IP set_real_ip_from 127.0.0.1; real_ip_recursive on; real_ip_header proxy_protocol; server_name 三达不溜.我的域名.坑 我的域名.坑; index index.html index.htm index.php default.html default.htm default.php; root /home/wwwroot/我的域名.坑; ssl_certificate /usr/local/nginx/conf/ssl/fullchain.cer; ssl_certificate_key /usr/local/nginx/conf/ssl/我的域名.坑_ssl.key; #反代 DoH 服务器 location /dns-query { proxy_pass http://127.0.0.1:8053/dns-query; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; #我要,真实的,IP! }
差不多这样。
来自 https://github.com/trojan-gfw/trojan/issues/433#issuecomment-692878138 的方法更加精妙:
stream { log_format basic '$remote_addr - $remote_user [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time'; map $ssl_preread_server_name $backend { trojan6.domain.com unix:/run/nginx-trojan-stream.sock; trojan.domain.com unix:/run/nginx-trojan-stream.sock; default 127.0.0.1:443; } server { listen unix:/run/nginx-trojan-stream.sock proxy_protocol; proxy_pass 127.0.0.1:8443; } server { listen 0.0.0.0:443; listen [::]:443; proxy_pass $backend; ssl_preread on; proxy_protocol on; } } http { log_format combined '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; server { listen 127.0.0.1:80 proxy_protocol; listen [::1]:443 ssl proxy_protocol; ... } }
http 的 log_format 中,原来的将原来的 $remote_addr 替换成 $proxy_protocol_addr 就成了。
stream 中的第一个 server 就是为了接收带 proxy_protocol 的 stream,然后发出不带 proxy_protocol 的 stream 给 trojan。
另外,我用的是在 Ubuntu 20.04上 的 Nginx v.1.18.0,来自官方 apt 源的。
本文大部分内容来自 自行搭建Clash订阅转换平台 一文,感谢原作者。
预备工作:
首先需要在域名服务商解析两个域名,都是 A 记录
前端 我们使用 sub.mysite.com
后端 我们使用 sc.mysite.com
最好先把 mysite.com 做好泛域名解析,例如:
apt install socat
curl https://get.acme.sh | sh
acme.sh --set-default-ca --server letsencrypt
export Namecom_Username="myname"
export Namecom_Token="fe9ckjdbnkjasd76dta7d7fb9b91a59c9"
acme.sh --issue --dns dns_namecom -d mysite.com -d *.mysite.com
搭建Sub-Web前端
更新系统并安装 Node 与 Yarn
依次运行下面四行代码,若是 CentOS 系统,请自行替换下面前两行命令中的 apt 为 yum
apt update -y
apt install -y curl wget sudo nodejs npm git
服务器在国内的:
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g yarn
服务器在国外的
npm install -g yarn
命令执行完毕以后,请运行下面的代码查询 Node 与 Yarn 是否安装成功,若是成功会返回版本号
node -v
yarn --version
下载并安装 Sub-Web
拉取 sub-web 程序,并进入 sub-web 文件夹
git clone https://github.com/CareyWang/sub-web.git --depth=1
cd sub-web
在项目目录中安装构建依赖项,构建的过程稍微有点长
yarn install
使用 webpack 运行 Web 客户端以进行本地开发。
yarn serve
到目前为止,浏览器访问 http://服务器ip:8080/ 应该可以进行前端 sub-web 的预览了。
修改默认后端地址
找到 VPS /root/src/sub-web/src/views/Subconverter.vue 文件
找到 257行 backendOptions:(写博客的时候是这行),替换后面的 http://127.0.0.1:25500/sub?
为 https://suc.mysite.com/sub?
(注意两个地方:域名为你刚才准备的后端域名,是 https 而非 http)
更换远程规则
因为这个版本更新以后,规则方面很少,经常用到的一些经典的 ACL4SSR 的规则并没有集成,大家可以看看,若是有,就不需要这样操作。
VPS找到 /root/src/sub-web/src/views/Subconverter.vue 文件,找到 258行 remoteConfig: [
,敲下回车,插入下面内容。
{
label: "ACL4SSR",
options: [
{
label: "ACL4SSR_Online 默认版 分组比较全 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
},
{
label: "ACL4SSR_Online_AdblockPlus 更多去广告 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_AdblockPlus.ini"
},
{
label: "ACL4SSR_Online_NoAuto 无自动测速 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_NoAuto.ini"
},
{
label: "ACL4SSR_Online_NoReject 无广告拦截规则 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_NoReject.ini"
},
{
label: "ACL4SSR_Online_Mini 精简版 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini.ini"
},
{
label: "ACL4SSR_Online_Mini_AdblockPlus.ini 精简版 更多去广告 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_AdblockPlus.ini"
},
{
label: "ACL4SSR_Online_Mini_NoAuto.ini 精简版 不带自动测速 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_NoAuto.ini"
},
{
label: "ACL4SSR_Online_Mini_Fallback.ini 精简版 带故障转移 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_Fallback.ini"
},
{
label: "ACL4SSR_Online_Mini_MultiMode.ini 精简版 自动测速、故障转移、负载均衡 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_MultiMode.ini"
},
{
label: "ACL4SSR_Online_Full 全分组 重度用户使用 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full.ini"
},
{
label: "ACL4SSR_Online_Full_NoAuto.ini 全分组 无自动测速 重度用户使用 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_NoAuto.ini"
},
{
label: "ACL4SSR_Online_Full_AdblockPlus 全分组 重度用户使用 更多去广告 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_AdblockPlus.ini"
},
{
label: "ACL4SSR_Online_Full_Netflix 全分组 重度用户使用 奈飞全量 (与Github同步)",
value:
"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_Netflix.ini"
},
{
label: "ACL4SSR 本地 默认版 分组比较全",
value: "config/ACL4SSR.ini"
},
{
label: "ACL4SSR_Mini 本地 精简版",
value: "config/ACL4SSR_Mini.ini"
},
{
label: "ACL4SSR_Mini_NoAuto.ini 本地 精简版+无自动测速",
value: "config/ACL4SSR_Mini_NoAuto.ini"
},
{
label: "ACL4SSR_Mini_Fallback.ini 本地 精简版+fallback",
value: "config/ACL4SSR_Mini_Fallback.ini"
},
{
label: "ACL4SSR_BackCN 本地 回国",
value: "config/ACL4SSR_BackCN.ini"
},
{
label: "ACL4SSR_NoApple 本地 无苹果分流",
value: "config/ACL4SSR_NoApple.ini"
},
{
label: "ACL4SSR_NoAuto 本地 无自动测速 ",
value: "config/ACL4SSR_NoAuto.ini"
},
{
label: "ACL4SSR_NoAuto_NoApple 本地 无自动测速&无苹果分流",
value: "config/ACL4SSR_NoAuto_NoApple.ini"
},
{
label: "ACL4SSR_NoMicrosoft 本地 无微软分流",
value: "config/ACL4SSR_NoMicrosoft.ini"
},
{
label: "ACL4SSR_WithGFW 本地 GFW列表",
value: "config/ACL4SSR_WithGFW.ini"
}
]
},
修改完毕以后,程序会自动更新,稍等然后再次刷新前端网页,会出现刚才添加的相关规则以及后端地址。
至此,我们的前端调试完毕,我们现在需要打包,生成一个发布目录。
首先停止调试程序,CTRL+C ,退出当前调试,然后执行下面的命令进行打包:
yarn build
执行以下打包命令,在 /root/src/sub-web 下面会生成一个 dist 目录,这个目录即为网页的发布目录。
把这个目录下的文件全部拷贝到你之前发布网站的目录下,比如 /home/wwwroot/mysite:
cp -R /root/src/sub-web/dist/* /home/wwwroot/mysite
反代详解:
因为之前已经有主站,我们需要反代前端和后端这两个站点:
打开你的 nginx.conf 文件(根据系统不同位置不一样,用 nginx -V
查看 --conf-path= 找到这个文件),在 event 和 http 代码块中间插入 stream 块内容:
... events { workerconnections 768; # multiaccept on; } stream { #这里就是 SNI 识别,将域名映射成一个配置名,请修改自己的一级域名 map $ssl_preread_server_name $backend_name { mysite.com web; sub.mysite.com sub; sc.mysite.com sc; #域名都不匹配情况下的默认值 default web; } #web 主站转发 upstream web { server 127.0.0.1:444; } #sub 前端转发 upstream sub { server 127.0.0.1:446; } #sc 后端转发 upstream sc { server 127.0.0.1:447; } #监听 443 并开启 ssl_preread server { listen 443 reuseport; listen [::]:443 reuseport; proxypass $backendname; ssl_preread on; } } http { ...
然后在对应的虚拟站点目录(一般是 nginx 配置目录下的 vhosts 目录 或者 conf.d 目录,lnmp 是 sites-enable 目录)建立两个新站点配置文件:
sub.mysite.com.conf
server { listen 80; server_name sub.mysite.com; if ($host ~ "sub.mysite.com$") { rewrite ^/(.)$ https://sub.mysite.com/ permanent; } } server { listen 127.0.0.1:446 ssl http2; servername sub.mysite.com; sslcertificate '/root/cfg/ssl/fullchain.cer'; sslcertificatekey '/root/cfg/ssl/mysite.com.key'; sslprotocols TLSv1.1 TLSv1.2 TLSv1.3; sslpreferserverciphers on; sslsessiontimeout '64m'; index index.php index.html index.htm default.php default.htm default.html; root /www/wwwroot/sub.mysite.com; #禁止访问的文件或目录 location ~ ^/(.user.ini|.htaccess|.git|.svn|.project|LICENSE|README.md) { return 404; } access_log off; }
sc.mysite.com.conf
server { listen 80; server_name sc.mysite.com; if ($host ~ "sc.mysite.com$") { rewrite ^/(.)$ https://sc.mysite.com/ permanent; } } server { listen 127.0.0.1:447 ssl http2; servername sc.mysite.com; sslcertificate '/root/cfg/ssl/fullchain.cer'; sslcertificatekey '/root/cfg/ssl/mysite.com.key'; sslprotocols TLSv1.1 TLSv1.2 TLSv1.3; sslpreferserverciphers on; sslsessiontimeout '64m'; index index.php index.html index.htm default.php default.htm default.html; root /www/wwwroot/sc.mysite.com; #反代后台 location / { proxy_pass http://127.0.0.1:25500; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; } #禁止访问的文件或目录 location ~ ^/(.user.ini|.htaccess|.git|.svn|.project|LICENSE|README.md) { return 404; } access_log off; }
由于我们之前申请的是泛域名证书,所以这里的虚拟站点都可以用一样的证书和密匙。
SubConverter后台搭建
下载并解压后端程序
cd /root/src
wget https://github.com/tindy2013/subconverter/releases/download/v0.7.0/subconverter_linux64.tar.gz
tar xvf subconverter_linux64.tar.gz
完成以后,在 /root/src 文件夹下会多出一个 subconverter 的文件夹,这个就是我们的后端程序
修改配置文件参数
现在我们需要修改后端配置文件中的一些参数
cd subconverter
cp pref.example.ini pref.ini
然后修改这个配置文件: /root/src/subconverter/pref.ini ,找到如下参数进行修改
api_access_token=123123dfsdsdfsdfsdf #api 默认没开启,这里随意设置
managed_config_prefix=https://suc.mysite.com #设置成我们刚刚解析的后端域名
listen=127.0.0.1 #这里改成 127.0.0.1 进行反代
接下来我们需要创建一个服务,让 VPS 每次重启或是开机自动运行后端程序
systemctl edit subconverter --full --force
贴入以下内容,保存。
[Unit] Description=A API For Subscription Convert After=network.target [Service] Type=simple ExecStart=/root/src/subconverter/subconverter WorkingDirectory=/root/src/subconverter Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
检查运行状态以及设置开机自启
systemctl enable --now subconverter
systemctl status subconverter
到这里,后端也就搭建完毕了,因为之前已经做好反代,我们现在可以在浏览器里面访问我们的后端了 https://suc.mysite.com, 成功会返回 subconverter 版本号。
全文完。