Đây là bài viết Phần 3 nằm trong series: WordPress to Astro Migration
Sau khi cài đặt và cấu hình Astro thành công trên máy tính, mình có thể đưa toàn bộ blog lên Github và deploy lên Cloudflare Worker ngay. Tuy nhiên, hiện tại có quá nhiều hình ảnh (khoảng 500 MB), không hợp lý khi lưu trữ trên Github, vì mỗi lần clone về máy sẽ mất rất nhiều thời gian.
Các file media (hình ảnh, video,…) nên được tách riêng khỏi phần nội dung (file text) và được lưu trữ trên các dịch vụ chuyên dụng. Theo mình tìm hiểu, hiện tại có 2 dịch vụ lưu trữ được tích hợp tốt với Astro:
- Cloudinary (giới hạn 25GB miễn phí)
- Cloudflare R2 (giới hạn 10GB miễn phí)
Lần này, mình chọn sử dụng Cloudflare R2. Cloudinary có thể được nghiên cứu sử dụng cho các blog khác sau này.
Bài viết [Phần 3] này sẽ hướng dẫn cách upload ảnh lên Cloudflare R2 để sử dụng cho Astro blog.
Mục Lục
1. Tạo R2 Bucket
Truy cập vào Cloudflare Dashboard và truy cập vào phần R2 Object Storage

Bấm vào nút Create bucket để tạo nơi lưu trữ mới

Đặt tên cho bucket và bấm Create Bucket

Bucket lưu trữ đã được tạo thành công.

2. Kết nối tên miền
Truy cập vào phần Setting của bucket vừa tạo, tìm đến phần Cusom Domains và bấm Add.

Nhập vào tên miền bạn muốn sử dụng để truy cập vào hình ảnh lưu trữ trên bucket, ví dụ images.balodeplao.com, bấm Continue.

Bấm tiếp Connect domain để Cloudflare tự động tạo DNS Record.

Tên miền đã dược kết nối thành công

3. Cấu hình rclone
Sau khi đã tạo bucket thành công, mình sẽ upload ảnh từ máy tính lên Cloudflare R2 bằng rclone.
Trước tiên, cần phải lấy các thông số API cần thiết từ Cloudflare để cấu hình rclone. Quay lại trang quản lý R2 của Cloudflare, bấm vào nút Manage

Bấm vào Create Account API Token

Phần Permissions, chọn Object Read & Write , tiếp theo chọn bucket vừa tạo trong phần Specify bucket, bấm Create Account API Token

Lưu lại ba thông số Access Key ID, Secret Access Key và endpoint

