使用Backblaze B2和Cloudflare Workers搭建免费的自定义域名图床和对象存储。
在我们建设运行博客和其他中小型网站的时候,常常需要用到类似于阿里OSS和腾讯COS这类似的对象存储服务,用于作为图床和zip、rar等文件的存储。尧言来来回回折腾了N多家的对象存储服务,最后某些网站的对象存储定为了阿里云的OSS。
某些站点由于备案和众所周知的其他原因,国内的对象存储是比较难满足需求的,在尝试了AWS的S3和Google Cloud之后,还是觉得美中不足,直到有一天遇到Backblaze。下面记录一下如何使用Backblaze B2和Cloudflare Workers搭建免费的自定义域名图床和对象存储。
各组件服务介绍
- Backblaze B2
Backblaze B2 是一个云存储解决方案,类似于Amazon AWS S3, 但是价格稍微便宜一些. 前 10GB 存储是完全免费的. 通常情况下,像使用 AWS S3 这类的服务,你必须为所提供的内容支付带宽费用,这通常是费用中最高的部分。不过,由于有了 Bandwidth Alliance(带宽联盟),Backblaze 到 Cloudflare 之间的出口是完全免费的,我们将大量使用这一优势。
- Cloudflare
最强大实用的DNS和CND服务提供商,没有之一。
免费额度
100,000 requests per day.(一天 10万次请求)
Up to 10ms CPU time per request.(每次请求最大占用 CPU 工作时间为 10ms)
First 10 GB for free.(前 10GB 存储免费)
The first 1 GB of data downloaded each day is free.(每天前 1GB 下载免费)
因为有 Bandwidth Alliance(带宽联盟),这个限制我们可以忽略不计。
Class “B” transactions - $0.004 per 10,000 with 2,500 free per day.(B 类传输,每天前 2500 次免费)
Cloudflare Workers 需要用到的 b2_download_file_by_name,属于 B 类传输。
Backblaze B2 提供了 10G 的免费存储空间,并且搭配 Cloudflare 的 page rules 来配置一些缓存规则,对于个人用户绰绰有余。Backblaze 当前的配额使用量可以在面板的 “Caps & Alerts” 查看,修改配额会要求提供信用卡,以便用于付费。所以,在你提供信用卡之前,一切都是免费的。
开始设置和配置
- 创建 Backblaze B2 Bucket(存储桶)
注册登陆Backblaze账号后,创作一个桶,然后会得到一个类似于下面的界面,这里有我们下一步需要用到的信息。我们需要记住下图标记的类似于s3.us-west-002.backblazeb2.com的域名。

- Cloudflare DNS
获取了上面的信息后,我们需要去到Cloudflare添加一条我们图床域名的解析记录,主机名我们自己决定,尧言用的是img;记录值是“桶的名字.上一步我们获取的域名”,就像yaoyan.s3.us-west-002.backblazeb2.com
例如尧言用的图床域名是img.yaoyan.info,桶的名字是yaoyan,则是把img解析到yaoyan.s3.us-west-002.backblazeb2.com就可以了。对了,要开启代理哦,就是Cloudflare的那朵云是亮的,这代表请求是通过了 Cloudflare 的 CDN 代理层。Cloudflare 默认的 TTL 将被设置为 auto(自动),对于我们的使用已经足够。
如果你的文件不会经常改变,我强烈建议你,添加一条 page-rule(页面规则) 来设置 “cache level(缓存等级)” 为 “everything(所有)”, 并且 “edge cache TTL(边界缓存存活时间)” 设置为较高的值,比如 7天。

然后,你还需要到Backblaze B2,在Bucket Info:处添加缓存时间,该时间越长那么文件在CloudFlare CDN节点上缓存的时间越长,单位为秒,请根据需要来设定。以一年的时间为例也就是31536000秒,一月的话就是2592000秒,一周的话就是604800秒,一天的话就是86400秒。
{"cache-control":"max-age=31536000"}
- Cloudflare Workers
通常来说, 现在这样,一切都可以正常工作了,如果你只要一个基础的图片存储,那么,你不需要配置其他的东西。但是,为了一些其他的酷炫效果,我们可以使用 Cloudflare Workers来重写图片的 URL 使链接更加友好, 比如从 URL 中去掉无用的 /file/
const b2Domain = 'img.domain.com'; // configure this as per instructions above
const b2Bucket = 'bucket-name'; // configure this as per instructions above
const b2UrlPath = `/file/${b2Bucket}/`;
addEventListener('fetch', event => {
return event.respondWith(fileReq(event));
});
// define the file extensions we wish to add basic access control headers to
const corsFileTypes = ['png', 'jpg', 'gif', 'jpeg', 'webp'];
// backblaze returns some additional headers that are useful for debugging, but unnecessary in production. We can remove these to save some size
const removeHeaders = [
'x-bz-content-sha1',
'x-bz-file-id',
'x-bz-file-name',
'x-bz-info-src_last_modified_millis',
'X-Bz-Upload-Timestamp',
'Expires'
];
const expiration = 31536000; // override browser cache for images - 1 year
// define a function we can re-use to fix headers
const fixHeaders = function(url, status, headers){
let newHdrs = new Headers(headers);
// add basic cors headers for images
if(corsFileTypes.includes(url.pathname.split('.').pop())){
newHdrs.set('Access-Control-Allow-Origin', '*');
}
// override browser cache for files when 200
if(status === 200){
newHdrs.set('Cache-Control', "public, max-age=" + expiration);
}else{
// only cache other things for 5 minutes
newHdrs.set('Cache-Control', 'public, max-age=300');
}
// set ETag for efficient caching where possible
const ETag = newHdrs.get('x-bz-content-sha1') || newHdrs.get('x-bz-info-src_last_modified_millis') || newHdrs.get('x-bz-file-id');
if(ETag){
newHdrs.set('ETag', ETag);
}
// remove unnecessary headers
removeHeaders.forEach(header => {
newHdrs.delete(header);
});
return newHdrs;
};
async function fileReq(event){
const cache = caches.default; // Cloudflare edge caching
const url = new URL(event.request.url);
if(url.host === b2Domain && !url.pathname.startsWith(b2UrlPath)){
url.pathname = b2UrlPath + url.pathname;
}
let response = await cache.match(url); // try to find match for this request in the edge cache
if(response){
// use cache found on Cloudflare edge. Set X-Worker-Cache header for helpful debug
let newHdrs = fixHeaders(url, response.status, response.headers);
newHdrs.set('X-Worker-Cache', "true");
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHdrs
});
}
// no cache, fetch image, apply Cloudflare lossless compression
response = await fetch(url, {cf: {polish: "lossless"}});
let newHdrs = fixHeaders(url, response.status, response.headers);
if(response.status === 200){
response = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHdrs
});
}else{
response = new Response('File not found!', { status: 404 })
}
event.waitUntil(cache.put(url, response.clone()));
return response;
}

- 防盗链
可以在 Cloudflare 的 Firewall 功能中,添加一条 firewall rule
(not http.referer contains “www.yaoyan.info” and http.request.full_uri contains “https://img.yaoyan.info")
拒绝block你不想要的请求达到防盗链的效果。
当然还有一个防盗链更直接的方法,就是直接在Cloudflare的Scrape Shield里面开启Hotlink 保护即可。
两种方法各有优劣,根据自己的需求配置即可。
相关推荐:
0 评论