天天看點

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/