Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Image Archive System là hệ thống lưu trữ và quản lý hình ảnh hiệu năng cao, được thiết kế để tối ưu chi phí và hiệu suất. Hệ thống sử dụng Cloudinary làm nơi lưu trữ ảnh, Cloudflare Pages làm nền tảng triển khai, và tích hợp Jetpack để tối ưu hóa hình ảnh. Với khả năng phân phối tải lên nhiều tài khoản Cloudinary, hệ thống giúp vượt qua giới hạn lưu trữ của gói miễn phí và tối đa hóa hiệu suất truy cập thông qua CDN của Cloudflare.

Tính năng chính

  • Hỗ trợ nhiều tài khoản: Phân phối tải lên nhiều tài khoản Cloudinary để tăng dung lượng lưu trữ
  • Tối ưu hóa hình ảnh: Tự động tối ưu hóa hình ảnh sau khi tải lên thông qua Jetpack
  • Kiểm soát truy cập: Hạn chế số lượng yêu cầu từ mỗi IP và phát hiện hành vi bất thường
  • Giao diện thân thiện: Giao diện kéo thả đơn giản, dễ sử dụng
  • Hiệu suất cao: Tích hợp với CDN của Cloudflare để tăng tốc độ truy cập
  • Upload hàng loạt: Hỗ trợ tải lên nhiều file cùng lúc với cơ chế phân chia batch thông minh
  • Quản lý URL đa dạng: Tự động tạo 4 định dạng URL phổ biến cho mỗi ảnh (Direct, Markdown, BBCode, HTML)

Tính năng giao diện người dùng

  • Mỗi ảnh tự động tạo 4 định dạng URL: Direct, Markdown, BBCode và HTML
  • Click vào URL để tự động copy vào clipboard
  • Nút “Copy All” cho phép copy tất cả URL theo định dạng đã chọn
  • Dễ dàng chuyển đổi giữa các định dạng URL khác nhau
  • Xem trước ảnh trước khi tải lên
  • Kiểm tra kích thước và loại file tự động
  • Tự động phát hiện và thông báo lỗi
  • Giao diện kéo thả trực quan

Đây là phiên bản Image Archive System mình hài lòng nhất, tính ổn định cao, hiệu quả, viết thành 1 bài hướng dẫn cài đặt, vì thú thực nếu không ghi chú lại, sẽ rất dễ quên, nhầm các công đoạn cài đặt

Cài đặt Image Archive System

3 bước đầu tiên là:

  • Tạo tài khoản Github nếu chưa có
  • Tạo tài khoản Cloudflare mới, để tận dụng 100.000 request miễn phí mỗi ngày
  • Tạo các tài khoản Cloudinary để chứa ảnh
    • 1 tài khoản Cloudinary mặc định có 25 credit, tối đa lên tới 100 credit, tương đương 100GB dung lượng, quá đủ cho 1 user thông thường sử dụng
    • Nếu bạn muốn tạo ra 1 trang tương tự img.bibica.net, public ra cho nhiều người dùng, có thể tạo thêm nhiều tài khoản Cloudinary khác
    • Việc tạo nhiều tài khoản Cloudinary bị cấm theo chính sách của hãng, dù thực tế bản thân mình dùng 3-5 tài khoản trong 5 năm nay, vẫn không thấy họ nói gì 😅

Download toàn bộ source code Image Archive System phiên bản storage Cloudinary tại đây

  • Tạo 1 dự án mới trên Github, chọn chế độ private

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Giải nén, upload tất cả file vào dự án

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Cấu hình server.js

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • ALLOWED_ORIGINS: thay bằng domain của bạn (nếu chưa biết được domain là gì, thì sau này cập nhập lại)
  • CLOUDINARY_ACCOUNTS: thay bằng tài khoản Cloudinary của bạn, muốn dùng thêm tài khoản thì copy thêm thành dòng mới

Mặc định khi vừa tạo tài khoản, login vào, sẽ hiện ra cái thông báo, có sẵn [cloud_name, api_key, api_secret]

["duxl2jwjy", "338626439374432", "xwr_At2WaxAtdK_u04sNpZXKWjM"],
["dga1onmqq", "447836514486728", "2IvUET_Af2o4Aq-7wLyfqh9jnbI"],
["dbvp17k9l", "431535683238757", "I5-J405OgrtKDJKKSx36lwjWaf0"],
  • RATE_LIMIT: đang giới hạn 20 lượt upload trong 5 phút (tính theo IP), sửa lại theo nhu cầu của bạn
  • MAX_SIZE_MB: Cloudinary hỗ trợ tài khoản miễn phí upload tối đa 10MB, đang dùng giá trị cao nhất, sửa lại theo nhu cầu của bạn
  • PATH: tùy chọn tạo ra url ảnh, mặc định tạo tên file ngẫu nhiên 8 kí tự
  • ABUSE_PROTECTION: đây là hình thức chống các tool, bot request làm tốn tài nguyên database , cấu hình từ server.js không có giá trị, để như mặc định là đủ

