由于 Cloudflare Workers 的域名被墙,首先需要将自己的域名代理到 Cloudflare。

创建worker

随便起一个名字,然后部署

然后进到刚刚部署的worker里,点击编辑代码

编辑worker

新建一个文件index.html

填入以下代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Minja'自用Docker Hub 镜像加速</title>
        <style>
        html, body {
            height: 100%;
        }
        body {
            font-family: "Roboto", "Helvetica", "Arial", sans-serif;
            font-size: 16px;
            color: #7ebdd6;
            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>Minja'自用Docker Hub 镜像加速</h1>
        </div>
        <div class="container">
            <div class="content">
                <h2>linux使用教程</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>直接 docker pull使用教程</p>
                <pre><code>docker pull {{host}}/library/mysql:5.7</code><button class="copy-button" onclick="copyCode(this)">复制</button></pre>
            </div>
        </div>
        <div class="footer">
            <p><a href="https://minja.fun/archives/tong-guo-cloudflarezi-jian-dockerjing-xiang" target="_blank">代码地址</a></p>
            <p>Powered by Cloudflare Workers</p>
        </div>
    </body>
</html>

然后编辑worker.js

import HTML from './index.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"
      }
    });
  }
}

点击右上角保存

部署worker

选择自己刚修改的版本部署

测试访问

部署成功后,绑定一个域名

如果域名由cloudflare托管,会自动创建DNS记录。

然后测试访问

复制docker pull代码,测试能不能pull下载镜像。