使用Cloudflare worker搭建镜像网站
主要参考了文章末尾参考的前两篇博客进行搭建,本来还想参考第三篇镜像一下dockerhub网页,但是在镜像完github之后立即遭到海外公司的攻击,以及邮件警告,所以暂时去除镜像页面的功能
要求
为了实现多仓库代理需要有自己的域名,并将多个二级域名(当然用一级域名也行)解析到同一个worker上,以域名example.com为例
需要将docker.example.com,quay.example.com,gcr.example.com,ghcr.example.com解析到同一个worker
代码
代码部分包括一个js文件和一个html文件,原教程中的html被命名为docker.html,使用改名称会无法保存,修改为其他名称后可以正常保存,不确定是cloudflare限制还是版本更新的bug.
代码中添加了根据域名前缀选择不同docker仓库的功能,同时在访问非docker前缀时会自动跳转到docker.example.com
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>镜像使用说明</title> <style> body { font-family: 'Roboto', sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; } .header { background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; padding: 20px 0; text-align: center; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .container { max-width: 800px; margin: 40px auto; padding: 20px; background-color: #fff; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 10px; } .content { margin-bottom: 20px; } .footer { text-align: center; padding: 20px 0; background-color: #333; color: #fff; } pre { background-color: #272822; color: #f8f8f2; padding: 15px; border-radius: 5px; overflow-x: auto; } code { font-family: 'Source Code Pro', monospace; } a { color: #4CAF50; text-decoration: none; } a:hover { text-decoration: underline; } @media (max-width: 600px) { .container { margin: 20px; padding: 15px; } .header { padding: 15px 0; } } </style> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&family=Source+Code+Pro:wght@400;700&display=swap" rel="stylesheet"> </head> <body> <div class="header"> <h1>镜像使用说明</h1> </div> <div class="container"> <div class="content"> <p>为了加速镜像拉取,你可以使用以下命令设置 registry mirror:</p> <pre><code>sudo tee /etc/docker/daemon.json <<EOF { "registry-mirrors": ["https://docker.example.com"] } EOF</code></pre> <p>为了避免 Worker 用量耗尽,你可以手动 pull 镜像然后 re-tag 之后 push 至本地镜像仓库:</p> <pre><code>docker pull docker.example.com/library/alpine:latest # 拉取 library 镜像 docker pull docker.example.com/coredns/coredns:latest # 拉取 coredns 镜像</code></pre> </div> <div> <p>对于quay.io,gcr.io,ghcr.io可以使用quay.example.com,gcr.example.com,ghcr.example.com替换原域名实现加速</p> </div> </div> <div class="footer"> <p>Powered by Cloudflare Workers</p> </div> </body> </html>
|
worker.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import HTML from './index.html'; export default { async fetch(request) { const url = new URL(request.url); const path = url.pathname; const originalHost = request.headers.get("host"); let registryHost; if (originalHost.startsWith("docker")) { registryHost = "registry-1.docker.io"; } if (originalHost.startsWith("quay")) { registryHost = "quay.io"; } if (originalHost.startsWith("gcr")) { registryHost = "gcr.io"; } if (originalHost.startsWith("ghcr")) { registryHost = "ghcr.io"; } if (path.startsWith("/v2/")) { const headers = new Headers(request.headers); headers.set("host", registryHost); const registryUrl = `https://${registryHost}${path}`; const registryRequest = new Request(registryUrl, { method: request.method, headers: headers, body: request.body, redirect: "follow", }); const registryResponse = await fetch(registryRequest); const responseHeaders = new Headers(registryResponse.headers); responseHeaders.set("access-control-allow-origin", originalHost); responseHeaders.set("access-control-allow-headers", "Authorization"); return new Response(registryResponse.body, { status: registryResponse.status, statusText: registryResponse.statusText, headers: responseHeaders, }); } else if (!originalHost.startsWith("docker") && path == '/') { let newHost = originalHost.replace(/([^\.]+\.)/, `https://docker.`); return Response.redirect(newHost, 302) } else { return new Response(HTML, { status: 200, headers: { "content-type": "text/html" } }); } } }
|
参考
- Ling的博客带页面的dockerhub镜像
- 且炼时光多仓库镜像
- 小王爷网页镜像