最近捡垃圾捡了台 homelab,就寻思着能不能把 H@H 放到这上面跑,这样就可以直接使用 H@H Downloader 将画廊直接下载到本地了。

然而测了一下家宽,发现是 NAT4,广东广电真是有够烂的,只能用公网服务器来转发了。研究了一下,确实可行,前提是这台服务器允许非备案域名的非标准端口访问

以下为配置步骤,仅供参考。

服务器配置

服务器上我选择使用 gost 搭建一个 socks5 代理,用于代理内网的 H@H 请求,再用 frp 搭建一个反向代理,用于将服务器上接受到的请求转发回内网的 H@H。

总共需放行三个端口:

  • frp 服务器端口:1234
  • H@H 监听端口:2345
  • socks5 代理端口:3456

gost 的启动非常简单:

1
docker run -d --restart=always --network=host --name gost ginuerzh/gost -L=username:password@:3456

frp 的配置也没什么难度:

frps.toml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 你的 frp 端口
bindPort = 1234
# 你的 H@H 端口
allowPorts = [
  { single = 2345 }
]

[auth]
method = "token"
token = "your_secret_token"
1
docker run -d --restart=always --network=host -v $PWD/frps.toml:/etc/frp/frps.toml --name frps snowdreamtech/frps

本地配置

辣鸡 java 竟然没有办法指定需要认证的 socks5 代理,因此需要在本地再启动一个 gost 转发一下我们的代理,去掉认证:

1
docker run --name=gost -d --restart=always --network=host ginuerzh/gost -L=:2345 -F=socks5://username:[email protected]:2345

然后再配置一下 frp,将本地的 H@H 端口映射出去:

frpc.toml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ServerAddr = "1.2.3.4"
serverPort = 1234

[auth]
method = "token"
token = "your_secret_token"

[[proxies]]
name = "hath"
type = "tcp"
localIP = "127.0.0.1"
localPort = 2345
remotePort = 2345
1
docker run --network=host -d --restart=always -v $PWD/frpc.toml:/etc/frp/frpc.toml --name frpc snowdreamtech/frpc

最后,启动 H@H:

1
java -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=3456 -jar HentaiAtHome.jar --disable-ip-origin-check

分流

跑了一段时间,发现不是很顺畅,因为中转服务在国内,但是 H@H 下载时常常会连到国外的节点,然后就卡在那里反复重试。

那能不能分流呢?注意到H@H 网络中的节点基本上在 .hath.network 这个域名下,于是立马想到根据域名分流——然后就浪费了我半天时间,还踩了 gost 的镜像是 v2 但文档是 v3 的坑。

这辣鸡 java 设置的代理竟然不支持转发 dns 请求,代理根本拿不到域名!不支持认证,也不能转发 DNS 请求,这代理功能简直就是个残废,java 印象–。

最后没办法,只能改 H@H 源码了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
diff --git a/src/hath/base/FileDownloader.java b/src/hath/base/FileDownloader.java
index d174c05..536f0e8 100644
--- a/src/hath/base/FileDownloader.java
+++ b/src/hath/base/FileDownloader.java
@@ -151,7 +151,13 @@ public class FileDownloader implements Runnable {
                                        Out.debug("Connecting to " + source.getHost() + "...");

                                        // should return a HttpURLConnection for http and HttpsURLConnection for https
-                                       URLConnection connection = source.openConnection();
+                                       URLConnection connection;
+                                       if (source.getPath().endsWith("/hathdl")) {
+                                               Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8081));
+                                               connection = source.openConnection(proxy);
+                                       } else {
+                                               connection = source.openConnection();
+                                       }

                                        connection.setConnectTimeout(5000);

两个坑点:

  1. 使用了请求路径来判断是否需要代理,因为有些节点没有域名,估计是源站。
  2. 尽管这里看上去就是专门下载文件的模块,但实际上它还会用于首次启动时向服务端汇报 ip,所以不能代理所有请求。