Cấu hình database D1

  • Vào Cloudflare, tạo 1 database D1 miễn phí

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Đặt tên: image-archive-db (hoặc tên tùy thích)

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Sang tab Console, dán đoạn SQL bên dưới vào, sau đó Execute:
CREATE TABLE IF NOT EXISTS images (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    folder TEXT,
    filename TEXT,
    cloudinary_url TEXT NOT NULL,
    file_size INTEGER,
    cloud_name TEXT
);

CREATE TABLE IF NOT EXISTS rate_limits (
    ip TEXT PRIMARY KEY,
    count INTEGER,
    reset_time INTEGER
);

CREATE TABLE IF NOT EXISTS abuse_blocks (
    ip TEXT PRIMARY KEY,
    failed_count INTEGER,
    block_until INTEGER,
    last_attempt INTEGER
);

CREATE INDEX idx_images_folder_filename ON images(folder, filename);
  • Lấy database_id (cạnh database_name)

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Cấu hình scripts/generate-pages.js

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • database_name: thay bằng database_name của bạn
  • database_id: thay bằng database_id của bạn
  • SERVER_PREFIX: có thể đổi sang 1 tên gọi mà bạn thích, đây là url dùng để gọi các server (mặc định sẽ tạo ra 19 server)

Cấu hình Cloudflare API Tokens

  • Tạo 1 API Tokens

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Chọn Template Cloudflare Workers

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Bắt buộc phải chọn vào tài khoản cụ thể (không dùng mặc định tất cả tài khoản)

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Click đơn giản về home, sẽ thấy ACCOUNT_ID

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Cấu hình GitHub Actions

  • Click vào Actions trên dự án, chọn Skip this and set up a workflow yourself 

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Điền vào nội dung bên dưới
name: Deploy Cloudflare Pages

on:
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    env:
      CLOUDFLARE_API_TOKEN: xxxxxxxxxxxxxxx
      CLOUDFLARE_ACCOUNT_ID: xxxxxxxxxxxxx
      CUSTOM_DOMAIN_SUFFIX: bibica.net
      SERVER_PREFIX: iserver
      SERVER_COUNT: 19

    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'

      - name: Install Wrangler
        run: npm install -g wrangler

      - name: Generate page configurations
        run: node scripts/generate-pages.js

      - name: Deploy Cloudflare Pages
        run: |
          for i in $(seq 1 $SERVER_COUNT); do
            PROJECT_NAME="${SERVER_PREFIX}${i}"
            CUSTOM_DOMAIN="${PROJECT_NAME}.${CUSTOM_DOMAIN_SUFFIX}"
            PAGES_DOMAIN="${PROJECT_NAME}.pages.dev"

            cd "${SERVER_PREFIX}/${PROJECT_NAME}"

            if ! wrangler pages project list | grep -q "$PROJECT_NAME"; then
              wrangler pages project create "$PROJECT_NAME" --production-branch=main > /dev/null
              echo "Successfully created the '${PROJECT_NAME}' project. It will be available at https://${PAGES_DOMAIN} once you create your first deployment."
            fi

            wrangler pages deploy . --project-name="$PROJECT_NAME" --commit-dirty=true > /dev/null

            DOMAIN_EXISTS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${PROJECT_NAME}/domains" \
              -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" | grep -o "$CUSTOM_DOMAIN" | head -1)

            if [ -z "$DOMAIN_EXISTS" ]; then
              curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${PROJECT_NAME}/domains" \
                -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
                -H "Content-Type: application/json" \
                --data '{"name":"'"$CUSTOM_DOMAIN"'"}' > /dev/null
            fi

            echo "CNAME ${CUSTOM_DOMAIN} -> ${PAGES_DOMAIN}"

            cd ../..
          done
  • CLOUDFLARE_API_TOKEN: thay bằng token tạo ra bước bước trên
  • CLOUDFLARE_ACCOUNT_ID: thay bằng ID tài khoản của bạn
  • CUSTOM_DOMAIN_SUFFIX: thay bibica.net bằng domain của bạn
  • SERVER_PREFIX: dùng theo tên tạo ra ở bước scripts/generate-pages.js

Chạy runs workflow

  • Actions -> Deploy Cloudflare Pages

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Đây là bước cuối cùng để public các server của bạn ra ngoài

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Lần đầu chạy thường mất 4-8 phút, vì phải tạo, cấu hình 19 server, các url server tạo ra sẽ từ Cloudflare Pages, sẽ có dạng iserver15-5uq.pages.dev
  • Nếu muốn dùng subdomain thì tạo CNAME theo tên hiển thị ra, như thèng img.bibica.net, sẽ dùng server iserver1.bibica.net -> iserver19.bibica.net
  • Lười thì dùng .pages.dev cho nhanh, vì thường user vào upload ảnh cũng chẳng ai quan tâm mấy cái này

