It's me ;-)

Sự kết hợp ngọt ngào giữa S3 và Cloudflare

Như các bạn đã biết thì S3 sẽ tính phí dựa trên dung lượng lưu trữ và request đến file lưu trữ đó. Điều đó có nghĩa là request càng nhiều thì phí sẽ càng tăng 😅

Vậy làm thế nào để giảm chi phí đây?

Thật ra thì có nhiều cách nhưng với dự án của mình đang chạy thì mình tiếp cận bằng cách kết hợp 2 cách sau:

  • Tối ưu dung lượng file
  • Sử dụng CDN

Tối ưu dung lượng file thì đơn giản là tìm cách làm sao để giảm dung lượng file đến mức tối đa mà không làm giảm chất lượng (ở dự án của mình là các file ảnh). Và vì bài toán này của mình chỉ liên quan đến ảnh nên mình có thể nhanh chóng chọn giải pháp là chuyển đổi từ các định dạng ảnh khác (JPG, PNG, GIF…) về webp

Còn sử dụng CDN là sao? Nó có liên quan gì đến S3?

Hiểu nôm na thì CDN là content delivery network – là một hệ thống nhiều máy tính (máy chủ) chứa những bản sao về nội dung, những máy chủ này được đặt ở nhiều nơi trong một mạng lưới và tối đa hóa băng thông cho việc truy cập dữ liệu. Một người dùng truy cập vào bản sao nội dung được chứa trên máy chủ gần với người dùng nhất sẽ làm giảm tình trạng “thắt cổ chai” so với việc tất cả người dùng cùng truy cập vào một máy chủ trung tâm.

Ở đây mình sẽ tận dụng tính năng miễn phí về CDN của Cloudflare để lấy dữ liệu từ S3 sau đó distribute qua các máy chủ khác. Như vậy thì khi có request đến 1 file, Cloudflare sẽ trả về nội dung cache của file đó trên CDN của họ, thay vì access trực tiếp vào file S3. Dĩ nhiên là khi cache miss thì vẫn phải lấy từ S3 thôi, nhưng dù sao thì cũng giảm đi được rất nhiều lần request rồi 😁

Để setup Cloudflare và S3 thì các bạn làm theo các bước như sau:

  1. Tạo 1 S3 bucket với tên trùng với CDN mà bạn định tạo. Ví dụ bạn định tạo theo domain static.example.com thì bucket name sẽ chính là static.example.com
  2. Sau khi tạo xong bucket thì bạn chọn tiếp Property của bucket là Static Website Hosting (để có endpoint mapping với Cloudflare)
  3. Ở tab Permissions, bạn thiết lập Block access public như hình bên dưới:
  4. Tiếp đó, bạn chỉnh Bucket Policy như sau:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "PublicReadGetObject",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::[your bucket name]/*",
                "Condition": {
                    "IpAddress": {
                        "aws:SourceIp": [
                            "2606:4700::/32",
                            "2803:f800::/32",
                            "2405:b500::/32",
                            "2405:8100::/32",
                            "2a06:98c0::/29",
                            "2c0f:f248::/32",
                            "173.245.48.0/20",
                            "103.21.244.0/22",
                            "103.22.200.0/22",
                            "103.31.4.0/22",
                            "141.101.64.0/18",
                            "108.162.192.0/18",
                            "190.93.240.0/20",
                            "188.114.96.0/20",
                            "197.234.240.0/22",
                            "198.41.128.0/17",
                            "162.158.0.0/15",
                            "104.16.0.0/12",
                            "172.64.0.0/13",
                            "131.0.72.0/22"
                        ]
                    }
                }
            }
        ]
    }
    
  5. Vào mục DNS của Cloudflare, tạo 1 CNAME record như hình bên dưới, nhớ là target chính là endpoint bạn có được ở bước 2:

Tada! Vậy là giờ bạn có thể upload file lên S3 rồi truy cập file thông qua CDN của Cloudflare được rồi. Như ví dụ trên thì khi bạn upload file hello.jpg vào bucket static.example.com thì bạn có thể truy cập bằng URL http://static.example.com/hello.jpg

Lưu ý: Để hạn chế truy cập trực tiếp vào file trên S3 thì bạn phải đặt policy cho bucket để chặn mọi public request ngoại trừ các request từ dải IP của Cloudflare

Leave a Reply

Your email address will not be published. Required fields are marked *