Repository: AlistGo/alist (language: go)

Issue:
对象存储内网接入
### Please make sure of the following things

- [X] I have read the [documentation](https://alist.nn.ci).
- [X] I'm sure there are no duplicate issues or discussions.
- [X] I'm sure this feature is not implemented.
- [X] I'm sure it's a reasonable and popular requirement.

### Description of the feature / 需求描述

我的alist安装在阿里云的服务器上，alist和对象存储在同一个可用区（杭州1），怎么内网接入，端点修改了之后下载链接有问题，他会去重定向到阿里云的私网端点，很显然是访问不到的： 由于使用内网后台上传不受上传带宽以及无费用，请问能否添加支持

### Suggested solution / 实现思路

可以配置内网和公网接入点，下载链接使用公网接入点即可

### Additional context / 附件

_No response_


Discussion / hints:
用本地代理不就可以了？
> 用本地代理不就可以了？

下载速度受限服务器上传带宽
> > 用本地代理不就可以了？
> 
> 下载速度受限服务器上传带宽

那我觉得那个“使用代理地址”功能可能能满足你这个需求，虽然我没研究过
> > > 用本地代理不就可以了？
> > 
> > 
> > 下载速度受限服务器上传带宽
> 
> 那我觉得那个“使用代理地址”功能可能能满足你这个需求，虽然我没研究过

我试了不行，这个是代理，正常应该需要重写下载链接
如果增加一种代理模式，要求用户提供一个lua脚本，这个lua脚本输入用户访问的文件路径，输出重定向地址，然后alist会把这个输出的重定向地址返回到前端，能解决你这个需求吗
之前搜到过一款网盘产品是可以设置内网接入点，只要服务器和对象存储在一个内网环境下，服务端和对象存储通讯是内网，他那款产品是可以在对象存储这边配置两个接入点，一个公网一个私网，基本只有用户下载的时候才需要用公网接入点，因为我这边设置成私网接入点后预览什么的都没遇到问题
![image](https://github.com/user-attachments/assets/3845a916-00ed-465b-90f6-558a8d34f748)


Fix patch:
diff --git a/drivers/s3/driver.go b/drivers/s3/driver.go
index 2b72d78980f..82c050a1fe8 100644
--- a/drivers/s3/driver.go
+++ b/drivers/s3/driver.go
@@ -99,8 +99,12 @@ func (d *S3) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*mo
 	var link model.Link
 	var err error
 	if d.CustomHost != "" {
-		err = req.Build()
-		link.URL = req.HTTPRequest.URL.String()
+		if d.EnableCustomHostPresign {
+			link.URL, err = req.Presign(time.Hour * time.Duration(d.SignURLExpire))
+		} else {
+			err = req.Build()
+			link.URL = req.HTTPRequest.URL.String()
+		}
 		if d.RemoveBucket {
 			link.URL = strings.Replace(link.URL, "/"+d.Bucket, "", 1)
 		}
diff --git a/drivers/s3/meta.go b/drivers/s3/meta.go
index 4436c61508e..4de4b60a690 100644
--- a/drivers/s3/meta.go
+++ b/drivers/s3/meta.go
@@ -14,6 +14,7 @@ type Addition struct {
 	SecretAccessKey          string `json:"secret_access_key" required:"true"`
 	SessionToken             string `json:"session_token"`
 	CustomHost               string `json:"custom_host"`
+	EnableCustomHostPresign  bool   `json:"enable_custom_host_presign"`
 	SignURLExpire            int    `json:"sign_url_expire" type:"number" default:"4"`
 	Placeholder              string `json:"placeholder"`
 	ForcePathStyle           bool   `json:"force_path_style"`


Test patch: