[教學] 使用 Cloudflare R2 與 Worker 為 Hugo 網站建立免費圖床

May 31, 2024 min read

前言:為何要用 Cloudflare R2 當 Hugo 圖床?

在經營以 Hugo 建置的靜態網站時,圖片管理一直是一個值得探討的議題。傳統作法是將圖片檔案直接放入專案的 static/ 目錄中,並隨著程式碼一同納入 Git 版本控制。然而,當圖片數量增多時,這種作法會導致 Git 倉庫變得異常肥大,不僅拖慢 git clonepull 的速度,也讓備份和管理變得相對麻煩。

為了解決這個問題,我將目光投向了 Cloudflare R2。R2 是一個與 Amazon S3 相容的物件儲存服務,但它最大的優勢在於「零出口費用」,這意味著無論您的圖片被多少使用者讀取,您都無需支付任何流量費用。搭配 Cloudflare Workers,我們甚至可以實現更進階的圖片處理功能。

本篇教學將帶您一步步實作,如何利用 Cloudflare R2 和 Worker,為您的 Hugo 網站打造一個高效、穩定且「免費」的圖床系統。

實作步驟:從 Worker 到 Shortcode

整個系統的核心流程如下:

Hugo Shortcode -> Cloudflare Worker -> Cloudflare R2

當使用者瀏覽您的文章時,文章中的 Shortcode 會向 Cloudflare Worker 發出請求,Worker 再從 R2 儲存體中抓取對應的圖片,並回傳給使用者。

步驟一:建立 Cloudflare Worker

首先,您需要在 Cloudflare 的儀表板上建立一個新的 Worker。這個 Worker 的作用是作為一個中介,負責接收來自網站的圖片請求,並從 R2 中取得圖片。

重要設定:在 Worker 的設定頁面中,務必將您的 R2 儲存體(Bucket)綁定到 Worker 上,這樣 Worker 才有權限讀取 R2 裡的檔案。

以下是 Worker 的程式碼範例:

export default {
  async fetch(request, env) {
    // 1. 解析請求的 URL,取得圖片的檔案路徑(key)
    const url = new URL(request.url);
    const objectName = url.pathname.substring(1);

    // 2. 從綁定的 R2 儲存體中獲取圖片物件
    // R2_BLOG_IMG 是您在設定中為 R2 綁定所指定的變數名稱
    let object = await env.R2_BLOG_IMG.get(objectName);

    // 如果找不到圖片,回傳 404 錯誤
    if (object === null) {
      return new Response("Image not found", { status: 404 });
    }

    // 3. 設定 HTTP 標頭,特別是 Cache-Control
    const headers = new Headers();
    object.writeHttpMetadata(headers);
    // 將圖片在瀏覽器中快取一年,減少不必要的請求
    headers.set('Cache-Control', 'public, max-age=31536000');

    // 4. 回傳圖片內容
    return new Response(object.body, {
      headers: headers,
    });
  },
};

步驟二:建立 Hugo Shortcode

接下來,在您的 Hugo 專案中,於 layouts/shortcodes/ 目錄下建立一個名為 r2image.html 的檔案。這個 Shortcode 能讓您在 Markdown 文章中,以更簡潔的方式插入存放在 R2 上的圖片。

{{/* 取得 shortcode 傳入的 key 和 alt 參數 */}}
{{ $imageKey := .Get "key" }}
{{ $altText := .Get "alt" }}

{{/* 組合出完整的圖片 URL */}}
<img src="https://your-worker-url.workers.dev/{{ $imageKey }}" alt="{{ $altText }}" loading="lazy">

請記得:將 your-worker-url.workers.dev 替換為您自己的 Worker 實際的 URL。

步驟三:在文章中使用

完成以上設定後,您就可以在 Markdown 文章中,透過以下語法輕鬆插入圖片:

{{< r2image key="your-image-folder/your-image.png" alt="圖片的描述文字" >}}

例如: 一隻戴著電腦龐克風格眼鏡的皮卡丘

這會顯示出存放在您 R2 儲存體根目錄下的 cyber-pikachu.png 圖片。

總結:優點與未來展望

透過 Cloudflare R2 與 Worker 建立的這套圖床系統,帶來了許多好處:

  • 輕量化的 Git 倉庫:將圖片資源與程式碼分離,讓您的專案版本庫保持輕巧,加快 clone 和部署的速度。
  • 方便的圖片管理:您可以直接透過 Cloudflare 的儀表板上傳、刪除或組織您的圖片資料夾,操作非常直觀。
  • 零成本高效能:R2 的零出口費用,加上 Worker 的免費額度,對於絕大多數的個人部落格或中小型網站來說,幾乎等同於零成本。同時,藉由 Cloudflare 的全球 CDN 網路,圖片載入速度也得到了保障。
  • 高度可擴展性:由於請求會經過 Worker,未來您可以輕易地在 Worker 中加入更多功能,例如:
    • 圖片即時縮放與裁切:根據請求的參數,動態輸出不同尺寸的圖片。
    • 格式轉換:自動將圖片轉換為 WebP 等更現代、壓縮率更高的格式。
    • 浮水印添加:自動為所有圖片加上版權浮水印。

總而言之,這是一個非常值得推薦給所有 Hugo 使用者的解決方案。