S3: Lưu Trữ File và Host Một Trang Web Tĩnh
Trong bài này chúng ta dùng S3 để lưu file và host một trang web tĩnh. Khác với EC2 ở chỗ không có máy chủ nào chạy liên tục: bạn chỉ đẩy file lên, AWS lo phần phục vụ.
S3 (Simple Storage Service) là dịch vụ lưu trữ object. Nó không phải ổ đĩa hay hệ thống file thông thường mà là kho chứa file phẳng: mỗi file là một object, được đặt trong một bucket. S3 hợp để lưu ảnh, video, file backup, file tải về, và để host nội dung web tĩnh.
Mục tiêu
- Tạo một bucket S3.
- Upload file lên bucket bằng cả giao diện và CLI.
- Bật tính năng static website hosting và mở trang web ra Internet.
- Dọn dẹp bucket sau khi xong.
Chi phí dự kiến
S3 tính tiền theo dung lượng lưu trữ, số lượt request và lượng dữ liệu tải ra.
- Tài khoản mô hình credit (tạo sau 15/07/2025): chi phí trừ vào credit được tặng. Vài file HTML chỉ tính bằng phần nghìn cent, gần như bằng không.
- Tài khoản mô hình cũ (tạo trước 15/07/2025): 5 GB lưu trữ, 20.000 lượt GET, 2.000 lượt PUT mỗi tháng được miễn phí trong 12 tháng đầu.
Dù theo mô hình nào, vài file trong bài này gần như không đáng kể về chi phí. Ta vẫn dọn ở cuối, vì bucket để lại lâu ngày dễ thành nơi quên lãng.
Khái niệm: bucket và object
- Bucket là thùng chứa cấp cao nhất. Tên bucket phải duy nhất trên toàn cầu — không chỉ trong tài khoản bạn mà trên toàn bộ AWS. Vì vậy tên kiểu
testhaymy-bucketchắc chắn bị trùng; nên đặt tên có phần riêng, ví dụdevops-series-<tên-bạn>-2025. - Object là file bạn lưu trong bucket, kèm một key (giống đường dẫn). Một object
images/logo.pngcó key làimages/logo.png— dấu/chỉ là một phần của tên, S3 không có thư mục thật mà chỉ hiển thị như thư mục cho dễ nhìn.
Mặc định, mọi bucket và object đều riêng tư: chỉ tài khoản của bạn truy cập được. Muốn cho người ngoài xem (như khi host web), bạn phải chủ động mở quyền. Mặc định riêng tư này là có chủ đích, vì lộ dữ liệu do bucket để công khai nhầm là một trong những sự cố bảo mật phổ biến nhất trên cloud.
Bước 1: Tạo bucket
Đặt sẵn một biến tên bucket để dùng lại (thay phần đuôi cho duy nhất):
BUCKET=devops-series-yourname-2025
aws s3 mb s3://$BUCKET --region ap-southeast-1
s3 mb nghĩa là "make bucket". Nếu báo lỗi tên đã tồn tại, đổi sang tên khác duy nhất hơn.
Kiểm tra bucket đã có:
aws s3 ls
Bước 2: Upload file
Tạo vài file tĩnh trên máy để upload:
mkdir site && cd site
cat > index.html <<'EOF'
<!doctype html>
<html lang="vi">
<head><meta charset="utf-8"><title>Trang tinh tren S3</title></head>
<body>
<h1>Xin chao tu S3</h1>
<p>Trang nay duoc host truc tiep tu mot S3 bucket.</p>
<p><a href="about.html">Trang gioi thieu</a></p>
</body>
</html>
EOF
cat > about.html <<'EOF'
<!doctype html>
<html lang="vi">
<head><meta charset="utf-8"><title>Gioi thieu</title></head>
<body><h1>Gioi thieu</h1><p>Day la trang thu hai.</p></body>
</html>
EOF
Upload một file:
aws s3 cp index.html s3://$BUCKET/
Hoặc đồng bộ cả thư mục lên bucket:
aws s3 sync . s3://$BUCKET/
s3 sync chỉ tải lên những file mới hoặc đã thay đổi, nên rất tiện khi cập nhật site. Liệt kê object trong bucket:
aws s3 ls s3://$BUCKET/
Tới đây, file đã nằm trên S3 nhưng vẫn riêng tư — mở bằng URL công khai sẽ bị từ chối. Bước tiếp theo mới mở ra Internet.
Bước 3: Bật static website hosting
S3 có thể phục vụ nội dung tĩnh trực tiếp như một web server. Bật tính năng này:
aws s3 website s3://$BUCKET/ \
--index-document index.html \
--error-document index.html
Lệnh này chỉ định trang mặc định (index.html) và trang hiển thị khi gặp lỗi.
Để người ngoài xem được, ta cần làm hai việc: gỡ chặn truy cập công khai, rồi gắn một bucket policy cho phép đọc.
Gỡ "Block Public Access" cho bucket này:
aws s3api put-public-access-block \
--bucket $BUCKET \
--public-access-block-configuration \
"BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"
Tạo file policy cho phép mọi người đọc object trong bucket:
cat > policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::$BUCKET/*"
}
]
}
EOF
aws s3api put-bucket-policy --bucket $BUCKET --policy file://policy.json
Policy này chỉ cho phép đọc (s3:GetObject), không cho phép ghi hay xóa. Người ngoài xem được trang web nhưng không sửa được file của bạn.
Địa chỉ trang web có dạng:
http://<BUCKET>.s3-website-<region>.amazonaws.com
Với ví dụ trên (region ap-southeast-1):
http://devops-series-yourname-2025.s3-website-ap-southeast-1.amazonaws.com
Định dạng endpoint khác nhau theo region: một số region dùng dấu gạch ngang (
s3-website-<region>), số khác dùng dấu chấm (s3-website.<region>). Để chắc chắn, lấy đúng URL ở console: mở bucket, tab Properties, kéo xuống mục Static website hosting — AWS hiển thị sẵn đường dẫn chính xác.
Mở địa chỉ này trên trình duyệt, bạn sẽ thấy trang index.html, và link sang about.html cũng chạy. Cập nhật site về sau chỉ cần sửa file rồi chạy lại aws s3 sync . s3://$BUCKET/.
Trong môi trường thật, ít ai để bucket công khai trực tiếp. Cách phổ biến là đặt một CDN (CloudFront) phía trước, giữ bucket ở chế độ riêng tư và chỉ cho CloudFront đọc. Cách này nhanh hơn (có cache toàn cầu) và hỗ trợ HTTPS. Series giữ ở mức S3 website cho đơn giản; khi cần production, hãy tìm hiểu CloudFront kết hợp Origin Access Control.
🧹 Dọn dẹp
S3 tính tiền theo dung lượng lưu, nên cần xóa cả object lẫn bucket. Bucket còn object thì không xóa được, phải dọn object trước.
Cách nhanh nhất là xóa toàn bộ object rồi xóa bucket trong một lệnh:
aws s3 rb s3://$BUCKET --force
s3 rb là "remove bucket"; --force xóa hết object bên trong trước khi xóa bucket.
Nếu muốn làm rõ từng bước:
# Xóa hết object
aws s3 rm s3://$BUCKET --recursive
# Rồi xóa bucket rỗng
aws s3 rb s3://$BUCKET
Kiểm tra bucket đã biến mất:
aws s3 ls
Dọn nốt thư mục tạm trên máy nếu muốn:
cd .. && rm -rf site
Tổng kết
Bạn vừa lưu file lên S3 và host một trang web tĩnh ra Internet mà không cần server chạy liên tục, đồng thời thấy mặc định mọi thứ trên S3 là riêng tư cho tới khi bạn chủ động mở. S3 sẽ còn quay lại ở các bài sau như một nơi lưu trữ chung.
Bài 5 ta đụng tới database: tạo PostgreSQL trên RDS, kết nối từ EC2, và áp dụng đúng bài học từ Bài 3 — đặt database trong private subnet thay vì phơi ra Internet.