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
5 changed files with 221 additions and 106 deletions

View File

@@ -52,10 +52,9 @@ jobs:
- name: Build and push Docker image
run: |
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 }}:latest \
--build-arg VERSION=${{ env.VERSION }} \
-f Dockerfile .
env:
GHCR_PUBLIC: true
GHCR_PUBLIC: true

View File

@@ -1,6 +1,7 @@
#!/bin/bash
# HubProxy 一键安装脚本 (Gitea 私人仓库版)
# HubProxy 一键安装脚本
# 支持自动下载最新版本或使用本地文件安装
set -e
# 颜色定义
@@ -8,104 +9,205 @@ RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
NC='\033[0m' # No Color
# 配置信息
VERSION="v1.2.1"
# 配置
REPO="sky22333/hubproxy"
GITHUB_API="https://api.github.com/repos/${REPO}"
GITHUB_RELEASES="${GITHUB_API}/releases"
SERVICE_NAME="hubproxy"
# 按照你的习惯,安装在 /opt如果你想完全放在 /vol1 下也可以修改此处
INSTALL_DIR="/opt/hubproxy"
INSTALL_DIR="/opt/hubproxy"
CONFIG_FILE="config.toml"
BINARY_NAME="hubproxy"
LOG_DIR="/var/log/hubproxy"
TEMP_DIR="/tmp/hubproxy-install"
echo -e "${BLUE}HubProxy 一键安装脚本 - 来自 Gitea 私人仓库${NC}"
echo -e "${BLUE}HubProxy 一键安装脚本${NC}"
echo "================================================="
# 1. 权限检查
# 检查是否以root权限运行
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}此脚本需要 root 权限运行${NC}"
echo -e "${RED}此脚本需要root权限运行${NC}"
echo "请使用: sudo $0"
exit 1
fi
# 2. 检测系统架构并匹配你的 Gitea 链接
arch=$(uname -m)
case $arch in
x86_64)
ARCH="amd64"
DOWNLOAD_URL="https://git.vps3344521.xyz/3344/hubproxy/releases/download/v1.2.1/hubproxy-v1.2.1-linux-amd64.tar.gz"
;;
aarch64|arm64)
ARCH="arm64"
DOWNLOAD_URL="https://git.vps3344521.xyz/3344/hubproxy/releases/download/v1.2.1/hubproxy-v1.2.1-linux-arm64.tar.gz"
;;
*)
echo -e "${RED}不支持的架构: $arch${NC}"
exit 1
;;
esac
# 检测系统架构
detect_arch() {
local arch=$(uname -m)
case $arch in
x86_64)
echo "amd64"
;;
aarch64|arm64)
echo "arm64"
;;
*)
echo -e "${RED}不支持的架构: $arch${NC}"
exit 1
;;
esac
}
echo -e "${BLUE}检测到架构: ${ARCH}${NC}"
echo -e "${BLUE}准备从 Gitea 下载...${NC}"
ARCH=$(detect_arch)
echo -e "${BLUE}检测到架构: linux-${ARCH}${NC}"
# 3. 安装必要工具
for cmd in curl tar; do
if ! command -v $cmd &> /dev/null; then
echo -e "${YELLOW}正在安装依赖 $cmd...${NC}"
apt update && apt install -y $cmd
fi
done
# 4. 执行下载
rm -rf "${TEMP_DIR}" && mkdir -p "${TEMP_DIR}"
cd "${TEMP_DIR}"
echo -e "${YELLOW}正在下载: ${DOWNLOAD_URL}${NC}"
curl -L -o "hubproxy.tar.gz" "${DOWNLOAD_URL}"
# 5. 解压 (根据你提供的包结构,通常解压后是一个目录或直接是二进制文件)
tar -xzf "hubproxy.tar.gz"
# 进入解压出的目录(如果压缩包里有 hubproxy 文件夹的话)
[ -d "hubproxy" ] && cd hubproxy
# 6. 配置服务环境
echo -e "${BLUE}配置安装目录: ${INSTALL_DIR}${NC}"
mkdir -p "${INSTALL_DIR}"
cp "${BINARY_NAME}" "${INSTALL_DIR}/"
chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
# 如果有默认配置文件也一并复制
if [ -f "config.toml" ]; then
if [ ! -f "${INSTALL_DIR}/config.toml" ]; then
cp "config.toml" "${INSTALL_DIR}/"
# 检查是否为本地安装模式
if [ -f "${BINARY_NAME}" ]; then
echo -e "${BLUE}发现本地文件,使用本地安装模式${NC}"
LOCAL_INSTALL=true
else
echo -e "${BLUE}本地无文件,使用自动下载模式${NC}"
LOCAL_INSTALL=false
# 检查依赖
missing_deps=()
for cmd in curl jq tar; do
if ! command -v $cmd &> /dev/null; then
missing_deps+=($cmd)
fi
done
if [ ${#missing_deps[@]} -gt 0 ]; then
echo -e "${YELLOW}检测到缺少依赖: ${missing_deps[*]}${NC}"
echo -e "${BLUE}正在自动安装依赖...${NC}"
apt update && apt install -y curl jq
if [ $? -ne 0 ]; then
echo -e "${RED}依赖安装失败${NC}"
exit 1
fi
# 重新检查依赖
for cmd in curl jq tar; do
if ! command -v $cmd &> /dev/null; then
echo -e "${RED}依赖安装后仍缺少: $cmd${NC}"
exit 1
fi
done
echo -e "${GREEN}依赖安装成功${NC}"
fi
fi
# 7. 写入 Systemd 服务
echo -e "${BLUE}正在创建 Systemd 服务...${NC}"
cat <<EOF > /etc/systemd/system/${SERVICE_NAME}.service
[Unit]
Description=HubProxy Service
After=network.target
# 自动下载功能
if [ "$LOCAL_INSTALL" = false ]; then
echo -e "${BLUE}获取最新版本信息...${NC}"
LATEST_RELEASE=$(curl -s "${GITHUB_RELEASES}/latest")
if [ $? -ne 0 ]; then
echo -e "${RED}无法获取版本信息${NC}"
exit 1
fi
[Service]
Type=simple
WorkingDirectory=${INSTALL_DIR}
ExecStart=${INSTALL_DIR}/${BINARY_NAME}
Restart=always
RestartSec=5
VERSION=$(echo "$LATEST_RELEASE" | jq -r '.tag_name')
if [ "$VERSION" = "null" ]; then
echo -e "${RED}无法解析版本信息${NC}"
exit 1
fi
[Install]
WantedBy=multi-user.target
EOF
echo -e "${GREEN}最新版本: ${VERSION}${NC}"
# 8. 启动服务
# 构造下载URL
ASSET_NAME="hubproxy-${VERSION}-linux-${ARCH}.tar.gz"
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/${ASSET_NAME}"
echo -e "${BLUE}下载: ${ASSET_NAME}${NC}"
# 创建临时目录并下载
rm -rf "${TEMP_DIR}"
mkdir -p "${TEMP_DIR}"
cd "${TEMP_DIR}"
curl -L -o "${ASSET_NAME}" "${DOWNLOAD_URL}"
if [ $? -ne 0 ]; then
echo -e "${RED}下载失败${NC}"
exit 1
fi
# 解压
tar -xzf "${ASSET_NAME}"
if [ $? -ne 0 ] || [ ! -d "hubproxy" ]; then
echo -e "${RED}解压失败${NC}"
exit 1
fi
cd hubproxy
echo -e "${GREEN}下载完成${NC}"
fi
echo -e "${YELLOW}开始安装 HubProxy...${NC}"
# 停止现有服务(如果存在)
if systemctl is-active --quiet ${SERVICE_NAME} 2>/dev/null; then
echo -e "${YELLOW}停止现有服务...${NC}"
systemctl stop ${SERVICE_NAME}
fi
# 备份现有配置(如果存在)
CONFIG_BACKUP_EXISTS=false
if [ -f "${INSTALL_DIR}/${CONFIG_FILE}" ]; then
echo -e "${BLUE}备份现有配置...${NC}"
cp "${INSTALL_DIR}/${CONFIG_FILE}" "${TEMP_DIR}/config.toml.backup"
CONFIG_BACKUP_EXISTS=true
fi
# 1. 创建目录结构
echo -e "${BLUE}创建目录结构${NC}"
mkdir -p ${INSTALL_DIR}
mkdir -p ${LOG_DIR}
chmod 755 ${INSTALL_DIR}
chmod 755 ${LOG_DIR}
# 2. 复制二进制文件
echo -e "${BLUE}复制二进制文件${NC}"
cp "${BINARY_NAME}" "${INSTALL_DIR}/"
chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
# 3. 复制配置文件
echo -e "${BLUE}复制配置文件${NC}"
if [ -f "${CONFIG_FILE}" ]; then
if [ "$CONFIG_BACKUP_EXISTS" = false ]; then
cp "${CONFIG_FILE}" "${INSTALL_DIR}/"
echo -e "${GREEN}配置文件复制成功${NC}"
else
echo -e "${YELLOW}保留现有配置文件${NC}"
fi
else
echo -e "${YELLOW}配置文件不存在,将使用默认配置${NC}"
fi
# 5. 安装systemd服务文件
echo -e "${BLUE}安装systemd服务文件${NC}"
cp "${SERVICE_NAME}.service" "/etc/systemd/system/"
systemctl daemon-reload
systemctl enable ${SERVICE_NAME}
systemctl restart ${SERVICE_NAME}
# 9. 清理并完成
rm -rf "${TEMP_DIR}"
echo "-------------------------------------------------"
echo -e "${GREEN}HubProxy 安装成功!${NC}"
echo -e "安装路径: ${INSTALL_DIR}"
echo -e "服务状态: ${BLUE}systemctl status ${SERVICE_NAME}${NC}"
# 6. 恢复配置文件(如果有备份)
if [ "$CONFIG_BACKUP_EXISTS" = true ]; then
echo -e "${BLUE}恢复配置文件...${NC}"
cp "${TEMP_DIR}/config.toml.backup" "${INSTALL_DIR}/${CONFIG_FILE}"
fi
# 7. 启用并启动服务
echo -e "${BLUE}启用并启动服务${NC}"
systemctl enable ${SERVICE_NAME}
systemctl start ${SERVICE_NAME}
# 8. 清理临时文件
if [ "$LOCAL_INSTALL" = false ]; then
echo -e "${BLUE}清理临时文件...${NC}"
cd /
rm -rf "${TEMP_DIR}"
fi
# 9. 检查服务状态
sleep 2
if systemctl is-active --quiet ${SERVICE_NAME}; then
echo ""
echo -e "${GREEN}HubProxy 安装成功!${NC}"
echo -e "${GREEN}默认运行端口: 5000${NC}"
echo -e "${GREEN}配置文件路径: ${INSTALL_DIR}/${CONFIG_FILE}${NC}"
else
echo -e "${RED}服务启动失败${NC}"
echo "查看错误日志: sudo journalctl -u ${SERVICE_NAME} -f"
exit 1
fi

View File

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

View File

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

View File

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