Tiếp theo, cấu hình rclone trên máy bằng lệnh sau
rclone configCode language: Nginx (nginx)Cấu hình theo hướng dẫn bên dưới
n → Tạo mới
balodeplao-image → Đặt tên
4 → Chọn s3
7 → Cloudflare R2 Storage
1 → Chọn nhập thông số trực tiếp
[paste Access Key ID] → Nhập Access Key ID
[paste Secret Access Key] → Nhập Secret Access Key
→ Không cần nhập region, bấm Enter
[endpoint] → Nhập vào Endpoint
→ Còn lại Enter hếtCode language: CSS (css)Sau khi tạo thành công, terminal sẽ hiện ra thông tin như bên dưới, chọn q để thoát
Current remotes:
Name Type
==== ====
balodeplao-image s3
e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> qCode language: Dockerfile (dockerfile)Xác nhận kết nối thành công bằng lệnh rclone tree balodeplao-image:balodeplao-image, thấy hiện ra như bên dưới là OK
❯ rclone tree balodeplao-image:balodeplao-image
/
0 directories, 0 filesCode language: YAML (yaml)4. Upload ảnh lên Cloudflare R2
Di chuyển đến thư mục public của astro để upload ảnh lên Cloudflare R2
cd ~/blog-bldl/public
rclone copy images/ balodeplao-image:balodeplao-image/images/ \
--progress \
--transfers 4 \
--retries 10 \
--retries-sleep 5s \
--tpslimit 10Code language: YAML (yaml)Chờ 5-10 phút để rclone tải toàn bộ hình ảnh lên Cloudflare R2.
Nếu bị lỗi trong khi chạy, có thể chạy lệnh tương tự, rclone tự skip file đã upload, chỉ tiếp tục phần còn lại.
rclone copy images/ balodeplao-image:balodeplao-image/images/ \
--progress \
--transfers 4 \
--retries 10 \
--retries-sleep 5s \
--tpslimit 10
Transferred: 480.912 MiB / 480.912 MiB, 100%, 1.192 MiB/s, ETA 0s
Checks: 95 / 95, 100%, Listed 2476
Transferred: 2286 / 2286, 100%
Elapsed time: 7m47.1sCode language: YAML (yaml)Xác nhận lại xem số lượng khớp nhau không
echo "R2: $(rclone ls balodeplao-image:balodeplao-image/images/ | wc -l) files"
echo "Local: $(ls images/ | wc -l) files"Code language: Bash (bash)Ngon lành rồi
R2: 2380 files
Local: 2380 filesCode language: YAML (yaml)5. Cập nhật markdown để sử dụng ảnh từ Cloudflare R2
Hiện tại hình ảnh sử dụng trong các file md đang có dạng như sau , được trỏ đến thư mục ảnh public/images trên máy tính. Để có thể sử dụng link ảnh lưu trên Cloudflare R2, có 2 phương án:
- Cập nhật tất cả link ảnh trong file markdown thành link Cloudflare R2.
- Sử dụng remark plugin để tự động chuyển đổi link relative
, thànhkhi chạynpm run devhoặcnpm run build. Cách này không cần phải cập nhật file markdown.
Trong bài viết này mình sẽ sử dụng cách 1 vì nó phù hợp với các blog không cần phải cập nhật nội dung mới. Làm 1 lần là xong.
Tạo update-image-urls.sh trong thư mục của astro (blog-bldl) và nhập nội dung sau vào
#!/bin/bash
# update-image-urls.sh
# Thay local image paths bằng Cloudflare R2 URLs
BLOG_DIR="./src/content/blog"
IMAGE_DOMAIN="https://image.balodeplao.com" # <-- đổi lại domain của bạn
echo "🔄 Updating image URLs to $IMAGE_DOMAIN ..."
# Cập nhật ảnh trong nội dung bài (body)
find "$BLOG_DIR" -name "*.md" -exec \
sed -i '' "s|](/images/|](${IMAGE_DOMAIN}/|g" {} +
# Cập nhật image trong frontmatter
# (chỉ thay giá trị chưa có full URL — không bắt đầu bằng http)
find "$BLOG_DIR" -name "*.md" -exec \
sed -i '' "s|image: \"\([^h][^t]\)|image: \"${IMAGE_DOMAIN}/\1|g" {} +
echo ""
echo "✅ Done."Code language: Bash (bash)Cho chạy để cập nhật link
chmod +x update-image-urls.sh
./update-image-urls.shCode language: Nginx (nginx)Kiểm tra lại lần nữa đển bảo đảm tất cả các link ảnh đã được chuyển thành dạng https://image.balodeplao.com/images/image.jpg
6. Xóa ảnh khỏi repo
Tất cả ảnh đã được đưa lên Cloudflare R2, mình có thể xóa ảnh đang lưu trên máy
rm -rf ~/blog-bldl/public/imagesCode language: JavaScript (javascript)7. Xác nhận blog hoạt động ổn định
Mở lại dev server bằng lệnh npm run dev. Sau đó kiểm tra lại website local xem hình ảnh có tải bình thường không.
Nếu ảnh không hiển thị, cần phải kiểm tra lỗi trong log để khắc phục.
Vậy là xong giai đoạn 3 của công cuộc chuyển blog từ WordPress qua Astro. Trong [Phần 4] kế tiếp, mình sẽ chia sẻ cách đưa blog lên Github và deploy lên Cloudflare Pages.
Bạn đang xem loạt bài viết: WordPress to Astro Migration
- Phần 1: [WordPress → Astro] Phần 1 – Chuyển bài viết từ Database qua file Markdown
- Phần 2: [WordPress → Astro] Phần 2 – Cài đặt và cấu hình Astro làm blog
- Phần 3: [WordPress → Astro] Phần 3 – Upload ảnh lên Cloudflare R2





