使用Cloudflare实现自定义域名加速GitHub图床

前言:为什么选择Cloudflare?

方案优势对比

特性 jsDelivr方案 Cloudflare方案
国内访问速度 ❌ 1500ms+ ✅ 200ms
自定义域名 ❌ 不可用 ✅ 自动SSL证书
缓存控制 ❌ 固定策略 ✅ 多级可配置
安全防护 ❌ 无 ✅ WAF+DDoS防护

技术选型要点

  • GitHub原生存储保障数据安全(99.999999999%持久性)
  • Cloudflare全球加速网络(285个边缘节点)
  • 开发者友好集成(PicGo+Git+CI/CD)

Cloudflare解决方案优势

  1. 全球智能路由
    285个边缘节点实现智能分发,平均加载时间从1200ms优化至200ms。基于Anycast网络架构,自动选择最优访问路径。

  2. 智能缓存机制

graph LR
    A[用户请求] --> B{边缘缓存}
    B -- 命中 --> C[立即响应]
    B -- 未命中 --> D[回源GitHub]
    D --> E[缓存并响应]
  1. 域名与安全
  • 🛡️ 自动SSL证书管理
  • 🌐 自定义品牌域名
  • 📊 流量分析仪表盘
  • 🔐 集成WAF/DDoS防护
  • ⚡ 智能缓存优化

需要准备的:

  • 自己的域名
  • Cloudflare账号
  • GitHub账号

创建GitHub仓库并获取访问令牌

参考之前的创建图床步骤(参考《VSCode+PicGo打造无缝GitHub图床体验》):

  1. 创建私有仓库 blog-images
  2. 生成github的token:
    • 权限范围:仅repo
    • 访问权限:内容读写
  3. 安全存储Token至本地密码管理器

配置Cloudflare Worker

1. 创建Worker服务

2. 部署基础代码

3. 注入代理代码

使用以下代码替换默认Worker代码:

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// Website you intended to retrieve for users.
const upstream = "raw.githubusercontent.com";

// Custom pathname for the upstream website.
// (1) 填写代理的路径,格式为 /<用户>/<仓库名>/<分支>
const upstream_path = "****";

// github personal access token.
// (2) 填写github令牌
const github_token = "****";

// Website you intended to retrieve for users using mobile devices.
const upstream_mobile = upstream;

// Countries and regions where you wish to suspend your service.
const blocked_region = [];

// IP addresses which you wish to block from using your service.
const blocked_ip_address = ["0.0.0.0", "127.0.0.1"];

// Whether to use HTTPS protocol for upstream address.
const https = true;

// Whether to disable cache.
const disable_cache = false;

// Replace texts.
const replace_dict = {
$upstream: "$custom_domain",
};

addEventListener("fetch", (event) => {
event.respondWith(fetchAndApply(event.request));
});

async function fetchAndApply(request) {
const region = request.headers.get("cf-ipcountry")?.toUpperCase();
const ip_address = request.headers.get("cf-connecting-ip");
const user_agent = request.headers.get("user-agent");

let response = null;
let url = new URL(request.url);
let url_hostname = url.hostname;

if (https == true) {
url.protocol = "https:";
} else {
url.protocol = "http:";
}

if (await device_status(user_agent)) {
var upstream_domain = upstream;
} else {
var upstream_domain = upstream_mobile;
}

url.host = upstream_domain;
if (url.pathname == "/") {
url.pathname = upstream_path;
} else {
url.pathname = upstream_path + url.pathname;
}

if (blocked_region.includes(region)) {
response = new Response(
"Access denied: WorkersProxy is not available in your region yet.",
{
status: 403,
}
);
} else if (blocked_ip_address.includes(ip_address)) {
response = new Response(
"Access denied: Your IP address is blocked by WorkersProxy.",
{
status: 403,
}
);
} else {
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set("Host", upstream_domain);
new_request_headers.set("Referer", url.protocol + "//" + url_hostname);
new_request_headers.set("Authorization", "token " + github_token);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers,
body: request.body,
});

let connection_upgrade = new_request_headers.get("Upgrade");
if (connection_upgrade && connection_upgrade.toLowerCase() == "websocket") {
return original_response;
}

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

if (disable_cache) {
new_response_headers.set("Cache-Control", "no-store");
} else {
new_response_headers.set("Cache-Control", "max-age=43200000");
}

new_response_headers.set("access-control-allow-origin", "*");
new_response_headers.set("access-control-allow-credentials", "true");
new_response_headers.delete("content-security-policy");
new_response_headers.delete("content-security-policy-report-only");
new_response_headers.delete("clear-site-data");

if (new_response_headers.get("x-pjax-url")) {
new_response_headers.set(
"x-pjax-url",
response_headers
.get("x-pjax-url")
.replace("//" + upstream_domain, "//" + url_hostname)
);
}

const content_type = new_response_headers.get("content-type");
if (
content_type != null &&
content_type.includes("text/html") &&
content_type.includes("UTF-8")
) {
original_text = await replace_response_text(
original_response_clone,
upstream_domain,
url_hostname
);
} else {
original_text = original_response_clone.body;
}

response = new Response(original_text, {
status,
headers: new_response_headers,
});
}
return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text();

var i, j;
for (i in replace_dict) {
j = replace_dict[i];
if (i == "$upstream") {
i = upstream_domain;
} else if (i == "$custom_domain") {
i = host_name;
}

if (j == "$upstream") {
j = upstream_domain;
} else if (j == "$custom_domain") {
j = host_name;
}

let re = new RegExp(i, "g");
text = text.replace(re, j);
}
return text;
}

async function device_status(user_agent_info) {
var agents = [
"Android",
"iPhone",
"SymbianOS",
"Windows Phone",
"iPad",
"iPod",
];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

需要修改的地方有:

1
2
3
4
5
6
7
8
// Custom pathname for the upstream website.
// (1) 填写代理的路径,格式为 /<用户>/<仓库名>/<分支>(一般是main)
const upstream_path = "****";

// github personal access token.
// (2) 填写github令牌
const github_token = "****";

部署

保存并且部署

重要配置提醒

  • 域名必须托管在Cloudflare平台
  • 需提前完成DNS解析配置
  • 建议开启「始终使用HTTPS」选项

前往Cloudflare控制台:

  1. 进入Worker详情页
  2. 打开【设置】→【域名和路由】
  3. 添加自定义域名(如:img.yourdomain.com
  4. 等待SSL证书自动签发(约2分钟)

域名配置演示

PicGo设置:

1
2
3
4
5
6
图床配置:
- 类型: GitHub
- 仓库名: yourname/blog-images
- 分支: main
- 自定义域名: https://img.yourdomain.com
- Token: github_pat_xxxx

完成以上配置后,您将获得:

  • 🚀 全球CDN加速的图片访问体验
  • 🔒 自动管理的SSL证书
  • 📸 无缝的PicGo/VSCode上传集成