3 Commits

Author SHA1 Message Date
starry
6ff610f5af Update docker-ghcr.yml 2026-01-11 00:09:48 +08:00
user123
7534c64197 https 2026-01-10 23:54:04 +08:00
user123
5928a0a9e4 Default Registry 2026-01-10 23:46:26 +08:00
4 changed files with 38 additions and 25 deletions

View File

@@ -52,10 +52,9 @@ jobs:
- name: Build and push Docker image - name: Build and push Docker image
run: | run: |
docker buildx build --push \ docker buildx build --push \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64 \
--tag ghcr.io/${{ env.REPO_LOWER }}:${{ env.VERSION }} \ --tag ghcr.io/${{ env.REPO_LOWER }}:${{ env.VERSION }} \
--tag ghcr.io/${{ env.REPO_LOWER }}:latest \
--build-arg VERSION=${{ env.VERSION }} \ --build-arg VERSION=${{ env.VERSION }} \
-f Dockerfile . -f Dockerfile .
env: env:
GHCR_PUBLIC: true GHCR_PUBLIC: true

View File

@@ -83,6 +83,12 @@ authHost = "registry.k8s.io"
authType = "anonymous" authType = "anonymous"
enabled = true enabled = true
# Default Registry
[defaultRegistry]
upstream = "registry-1.docker.io"
authHost = "auth.docker.io"
enabled = true
[tokenCache] [tokenCache]
# 是否启用缓存(同时控制Token和Manifest缓存)显著提升性能 # 是否启用缓存(同时控制Token和Manifest缓存)显著提升性能
enabled = true enabled = true

View File

@@ -49,6 +49,8 @@ type AppConfig struct {
} `toml:"download"` } `toml:"download"`
Registries map[string]RegistryMapping `toml:"registries"` Registries map[string]RegistryMapping `toml:"registries"`
DefaultRegistry RegistryMapping `toml:"defaultRegistry"`
TokenCache struct { TokenCache struct {
Enabled bool `toml:"enabled"` Enabled bool `toml:"enabled"`

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"regexp"
"strings" "strings"
"time" "time"
@@ -16,6 +17,8 @@ import (
"hubproxy/utils" "hubproxy/utils"
) )
var realmRegex = regexp.MustCompile(`realm="(https?://)([^/"]+)(/?[^"]*)"`)
// DockerProxy Docker代理配置 // DockerProxy Docker代理配置
type DockerProxy struct { type DockerProxy struct {
registry name.Registry registry name.Registry
@@ -68,7 +71,13 @@ var registryDetector = &RegistryDetector{}
// InitDockerProxy 初始化Docker代理 // InitDockerProxy 初始化Docker代理
func InitDockerProxy() { func InitDockerProxy() {
registry, err := name.NewRegistry("registry-1.docker.io") cfg := config.GetConfig()
upstream := "registry-1.docker.io"
if cfg.DefaultRegistry.Upstream != "" {
upstream = cfg.DefaultRegistry.Upstream
}
registry, err := name.NewRegistry(upstream)
if err != nil { if err != nil {
fmt.Printf("创建Docker registry失败: %v\n", err) fmt.Printf("创建Docker registry失败: %v\n", err)
return return
@@ -353,17 +362,21 @@ func (r *ResponseRecorder) Write(data []byte) (int, error) {
} }
func proxyDockerAuthOriginal(c *gin.Context) { func proxyDockerAuthOriginal(c *gin.Context) {
var authURL string cfg := config.GetConfig()
authHost := "auth.docker.io"
if cfg.DefaultRegistry.AuthHost != "" {
authHost = cfg.DefaultRegistry.AuthHost
}
if targetDomain, exists := c.Get("target_registry_domain"); exists { if targetDomain, exists := c.Get("target_registry_domain"); exists {
if mapping, found := registryDetector.getRegistryMapping(targetDomain.(string)); found { if mapping, found := registryDetector.getRegistryMapping(targetDomain.(string)); found {
authURL = "https://" + mapping.AuthHost + c.Request.URL.Path authHost = mapping.AuthHost
} else {
authURL = "https://auth.docker.io" + c.Request.URL.Path
} }
} else {
authURL = "https://auth.docker.io" + c.Request.URL.Path
} }
authURL := "https://" + authHost + c.Request.URL.Path
if c.Request.URL.RawQuery != "" { if c.Request.URL.RawQuery != "" {
authURL += "?" + c.Request.URL.RawQuery authURL += "?" + c.Request.URL.RawQuery
} }
@@ -406,10 +419,15 @@ func proxyDockerAuthOriginal(c *gin.Context) {
} }
} }
scheme := "http"
if c.Request.TLS != nil || c.GetHeader("X-Forwarded-Proto") == "https" {
scheme = "https"
}
for key, values := range resp.Header { for key, values := range resp.Header {
for _, value := range values { for _, value := range values {
if key == "Www-Authenticate" { if key == "Www-Authenticate" {
value = rewriteAuthHeader(value, proxyHost) value = rewriteAuthHeader(value, scheme, proxyHost)
} }
c.Header(key, value) c.Header(key, value)
} }
@@ -420,13 +438,8 @@ func proxyDockerAuthOriginal(c *gin.Context) {
} }
// rewriteAuthHeader 重写认证头 // rewriteAuthHeader 重写认证头
func rewriteAuthHeader(authHeader, proxyHost string) string { func rewriteAuthHeader(authHeader, scheme, proxyHost string) string {
authHeader = strings.ReplaceAll(authHeader, "https://auth.docker.io", "http://"+proxyHost) return realmRegex.ReplaceAllString(authHeader, fmt.Sprintf(`realm="%s://%s$3"`, scheme, proxyHost))
authHeader = strings.ReplaceAll(authHeader, "https://ghcr.io", "http://"+proxyHost)
authHeader = strings.ReplaceAll(authHeader, "https://gcr.io", "http://"+proxyHost)
authHeader = strings.ReplaceAll(authHeader, "https://quay.io", "http://"+proxyHost)
return authHeader
} }
// handleMultiRegistryRequest 处理多Registry请求 // handleMultiRegistryRequest 处理多Registry请求
@@ -605,12 +618,5 @@ func createUpstreamOptions(mapping config.RegistryMapping) []remote.Option {
remote.WithTransport(utils.GetGlobalHTTPClient().Transport), remote.WithTransport(utils.GetGlobalHTTPClient().Transport),
} }
// 预留将来不同Registry的差异化认证逻辑扩展点
switch mapping.AuthType {
case "github":
case "google":
case "quay":
}
return options return options
} }