如何使用 Amazon S3 架設靜態網站
使用 Amazon S3 建立靜態網站,介紹 Console 與 Terraform 建立 Bucket、靜態網站託管、公開存取政策、重新導向,以及網站檔案上傳與測試。
Amazon S3 除了可以存放檔案,也能用來快速架設靜態網站。
如果網站只包含 HTML、CSS、JavaScript、圖片等靜態檔案,便不需要先建立 EC2、安裝 Web Server,日後也不用自行負責作業系統與伺服器的維運。
因此,S3 不只是適合用來展示概念驗證(PoC),也是一個設定簡單、維運成本低的靜態網站託管服務。
不過,S3 靜態網站託管有一個重要限制:S3 的 Website endpoint 只支援 HTTP,不支援 HTTPS。這篇文章先以簡單可運作的 S3 靜態網站為主,說明基本設定與存取方式。
建立 S3 Bucket
首先進入 Amazon S3 Console,建立一個新的 Bucket。
Bucket 名稱必須符合 DNS 命名規則,而且在 AWS 的所有帳號與 Region 中都必須是唯一的。這個名稱除了是 Bucket 的識別名稱,也會成為之後網站網址的一部分,因此建議一開始就使用不容易變動的名稱。
物件擁有權
在「物件擁有權」設定中,通常保留預設的「ACL 停用」即可。
停用 ACL 後,物件的存取權限會集中由 Bucket policy 或 IAM policy 管理,權限邏輯會比較容易理解,也能避免不同上傳者造成物件擁有權不一致的問題。
只有在確定需要使用舊式 ACL,或是必須針對個別物件設定 ACL 時,才需要考慮啟用 ACL。
封鎖公開存取
如果要直接透過 S3 Website endpoint 讓任何訪客讀取網站內容,就必須取消「封鎖所有公開存取」。
取消後,AWS 會要求確認此 Bucket 可能被公開存取。請先確認 Bucket 只會存放可以公開提供的網站檔案,不要把密碼、私密金鑰、備份檔或其他敏感資料放在裡面。
如果帳號層級的 Block Public Access 仍然開啟,Bucket 層級的設定可能仍無法讓公開 policy 生效。這時需要依照組織的安全規範,檢查帳號或 Organization 層級的公開存取設定。
其餘設定先維持預設值,接著按下「建立 Bucket」即可。
啟用靜態網站託管
建立 Bucket 後,進入 Bucket 的「屬性」分頁,拉到頁面最下方,找到「靜態網站託管」。
按下「編輯」,啟用靜態網站託管,並設定以下內容:
- 索引文件:
index.html - 錯誤文件:
error.html
索引文件是使用者進入網站根目錄時,S3 預設回傳的頁面;錯誤文件則是在找不到檔案時顯示的頁面。錯誤文件可以依照網站需求改成其他檔名,但檔案必須實際存在於 Bucket 中。
設定完成後,S3 會在同一個頁面顯示 Website endpoint。建議直接複製 Console 顯示的網址,因為不同 Region 的 endpoint 格式可能略有差異。
設定網站重新導向
如果網站路徑有變更,可以使用重新導向規則,避免原本的網址直接變成 404。
例如,網站中的 docs 資料夾改名為 documents,就可以把原本以 docs/ 開頭的請求導向新的路徑:
1
2
3
4
5
6
7
8
9
10
[
{
"Condition": {
"KeyPrefixEquals": "docs/"
},
"Redirect": {
"ReplaceKeyPrefixWith": "documents/"
}
}
]
這類規則適合處理網站路徑調整或舊網址相容問題。若只是單一頁面的變更,也可以在網站程式中處理導向,或直接保留一個舊檔案來轉址。
設定 Bucket policy
S3 預設不會讓網際網路上的匿名使用者讀取物件。若要讓靜態網站公開,必須建立一個只允許讀取物件的 Bucket policy。
進入 Bucket 的「權限」分頁,在「Bucket policy」中貼上以下內容,並將 YOUR_BUCKET_NAME 替換成實際的 Bucket 名稱:
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicReadForWebsite",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
}
]
}
這個 policy 的作用是允許任何人讀取 Bucket 中的物件,但不包含上傳、修改或刪除權限。若只想公開某個資料夾,也可以把 Resource 限縮成特定 prefix,例如:
1
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/public/*"
如果覺得每個物件都要設定存取權限很麻煩,使用 Bucket policy 會比較適合。之後上傳新的檔案,只要檔案位於 policy 的範圍內,就會自動套用相同的讀取規則,不需要逐一設定物件權限。
將 Bucket 設為公開,代表任何人都可能讀取範圍內的物件。請確認 Bucket 只存放可公開的網站資源,並定期檢查 Bucket policy 與存取紀錄。
上傳網站檔案並測試
接著將 index.html、error.html、CSS、JavaScript 與圖片等網站檔案上傳到 Bucket。
完成後,使用 S3 Console 顯示的 Website endpoint 開啟網站。一般會是以下其中一種格式:
1
http://YOUR_BUCKET_NAME.s3-website-YOUR_REGION.amazonaws.com
或:
1
http://YOUR_BUCKET_NAME.s3-website.YOUR_REGION.amazonaws.com
例如,網站根目錄會自動載入先前設定的 index.html;如果直接輸入一個不存在的路徑,則會顯示 error.html。
Website endpoint 與 REST endpoint 的差異
這兩種網址很容易混淆:
| Endpoint | 用途 | HTTPS | 是否套用網站設定 |
|---|---|---|---|
| S3 Website endpoint | 存取靜態網站 | 不支援 | 支援 index、error 與 redirect |
| S3 REST endpoint | 存取指定物件或使用 S3 API | 支援 | 不套用 Website endpoint 的網站行為 |
例如,https://YOUR_BUCKET_NAME.s3.YOUR_REGION.amazonaws.com/index.html 是 REST endpoint 的物件網址。它可以用 HTTPS 讀取指定的 index.html,但不等同於 S3 靜態網站的 Website endpoint,也不會完整套用網站根目錄、錯誤頁面與重新導向設定。
使用 Terraform 建立
除了使用 AWS Console,也可以使用 Terraform 管理 S3 靜態網站。以下範例會建立 Bucket、物件擁有權設定、公開存取設定、Website configuration,以及允許公開讀取物件的 Bucket policy。
請先將範例中的 Bucket 名稱替換成符合 DNS 命名規則,且在所有 AWS 帳號與 Region 中都唯一的名稱。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
resource "aws_s3_bucket" "markmew_s3_static_html" {
bucket = "markmew-s3-static-html"
}
resource "aws_s3_bucket_ownership_controls" "markmew_s3_static_html" {
bucket = aws_s3_bucket.markmew_s3_static_html.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
resource "aws_s3_bucket_public_access_block" "markmew_s3_static_html" {
bucket = aws_s3_bucket.markmew_s3_static_html.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_acl" "markmew_s3_static_html" {
depends_on = [
aws_s3_bucket_ownership_controls.markmew_s3_static_html,
aws_s3_bucket_public_access_block.markmew_s3_static_html,
]
bucket = aws_s3_bucket.markmew_s3_static_html.id
acl = "public-read"
}
resource "aws_s3_bucket_website_configuration" "markmew_s3_static_html" {
bucket = aws_s3_bucket.markmew_s3_static_html.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
data "aws_iam_policy_document" "markmew_s3_static_html_public_read" {
statement {
sid = "AllowPublicReadForWebsite"
effect = "Allow"
principals {
type = "*"
identifiers = ["*"]
}
actions = [
"s3:GetObject",
]
resources = [
"${aws_s3_bucket.markmew_s3_static_html.arn}/*",
]
}
}
resource "aws_s3_bucket_policy" "markmew_s3_static_html_public_read" {
depends_on = [
aws_s3_bucket_public_access_block.markmew_s3_static_html,
]
bucket = aws_s3_bucket.markmew_s3_static_html.id
policy = data.aws_iam_policy_document.markmew_s3_static_html_public_read.json
}
監控請求與成本
S3 的費用不只包含儲存空間,也可能包含請求次數、資料傳出與其他相關服務費用。網站流量增加時,建議定期檢查 S3 的儲存量、請求數與資料傳出量。
如果需要更細緻地觀察請求數、錯誤與延遲,可以參考之前的文章:如何啟用 Amazon S3 Request Metrics:用 CloudWatch 監控請求、錯誤與延遲。
監控之外,也建議設定 AWS Budgets 或 CloudWatch Alarm,在流量或費用異常時及早收到通知。若網站內容是公開的,還要留意檔案被大量下載或遭到惡意請求的情況。
結語
使用 S3 架設靜態網站的流程並不複雜:建立 Bucket、啟用靜態網站託管、設定公開讀取 policy,再上傳網站檔案,就能快速得到一個可以存取的網站。
這種方式很適合個人網站、文件頁面、產品展示頁與概念驗證。由於直接公開 S3 Website endpoint 只支援 HTTP,使用前請先確認網站內容不涉及需要加密傳輸的敏感資訊。
在啟用公開存取前,先確認 Bucket 裡沒有敏感資料;網站上線後,再搭配成本監控與請求監控,就能在維持簡單架構的同時,降低誤設權限與流量異常造成的風險。