Sau này, nếu chỉnh sửa code, bổ xung tài khoản Cloudinary tại server.js, cần chạy lại runs workflow Deploy Cloudflare Pages, nó sẽ tự cấu hình toàn bộ 19 server

Cấu hình client

Mở file index.html ra, tìm kiếm dòng this.servers

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Cá nhân mình đang dùng URL iserver1.bibica.net -> iserver19.bibica.net, điền thế cho gọn, nếu bạn dùng ít server hơn, hoặc dùng các sub .pages.dev thì dùng trực tiếp URL cho tiện

this.servers = [
  "https://iserver1-h9b.pages.dev",
  "https://iserver2-310.pages.dev",
  "https://iserver3-72y.pages.dev",
  "https://iserver4-dhg.pages.dev",
  "https://iserver5-3oe.pages.dev",
  "https://iserver6-5qe.pages.dev",
  "https://iserver7-9u7.pages.dev",
  "https://iserver8-epr.pages.dev",
  "https://iserver9-bna.pages.dev",
  "https://iserver10-9h8.pages.dev",
  "https://iserver11-8vp.pages.dev",
  "https://iserver12-f4l.pages.dev",
  "https://iserver13-ehj.pages.dev",
  "https://iserver14-f3g.pages.dev",
  "https://iserver15-5uq.pages.dev",
  "https://iserver16-87s.pages.dev",
  "https://iserver17-br0.pages.dev",
  "https://iserver18-124.pages.dev",
  "https://iserver19-bfe.pages.dev"
];

Các cấu hình giới hạn khác, maxFiles, maxFileSize điền theo cấu hình bạn giới hạn ở server, cho client và server đồng bộ với nhau

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Cấu hình quan trọng nhất ở client là this.maxBatchSize = 40 * 1024 * 1024;, giá trị mình đang duy trì là batch 40MB, khi user upload cùng lúc nhiều file (100-1000) dung lượng nhỏ, sẽ thấy sự tối ưu của tùy chọn này, giá trị này nên duy trì < 40MB, cao hơn không có nhiều tác dụng, và dễ làm Cloudflare báo lỗi thiếu RAM

Sau khi chỉnh sửa lại đường dẫn this.servers tại index.html thì có thể triển khai lên Cloudflare Pages

Triển khai lên Cloudflare Pages

  • Vào Cloudflare Dashboard > Pages > Create a project:

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Kết nối với GitHub repository của bạn

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Cấu hình build: (tất cả để mặc định)

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Nhấn Save and Deploy

Cấu hình Bind D1 Database

Vào Settings > Functions > D1 database bindings:

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

  • Variable name: DB
  • D1 database: image-archive-db (mặc định nó sẽ hiện ra db bạn đã tạo)

Khởi động lại Deploy

  • Quay lại tab Deployments > Production > View details
  • Tại Deployment details, nhấn Retry deployment

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Nếu sử dụng domains: demo-7et.pages.dev để chạy Image Archive System thì cần sửa lại ALLOWED_ORIGINS theo domain này tại server.js

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Mỗi khi sửa server.js, cần chạy lại runs workflow Deploy Cloudflare Pages để cập nhập lại

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Bản Image Archive System viết chạy trên nhiều server upload, nên quá trình cập nhập server hơi phức tạp, sử dụng thực tế chỉ có lần đầu tiên làm hơi nhiều thao tác, sử dụng thực tế nếu bạn dùng khoảng 10 tài khoản Cloudinary thì chắc 10 năm không cần nhìn lại luôn, vì khó ai upload ảnh tới 250GB lắm

Hướng dẫn cài đặt Image Archive System phiên bản storage Cloudinary

Trong miss/cron-worker.js, mình có tạo sẵn 1 cron chạy qua woker, nếu tài khoản dùng > 15GB dung lượng sẽ, gửi thông báo qua Telegram, bạn nào thích có thể cài thêm, tránh tài khoản dùng quá credit

Kết luận

Image Archive System dùng cá nhân, mình không thấy quá nhiều ưu điểm, nó hợp hơn cho bạn nào làm mấy trang dạng truyện coi online, upload cường độ cao, URL ảnh được ẩn, gần như không ai biết được ảnh để ở đâu, băng thông thì Cloudflare miễn phí


Related Posts

Chính sách bình luận: Chúng tôi rất trân trọng các bình luận của bạn và cảm ơn thời gian bạn dành để chia sẻ ý tưởng và phản hồi.
Ghi chú: Những bình luận được xác định là spam hoặc chỉ mang tính quảng cáo sẽ bị xóa.

• Để cải thiện trải nghiệm bình luận, chúng tôi khuyến khích bạn tạo một tài khoản Gravatar. Thêm avatar vào tài khoản Gravatar sẽ giúp bình luận của bạn dễ nhận diện hơn đối với các thành viên khác.

✂️ Sao chép và 📋 Dán Emoji 💪 giúp bình luận thêm sinh động và thú vị!