天天看点

backblaze_cloudflare 图床配置

cloudflare + back blaze 图床配置

      • 概述
      • backblaze
        • 注册 backblaze(自己的测试账号)
        • 创建bucket
        • 设置bucket header
        • 上传文件
        • 接口调用收费,每天前2500次免费,调用次数超了会报错,除非加入收费计划
        • 添加app key
      • 申请测试域名
      • cloudflare
        • 注册 cloudflare
        • cloudflare 添加 根域名
        • 添加缓存规则
          • 在域名服务商处配置dns
        • 配置worker
          • 概述
          • 具体配置
        • 缓存配置
        • 防盗链原理
      • python脚本更新worker
        • 前置条件:
          • backblaze
          • cloudflare
        • 脚本作用
        • 请求生命周期
        • 脚本正文
        • 设置敏感变量
        • 通过crontab设置脚本定时执行
      • 测试
      • 参考链接

概述

backblaze:又叫b2,是一家云存储平台,可以把自己的文件上传至云端,同时提供一个可以在外界访问的url地址。本文访问图片

cloudflare:一家CDN,缓存网页,我们的目的是缓存backblaze的图片,使用户看图的流量不走 backblaze,走 cloudflare。

backblaze 在 cloudflare 的带宽联盟中,二者之间的流量免费,在这里使用backblaze,使用户流量全部走带宽联盟

带宽联盟:https://www.cloudflare.com/zh-cn/bandwidth-alliance/

backblaze

注册 backblaze(自己的测试账号)

B2 Cloud Storage -> Sign Up

传送门

创建bucket

My Account -> Buckets -> Create a Bucket

创建的时候需要填 Bucket Unique Name,选好是 private 还是 public

这里为了防止别有用心的人士刷backblaze的流量,创建 private bucket,使用户不能直连backblaze,只能连cloudflare

设置bucket header

在默认情况下,backblaze 端会发送 cache-control header, 设为不允许缓存,此时我们访问图片的 CF-Cache-Status 为 BYPASS,绕过了缓存

这时需要在 backblaze 的 buckets -> bucket settings -> bucket info 中设置如下:

{"cache-control":"public, max-age=604800"}
           

上传文件

My Account -> Browse Files 或 My Account -> Buckets -> Upload/Download

在 Browse Files 界面,点击每个文件右侧的小 “i” 可显示图片链接

接口调用收费,每天前2500次免费,调用次数超了会报错,除非加入收费计划

文档

# 报错文本
Transaction cap exceeded, see the Caps & Alerts page to increase your cap.
           

这里需要注意,cloudflare CDN 在全球有多个站点,访问 B2 的次数不仅仅是"有多少文件就访问多少次", 还要乘一个站点数量的系数

因此,如果访问次数有可能会超过2500次的情况下,backblaze 需要配置账号支付方式(每天超过2500次之后,每10000次自动扣款),否则 backblaze 会直接限制加载图片

添加app key

MyAccount -> App Keys -> add a new application key

设置key对哪些bucket有哪些权限

key id 和 key 本体 只出现一次,要记下来!!!

申请测试域名

腾讯云买一个一年的根域名,30多块钱

腾讯云 -> 搜索域名注册 -> 买一个1年的

腾讯云 -> 控制台 -> 前往dnspod 控制台 -> 配置dns

cloudflare

注册 cloudflare

https://dash.cloudflare.com/

cloudflare 添加 根域名

cloud flare 控制台 -> 添加站点 -> 输入刚注册的根域名 -> 选择"免费"计划 -> 增加一条cname记录,把<自己随便写一个名字>.superggn.com 指向 b2 域名(f000.backblazeb2.com)

通过https://image.superggn.com/file// 访问public bucket文件

添加缓存规则

CF -> superggn.com -> Rules -> Create Page Rule

