開始寫部落格後,我對於圖床的要求開始變得急迫。 以前測試過不少第三方圖床,一來免費的服務限制多到不好用,要不就是付費的貴到用不起。 於是,我決定自己來,既可避免圖片遺失的風險(只怕我的信用卡刷爆)。
本來計劃利用 Cloudfront + S3 組合滿足所有需求,但是沒想到 AWS 帳號第一次使用 Cloudfront 需要審核(之前都是用公司的帳號操作)。這讓我不得不暫時轉向 Cloudflare。
幸運的是,使用 Cloudflare 也不失為一個好選擇。我的域名正好由 Cloudflare 管理,其 DNS Records 的 Proxied 功能提供 CDN 服務和自動識別靜態內容的緩存,還能利用 Cloudflare WAF 防止盜連。
接下來,我將分享我的搭建過程,使用域名 example.com
作為示例。
目標
- 建立圖床 - AWS S3 Bucket
- 透過 Cloudflare:
- 自定義域名
images.example.com
指向 S3 圖床(DNS Records) - 啟用 CDN 緩存以加速訪問(Caching)
- 實現防盜連功能(WAF)
為什麼要 CDN
Content Distribution Network (CDN) 透過分布在多個地點的節點,優化內容傳輸,減少供應者的頻寬成本,提升使用者的下載速度和系統穩定性。
- Cloudflare
事實上現在的 CDN 服務所做的優化不只如此,比如 Cloudflare 的 CDN 不僅如此,其節點會根據設定,暫存請求內容,減少對原始服務器的請求次數,進一步優化性能和成本。
思考以下的情境:
-
AWS S3 Bucket 的服務是建立在單一區域的服務,假設我們將 S3 建立在 美國,而在地球另一端的台灣客戶端要訪問這個 S3 的資源,由它所發起的請求就需要跨越半個地球的距離來回交握,及大的增加延遲、降低用戶體驗。CDN 便可優化這一過程。
-
AWS S3 Bucket 是以流量計費,使用者向 S3 請求了一個 1MB 檔案 10 次,流量就是 10MB;如果有 CDN Cache 這份檔案的的情況下,同樣的案例, S3 只會計算 1MB 的流量 ─ 因為 S3 實際上只接收到第一次的請求,剩下的九次請求都會回覆 Cache 的內容。
為什麼要防盜連
除了內容保護的因素外,主要是為了減少不必要的流量消耗。想像一下: 你的部落格中的圖片被他人擅自引用,導致大量請求直接指向你的存儲空間,不僅增加了流量成本,也可能影響服務的穩定性。透過設定防盜連,可以有效控制這一問題。
所以應用防盜連機制是有必要的,目前常見的機制是 referer。Cloudflare WAF 可以簡單設定完成。
- Cloudflare
搭建步驟
S3
- 在 S3 創建 Bucket,命名為
mybucket
,Region 選擇 ap-northeast-1;不需要將 Bucket 公開。 - 到 Bucket -> 分頁 Properties 啟用 Static website hosting;endopint 應該會是
http://mybucket.s3-website-ap-northeast-1.amazonaws.com
。 - 上傳一張測試圖片
test.jpg
,確認可以訪問http://mybucket.s3-website-ap-northeast-1.amazonaws.com/test.jpg
。
(可選) 因為未來打算只透過 Cloudflare 的域名訪問 s3 bucket 的 endpoint,可以考慮進一步收緊權限。
進入 mybucket -> 分頁 Permissions -> Bucket policy 面板,加入以下 policy:
1{2 "Version": "2012-10-17",3 "Id": "restrict-s3-bucket",4 "Statement": [5 {6 "Sid": "AllowRequestsOnlyFromCloudFlare",7 "Effect": "Allow",8 "Principal": "*",9 "Action": "s3:GetObject",10 "Resource": "arn:aws:s3:::mybucket/*",11 "Condition": {12 "IpAddress": {13 "aws:SourceIp": [14 "103.21.244.0/22",15 "103.22.200.0/22",47 collapsed lines
16 "103.31.4.0/22",17 "104.16.0.0/13",18 "104.24.0.0/14",19 "108.162.192.0/18",20 "131.0.72.0/22",21 "141.101.64.0/18",22 "162.158.0.0/15",23 "172.64.0.0/13",24 "173.245.48.0/20",25 "188.114.96.0/20",26 "190.93.240.0/20",27 "197.234.240.0/22",28 "198.41.128.0/17"29 ]30 }31 }32 },33 {34 "Sid": "ExplicitDeny",35 "Effect": "Deny",36 "Principal": "*",37 "Action": "s3:GetObject",38 "Resource": "arn:aws:s3:::mybucket/*",39 "Condition": {40 "NotIpAddress": {41 "aws:SourceIp": [42 "103.21.244.0/22",43 "103.22.200.0/22",44 "103.31.4.0/22",45 "104.16.0.0/13",46 "104.24.0.0/14",47 "108.162.192.0/18",48 "131.0.72.0/22",49 "141.101.64.0/18",50 "162.158.0.0/15",51 "172.64.0.0/13",52 "173.245.48.0/20",53 "188.114.96.0/20",54 "190.93.240.0/20",55 "197.234.240.0/22",56 "198.41.128.0/17"57 ]58 }59 }60 }61 ]62}
Cloudflare
設定子域名和 CDN
- 在 DNS Records 中新增一條 CNAME 記錄,指向 S3 Bucket 的 endpoint。
1type: CNAME2name: image3content: mybucket.s3-website-ap-northeast-1.amazonaws.com4Proxy: proxied
- 使用 1.1.1.1 Purge 刷新功能確保設定生效。
- 測試
images.example.com/test.jpg
,確認可正常訪問 S3 存儲的資源。
設定 WAF
- 在 Security -> WAF 中新增一條規則,設定不允許非指定 referer 的請求通過,如不來自
blog.example.com
。 - (Options) 在規則中加入另一個 referer=“localhost”,方便本地環境瀏覽測試。
- 使用 Referrer Policy Test 檢查
images.example.com/test.jpg
,確認設置了 referrer-policy header - 確認用瀏覽器訪問
images.example.com/test.jpg
會被阻擋。
What’s next
這是我目前可用資源中的最佳解決方案,也是最省錢的方案。 等到 AWS 的 Cloudfront 服務可用後,且圖庫流量大到我無法負擔,可能會再重構新的解決方案。
參考
- Proxy status · Cloudflare DNS docs
- Configuring an Amazon Web Services static site to use Cloudflare · Cloudflare Support docs
- 盗链行为与 AWS 防盗链技术
- 用 AWS S3 做博客图床
- WS 图床防盗链
- 正确使用 AWS S3 的方式之打造自己的 https 图床
- 将图床切换至 AWS S3 以及设置 CDN、防盗链、生成缩略图的过程
- What is caching?
- What is a WAF? | Web Application Firewall explained
- WebsiteEndpoints