惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
G
Google Developers Blog
有赞技术团队
有赞技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Blog — PlanetScale
Blog — PlanetScale
罗磊的独立博客
博客园 - 聂微东
V
Visual Studio Blog
博客园_首页
D
DataBreaches.Net
腾讯CDC
I
InfoQ
F
Fortinet All Blogs
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
月光博客
月光博客
Recent Announcements
Recent Announcements
MongoDB | Blog
MongoDB | Blog
C
Check Point Blog

繁星点点

最新轻量级龙虾部署教程 通过netboot.xyz重装系统 giffgaff卡保号教程 Llinux系统中全新透明代理方案(可代理所有出站流量) tailscale开启子网路由常见的坑 OpenWrt固件编译 解决UFW和Docker的问题 使用PGP的非对称算法加密文件 NSSM工具把任意exe程序注册为Windows后台服务 轻量级简约端口转发rinetd 安卓IDE的安装和使用 IP信息查询网站汇总 热点共享代理教程 SSH使用密钥认证登录详细解释 Debian系统公网IP出口切换指南,适用多IP服务器 Windows系统安装Scoop包管理器 安卓Flutter开发学习笔记 使用手机搭建节点服务端 关于github提交记录泄露真实邮箱的处理办法 anytls协议部署教程 caddy给域名用上ECH加密 通过gitlab流水线自动备份仓库 通过CF-Workers代理访问网站 低配机器使用alpine系统跑docker 端口敲门教程 3x-ui面板通过api管理示例 nmap端口扫描 数据库常用命令 snap和winget包管理器 Git推送GitHub常用命令
解决CF反代Docker失效的问题
2024-11-16 · via 繁星点点

最近国内拉取镜像时发现之前的worker反代的docker加速用不了了,报错为auth.docker.io/token这个域名的问题。

经过抓包发现,现在拉取镜像会请求三个域名,顺序是先请求了registry-1.docker.io得到了 401http 状态码后转去访问了auth.docker.io得到了 Authorization字段以后重新请求 registry-1.docker.io,获取源数据后被 307 转发到了 production.cloudflare.docker.com 上。


由此看出auth.docker.io是用于验证鉴权的域名,production.cloudflare.docker.com 是用于下载镜像文件的域名,这些域名我测了一下全都被墙了。

之前的CF代码只反代了registry-1.docker.io,所以导致失效,既然找到问题所在就比较好解决了。

下面贴出我修改的worker.js代码:

import HTML from './docker.html';

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const host = request.headers.get("host");
    
    const registryHost = "registry-1.docker.io";
    const authHost = "auth.docker.io";
    const productionHost = "production.cloudflare.docker.com";

    // 处理认证请求
    if (url.pathname.startsWith('/token')) {
      const headers = new Headers(request.headers);
      headers.set('host', authHost);
      
      const authUrl = `https://${authHost}${url.pathname}${url.search}`;
      const authRequest = new Request(authUrl, {
        method: request.method,
        headers: headers,
        body: request.body,
        redirect: "follow",
      });

      const response = await fetch(authRequest);
      const responseHeaders = new Headers(response.headers);
      responseHeaders.set('access-control-allow-origin', host);
      responseHeaders.set('access-control-allow-headers', 'Authorization');
      
      return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: responseHeaders,
      });
    }
    
    // 处理 registry v2 请求
    if (url.pathname.startsWith('/v2/')) {
      const headers = new Headers(request.headers);
      headers.set('host', registryHost);
      
      const registryUrl = `https://${registryHost}${url.pathname}${url.search}`;
      const registryRequest = new Request(registryUrl, {
        method: request.method,
        headers: headers,
        body: request.body,
        redirect: "follow",
      });

      const response = await fetch(registryRequest);
      const responseHeaders = new Headers(response.headers);
      responseHeaders.set('access-control-allow-origin', host);
      responseHeaders.set('access-control-allow-headers', 'Authorization');

      // 修改认证头,将认证请求指向主域名
      const wwwAuth = responseHeaders.get('www-authenticate');
      if (wwwAuth) {
        const newWwwAuth = wwwAuth
          .replace('https://auth.docker.io', `https://${host}`)
          .replace('https://auth.hub.docker.com', `https://${host}`);
        responseHeaders.set('www-authenticate', newWwwAuth);
      }

      // 修改重定向地址
      const location = responseHeaders.get('location');
      if (location) {
        const newLocation = location
          .replace('https://production.cloudflare.docker.com', `https://${host}`);
        responseHeaders.set('location', newLocation);
      }

      return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: responseHeaders,
      });
    }

    // 处理默认请求
    return new Response(HTML.replace(/{{host}}/g, host), {
      status: 200,
      headers: {
        "content-type": "text/html"
      }
    });
  }
}