URL: image.superggn.com/*

Cache level: standard

在域名服务商处配置dns

腾讯云 -> 控制台 -> 前往dnspod 控制台 -> 配置dns

在哪里买的域名就在哪里修改

配置worker

概述

worker 实现功能:

修改入方向链接

访问b2 private bucket

具体配置

CF -> superggn.com -> workers -> 管理 workers

创建worker

暂时不进行edit操作,直接save and deploy

记住worker的名字

CF -> superggn.com -> workers -> 添加路由

路由:image.superggn.com/*

即在 配置dns 步骤得到的我们的测试域名,绑定到刚建立的 worker 上

缓存配置

CF -> superggn.com -> Rules -> Create Page Rule

设置 cache level -> standard -> save and deploy

防盗链原理

CF -> superggn.com -> Rules -> Scrape Shield

Hotlink Protection -> On

用户自己单独在浏览器中输入图片地址,还是能访问到,那防盗链是如何实现的呢?

别的网站在网页中加载图片访问我的图片地址时,请求会带这样一个 header:

Referer:referesite.com
           

Hotlink Protection 就是拦截所有该 header 和自己域名不符的访问请求

在工作中,一般不配置这个,因为一旦开启了防盗链,之前共享到其他网站的链接都会失效

python脚本更新worker

前置条件:

backblaze

b2 bucket name

b2 bucket id

在 bucket 获取

b2 app key id

b2 app key

在 backblaze 生成的 app key(规定了能访问哪个bucket)
cloudflare

cf worker account id

workers -> manage workers

右边栏 account id

cf worker name

cf worker api key

my profile -> api tokens -> create token

选 Edit Cloudflare Workers 模板即可

脚本作用

worker 本质上就是一个跑在某个ip上的一段脚本,所以 worker name 和 script name 是等价的

向 backblaze 发送请求,获取b2 auth token(没有这个token是访问不到 private bucket 的)(最长有效期7天,你可以试一下把 maxSecondsAuthValid 设置长一点,直接报错),将获取到的 b2 auth token 更新到 cloudflare worker script 中,实现访问授权

请求生命周期

请求——cloudflare——worker——backblaze

脚本正文

注意替换变量

import base64
import json

import requests

ETC_ROOT = '/etc/DiceServer'

with open('{}/cloudflare_backblaze_config.txt'.format(ETC_ROOT)) as f:
    CLOUDFLARE_BACKBLAZE_CONFIG_LIST = f.read().strip().split()
    # backblaze config
    B2_BUCKET_NAME = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[1]
    BUCKET_SOURCE_ID = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[3]
    # backblaze config for b64 encoding
    B2_APP_KEY_ID = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[5]
    B2_APP_KEY = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[7]
    B2_DOMAIN = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[9]
    # cloudflare config
    CF_WORKER_ACCOUNT_ID = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[11]
    CF_WORKER_API_KEY = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[13]
    CF_WORKER_NAME = CLOUDFLARE_BACKBLAZE_CONFIG_LIST[15]

flagDebug = True

# An authorization token is valid for not more than 1 week
# This sets it to the maximum time value
maxSecondsAuthValid = 7 * 24 * 60 * 60  # one week in seconds

# DO NOT CHANGE ANYTHING BELOW THIS LINE ###

baseAuthorizationUrl = 'https://api.backblazeb2.com/b2api/v2/b2_authorize_account'
b2GetDownloadAuthApi = '/b2api/v2/b2_get_download_authorization'

# Get fundamental authorization code
idAndKey = B2_APP_KEY_ID.encode() + b':' + B2_APP_KEY.encode()
b2AuthKeyAndId = base64.b64encode(idAndKey)
basicAuthString = 'Basic ' + b2AuthKeyAndId.decode('UTF-8')
authorizationHeaders = {'Authorization': basicAuthString}
resp = requests.get(baseAuthorizationUrl, headers=authorizationHeaders)

if flagDebug:
    print("resp.status_code", resp.status_code)
    print("resp.headers", resp.headers)
    print("resp.content", resp.content.decode())
    print("_____________")

respData = json.loads(resp.content.decode("UTF-8"))

bAuToken = respData["authorizationToken"]
bFileDownloadUrl = respData["downloadUrl"]
bPartSize = respData["recommendedPartSize"]
bApiUrl = respData["apiUrl"]

# Get specific download authorization

getDownloadAuthorizationUrl = bApiUrl + b2GetDownloadAuthApi
downloadAuthorizationHeaders = {'Authorization': bAuToken}

resp2 = requests.post(getDownloadAuthorizationUrl,
                      json={'bucketId': BUCKET_SOURCE_ID,
                            'fileNamePrefix': "",
                            'validDurationInSeconds': maxSecondsAuthValid},
                      headers=downloadAuthorizationHeaders)

resp2Content = resp2.content.decode("UTF-8")
resp2Data = json.loads(resp2Content)

bDownAuToken = resp2Data["authorizationToken"]

if flagDebug:
    print("authorizationToken: " + bDownAuToken)
    print("downloadUrl: " + bFileDownloadUrl)
    print("recommendedPartSize: " + str(bPartSize))
    print("apiUrl: " + bApiUrl)

workerTemplate = """
addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
    let authToken = '<B2_DOWNLOAD_TOKEN>'
    const b2Domain = '<B2_DOMAIN>'
    const b2UrlPath = '/file/<B2_BUCKET_NAME>/'
    let b2Headers = new Headers(request.headers)
    const url = new URL(request.url)
    if (url.host === b2Domain && !url.pathname.startsWith(b2UrlPath)) {
        url.pathname = b2UrlPath + url.pathname;
    }
    b2Headers.append("Authorization", authToken)
    modRequest = new Request(url, {
        method: request.method,
        headers: b2Headers
    })

    const response = await fetch(modRequest)
    return response
}
"""

workerCode = workerTemplate.replace('<B2_DOWNLOAD_TOKEN>', bDownAuToken)
workerCode = workerCode.replace('<B2_BUCKET_NAME>', B2_BUCKET_NAME)
workerCode = workerCode.replace('<B2_DOMAIN>', B2_DOMAIN)

cfHeaders = {'Authorization': "Bearer " + CF_WORKER_API_KEY,
             'Content-Type': 'application/javascript'}

cfUrl = 'https://api.cloudflare.com/client/v4/accounts/' + CF_WORKER_ACCOUNT_ID + "/workers/scripts/" + CF_WORKER_NAME

resp = requests.put(cfUrl, headers=cfHeaders, data=workerCode)

if flagDebug:
    print(resp)
    print(resp.headers)
    print(resp.content)
"""

workerCode = workerTemplate.replace('<B2_DOWNLOAD_TOKEN>', bDownAuToken)
workerCode = workerCode.replace('<B2_BUCKET_NAME>', b2BucketName)

cfHeaders = {'Authorization': "Bearer " + cfWorkerApiKey,
             'Content-Type': 'application/javascript'}

cfUrl = 'https://api.cloudflare.com/client/v4/accounts/' + cfWorkerAccountId + "/workers/scripts/" + cfWorkerName

resp = requests.put(cfUrl, headers=cfHeaders, data=workerCode)

if flagDebug:
    print(resp)
    print(resp.headers)
    print(resp.content)

print("_______________")
           

设置敏感变量

通过crontab设置脚本定时执行

将脚本文件 update_cloudflare_worker.py(随便取什么名字都行)放到测试服务器cron脚本目录(这个可以直接通过crontab -l 看看其他脚本都放在哪)下

cd /home/ubuntu/test_crontab
vim update_cloudflare_worker.py
# 把脚本粘贴进去,保存退出
crontab -l
crontab -e
# 在下方添加一行
* * * * *	python3 /home/ubuntu/test_crontab/update_cloudflare_worker.py
# 保存退出
           

测试

访问图片url,查看 response header 中的 CF-Cache-Status,若为 HIT,则OK

设置完成,再次访问两次图片,CF-Cache-Status 显示为 MISS(第一次访问,回源站取内容) 和 HIT(使用缓存),配置完成

参考链接

public bucket

https://help.backblaze.com/hc/en-us/articles/217666928-Using-Backblaze-B2-with-the-Cloudflare-CDN

private bucket

https://help.backblaze.com/hc/en-us/articles/360010017893-How-to-allow-Cloudflare-to-fetch-content-from-a-Backblaze-B2-private-bucket

去除链接中间的/file//

https://www.reddit.com/r/backblaze/comments/i3t104/using_cloudflarebackblaze_b2_can_i_remove/

https://jross.me/free-personal-image-hosting-with-backblaze-b2-and-cloudflare-workers/

国内教程

https://dukeluo.me/2020/02/12/blog-clean-plan-1.html

https://www.wangfuchao.com/1290/