新建一个docker.html前端文件,填入以下代码,部署后记得绑定自定义域,因为默认的worker域名是被墙的,其他的默认即可。

docker.html文件的代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Docker Hub 镜像加速</title>
        <style>
        html, body {
            height: 100%;
        }
        body {
            font-family: "Roboto", "Helvetica", "Arial", sans-serif;
            font-size: 16px;
            color: #333;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
        }
        .container {
            margin: 0 auto;
            max-width: 600px;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
        }
        .header {
            background-color: #438cf8;
            color: white;
            padding: 10px;
            display: flex;
            align-items: center;
        }
        h1 {
            font-size: 24px;
            margin: 0;
            padding: 0;
        }
        .content {
            padding: 32px;
            flex-grow: 1;
        }
        pre {
            background-color: #f4f4f4;
            padding: 16px;
            border-radius: 4px;
            position: relative;
            overflow: auto;
            margin-bottom: 16px;
        }
        code {
            display: block;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        .copy-button {
            position: absolute;
            top: 8px;
            right: 8px;
            padding: 4px 8px;
            background-color: #438cf8;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
        }
        .footer {
            padding: 5px;
            text-align: center;
            font-size: 15px;
        }
        .footer a {
            color: #438cf8;
            text-decoration: none;
        }
        </style>
        <script>
            function copyCode(button) {
                const code = button.previousElementSibling.innerText;
                navigator.clipboard.writeText(code).then(function() {
                    button.innerText = "已复制";
                    setTimeout(function() {
                        button.innerText = "复制";
                    }, 2000);
                });
            }
        </script>
    </head>
    <body>
        <div class="header">
            <h1>Docker Hub 镜像加速</h1>
        </div>
        <div class="container">
            <div class="content">
                <h2>Docker Hub 镜像加速</h2>
                <p>为了加速镜像拉取,你可以使用以下命令设置 registry mirror</p>
                <pre><code>sudo mkdir -p /etc/docker</code><button class="copy-button" onclick="copyCode(this)">复制</button></pre>
                <pre><code>sudo tee /etc/docker/daemon.json &lt;&lt;EOF
{
    "registry-mirrors": ["https://{{host}}"]
}
EOF</code><button class="copy-button" onclick="copyCode(this)">复制</button></pre>
                <pre><code>sudo systemctl daemon-reload</code><button class="copy-button" onclick="copyCode(this)">复制</button></pre>
                <pre><code>sudo systemctl restart docker</code><button class="copy-button" onclick="copyCode(this)">复制</button></pre>
                <br>
                <p>不用设置环境也可以直接使用,用法示例:</p>
                <pre><code>docker pull {{host}}/library/mysql:5.7</code><button class="copy-button" onclick="copyCode(this)">复制</button></pre>
                <p>说明:library是一个特殊的命名空间,它代表的是官方镜像。如果是某个用户的镜像就把library替换为镜像的用户名</p>
            </div>
        </div>
        <div class="footer">
            <p><a href="https://blog.52013120.xyz/post/29.html" target="_blank">代码地址</a></p>
        </div>
    </body>
</html>

  • 基于这个思路我还写了caddy反代的配置,caddy自动配置SSL证书可太香了,并且不依赖CF,可以自己部署在服务器上。
hub.example.com {
    handle /v2/* {
        reverse_proxy https://registry-1.docker.io {
            header_up Host {http.reverse_proxy.upstream.hostport}
            header_down WWW-Authenticate "https://auth.docker.io" "https://{http.request.host}"
            header_down Location "https://production.cloudflare.docker.com" "https://{http.request.host}"
        }
    }

    handle /token* {
        reverse_proxy https://auth.docker.io {
            header_up Host {http.reverse_proxy.upstream.hostport}
        }
    }

    handle /* {
        reverse_proxy https://production.cloudflare.docker.com {
            header_up Host {http.reverse_proxy.upstream.hostport}
        }
    }
}

记得第一行的hub.example.com替换为你的域名

  • caddy反代ghcr.io
example.com {
    handle /v2/* {
        reverse_proxy https://ghcr.io {
            header_up Host {http.reverse_proxy.upstream.hostport}
            header_down WWW-Authenticate "https://ghcr.io" "https://{http.request.host}"
            header_down Location "https://pkg-containers.githubusercontent.com" "https://{http.request.host}"
        }
    }

    handle /token* {
        reverse_proxy https://ghcr.io {
            header_up Host {http.reverse_proxy.upstream.hostport}
        }
    }

    handle /* {
        reverse_proxy https://pkg-containers.githubusercontent.com {
            header_up Host {http.reverse_proxy.upstream.hostport}
        }
    }
}