iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0
Modern Web

前端來點 AWS 技能樹!系列 第 28 篇

Day28 - ACM:幫 CloudFront 接上自己的 Domain 和 HTTPS

  • 分享至 

  • xImage
  •  

Day27 讓練習專案改由 S3+CloudFront 上線了,不過網址還是 CloudFront 給的 d111111abcdef8.cloudfront.net,又長又記不起來。今天要幫它接上自己的 Domain,把 HTTPS 憑證換成自己 Domain 的,最後再把昨天遇到的 403 換成我們自己的 404 頁面ㄅ!

要用哪個網址?

Day20 已經把 example.com 指到 EC2 了,所以今天不動它,另外開一個 Subdomain static.example.com 給 CloudFront 用:

網址 DNS Record 走哪條路
example.com A Record,指到 EC2 的 Elastic IP(Day20) EC2+Caddy+container
static.example.com CNAME Record,指到 d111111abcdef8.cloudfront.net(今天) S3+CloudFront

Subdomain 不用另外買。只要有 example.com,底下的 www、static 這些名字,在 DNS 加一筆 Record 就有了。像是 Day20 開的 www.example.com 就是一個 Subdomain,今天的 static.example.com 也是用一樣的方法開的。
同一個 Domain 底下的 Subdomain,可以各自指到不同的地方。DNS 只負責告訴瀏覽器「這個名字要去找誰」,後面是 EC2 還是 CloudFront,它不在乎。

HTTPS 憑證這次從哪裡來?

Day22 的憑證是 Caddy 在 EC2 上自動跟 Let's Encrypt 申請的。CloudFront 沒有可以讓我們裝 Caddy 的 Server,所以憑證改用 AWS 自己的憑證服務 ACM(AWS Certificate Manager):

EC2 這條路(Day22) CloudFront 這條路(今天)
誰發的憑證 Let's Encrypt Amazon(ACM)
怎麼證明 Domain 是你的 Let's Encrypt 連到你的 Server 確認,所以 80 port 要開 在 DNS 加一筆 ACM 指定的 CNAME Record
憑證放在哪裡 EC2 上的 Caddy CloudFront 的各個據點
誰負責續期 Caddy ACM,只要憑證有在用、驗證用的 CNAME Record 還在
費用 免費 免費

有一個規則一定要記住:給 CloudFront 用的 ACM 憑證,一定要在 us-east-1,也就是 US East (N. Virginia)(美國東部維吉尼亞北部)。CloudFront 是全球服務,只認這個 region 的憑證,就算 bucket 在台北也一樣。今天會用 CloudFront 的流程申請,而它會自動建在 us-east-1。如果你想先到 ACM 自己申請,記得先把右上角的 region 切過去,不然等一下在 CloudFront 會找不到這張憑證喔!

為什麼 DNS 要放到最後?

今天的流程是這樣:

  1. 在 CloudFront 加上 Domain,順便申請憑證
  2. 到 Cloudflare 加一筆驗證用的 CNAME Record,讓 ACM 確認 Domain 是你的
  3. 憑證發下來之後,把 Domain 正式加到 distribution
  4. 最後才到 Cloudflare 加一筆 CNAME Record,把 static.example.com 指到 CloudFront

如果一開始就把 static.example.com 指到 CloudFront,但 distribution 還不認得這個 Domain、手上也沒有它的憑證,瀏覽器連過去只會看到憑證錯誤。而等 CloudFront 都準備好了才改 DNS,網址一接上就是好的。
如果你的 Domain 是 .dev、.app 這類瀏覽器一律強制 HTTPS 的(Day20 提過),或是主 Domain 的 HSTS 設定包含了 Subdomain(includeSubDomains),瀏覽器遇到憑證錯誤時,連「繼續前往」的選項都不會給,所以這個順序就更重要了。

在 CloudFront 加上 Domain、申請憑證

到 CloudFront 的 Console,點進 Day27 建立的 distribution:

  1. 在 General Tab 的 Settings 區塊找到 Alternate domain names,按 Add a domain。
  2. 填 static.example.com,按 Next。
  3. 到了 TLS certificate 這一步,CloudFront 會先找 us-east-1 有沒有這個 Domain 的憑證。我們還沒有,所以按 Create certificate 建立一張新的。Create a wildcard certificate 不用勾,我們只需要 static.example.com 這一個名字。
    https://ithelp.ithome.com.tw/upload/images/20261012/20179793BerbfgC2yv.png
    建立之後,畫面上會出現一組要加到 DNS 的 CNAME Record,長得像這樣:
欄位 範例
Record name _3639ac514e785e898d2646601fa951d5.static.example.com.
Record type CNAME
Record value _98d2646601fa951d53639ac514e785e8.xxxxxxxxxx.acm-validations.aws.

這一頁先不要關,接下來要把它加到 Cloudflare。

到 Cloudflare 加驗證用的 CNAME

ACM 不會連到你的 Server,而是請你在 DNS 加一筆它指定的 Record。你加得上去,就代表你管得了這個 Domain 的 DNS,也就證明 Domain 是你的。
進入 Cloudflare 中的 example.com,找到 DNS → 記錄(Records),按新增記錄(Add record),跟 Day20 一樣新增一筆 CNAME:

欄位 這次填什麼
類型(Type) CNAME
名稱(Name) 貼上 Record name
目標(Target) 貼上 Record value
代理狀態(Proxy status) 僅 DNS(DNS only,灰雲)
存活時間(TTL) 自動(Auto)

儲存之後,檢查名稱那一欄有沒有出現兩次 example.com。有些 DNS 服務會自動在名稱後面補上 Domain,如果貼的是完整名稱,就可能變成 ….static.example.com.example.com,這樣驗證會失敗。
想自己確認 Record 有沒有生效,可以在 Mac 的終端機查查看:

dig +short CNAME _3639ac514e785e898d2646601fa951d5.static.example.com

有回傳 ….acm-validations.aws. 就代表加好了。
回到 CloudFront 的頁面按 Validate certificate,通常幾分鐘內就會驗證成功。
這筆 CNAME Record 之後不要刪喔!ACM 會在憑證到期前自動續期,續期時也要靠它確認 Domain 還是你的。

把 Domain 加到 distribution

憑證驗證成功後按 Next,確認一下內容,再按 Add domains。
distribution 的 Last modified 會先顯示 Deploying,等幾分鐘變回日期和時間,就部署完成了。

到這裡,distribution 已經認得 static.example.com,也有它的憑證了,只差 DNS 還沒有指過來。

把 static.example.com 指到 CloudFront

回到 Cloudflare 的新增記錄(Add record),再加一筆 CNAME。作法跟 Day20 開 www 一模一樣,差別只在目標(Target):www 指到自己的網域,static 指到 CloudFront:

欄位 Day20 的 www 今天的 static
類型(Type) CNAME CNAME
名稱(Name) www static
目標(Target) example.com distribution 的 Distribution domain name,例如 d111111abcdef8.cloudfront.net
代理狀態(Proxy status) 僅 DNS(DNS only,灰雲) 僅 DNS(DNS only,灰雲)
存活時間(TTL) 自動(Auto) 自動(Auto)

CNAME 的意思也跟 Day20 一樣:static.example.com 是 d111111abcdef8.cloudfront.net 的別名,瀏覽器查 static.example.com 時,會沿著它找到 CloudFront 的 IP。
代理狀態也一樣要選灰雲。Day20 選灰雲,是為了讓瀏覽器直接連到 EC2;今天則是要讓瀏覽器直接連到 CloudFront,拿到剛剛 ACM 發的憑證。如果選橘雲,Cloudflare 會擋在前面,瀏覽器拿到的會是 Cloudflare 的憑證,等於在 CloudFront 前面又多了一層 CDN。

驗收

DOMAIN=static.example.com
dig +short "$DOMAIN"
curl -sI "https://$DOMAIN/" | grep -iE '^(HTTP|x-cache|content-type)'
curl -sv -o /dev/null "https://$DOMAIN/" 2>&1 | grep -iE 'subject:|issuer:|expire date:'

結果會出現類似:

d111111abcdef8.cloudfront.net.
192.0.2.10
192.0.2.11
HTTP/2 200
content-type: text/html
x-cache: Hit from cloudfront
*  subject: CN=static.example.com
*  expire date: Apr 27 23:59:59 2027 GMT
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M04
看哪裡 正常的話
dig +short 第一行是 d111111abcdef8.cloudfront.net.,後面接著幾個 IP
curl -sI HTTP/2 200 和 content-type: text/html
subject: CN=static.example.com,代表這張憑證是發給我們的 Domain
issuer: 裡面有 O=Amazon,代表憑證是 ACM 發的
expire date: 憑證到期日,到期前 ACM 會自動續期

用瀏覽器打開 https://static.example.com,點網址列左邊的圖示,也可以看到憑證是 Amazon 發的。原本的 https://d111111abcdef8.cloudfront.net 還是可以用,兩個網址連到的是同一個 distribution。
如果 dig 什麼都沒回傳,先等幾分鐘再查。DNS 會把「查不到」的結果記住一段時間,如果加 Record 之前就查過這個名字,可能要等這段時間過去才查得到。

換上自己的 404 頁面

Day27 試過打一個不存在的路徑會拿到 403:bucket policy 只給 CloudFront 讀檔案的權限,S3 沒辦法告訴它「這個檔案不存在」。專案匯出時已經有一個 404.html,我們讓 CloudFront 遇到 403 時改回傳這個頁面,狀態碼也改成 404:

  1. 在 distribution 切到 Error pages Tab,按 Create custom error response。
  2. HTTP error code 選 403: Forbidden。
  3. Error caching minimum TTL 維持預設的 10,意思是這個錯誤結果在據點上快取 10 秒。
  4. Customize error response 選 Yes。
  5. Response page path 填 /404.html。
  6. HTTP Response code 選 404: Not Found。
  7. 按 Create,等 distribution 部署完成。

https://ithelp.ithome.com.tw/upload/images/20261012/20179793dRi5ZsseQ9.png
再試一次不存在的路徑:

curl -sI "https://$DOMAIN/abc" | grep -iE '^(HTTP|content-type)'

這次會看到 HTTP/2 404 和 content-type: text/html,用瀏覽器打開也會看到練習專案的 404 頁面了!

PS. 這樣設定之後,所有的 403 都會變成 404 頁面。之後如果 OAC 或 bucket policy 設壞了,看到的也會是 404,除錯時要記得這件事。另一種做法是在 bucket policy 多給 CloudFront s3:ListBucket 權限,讓 S3 自己回 404;這篇先用比較簡單的做法。

費用的部分

  • ACM 發給 CloudFront 用的公開憑證不用錢。但如果你是到 ACM 自己申請,看到 Enable export 不要選,那是可以匯出私鑰的憑證,要另外收費,CloudFront 也用不到這個。
  • CloudFront 接自己的 Domain 是用 SNI(瀏覽器在建立 HTTPS 連線時,先說出要連哪個 Domain,CloudFront 才知道要拿出哪一張憑證),不會另外收費。但如果你是從 Settings 的 Edit 選憑證,會看到 Legacy clients support,那是給不支援 SNI 的舊瀏覽器用的專屬 IP,一個月 600 美元,千萬不要選。
  • Cloudflare 的 DNS Record 也不用錢。

今天練習專案的 S3 版有了自己的網址,HTTPS 也換成自己 Domain 的憑證,不存在的路徑也會看到 404 頁面了。不過每次改內容,還是要自己 build、aws s3 sync、再清 CloudFront 的快取,有點麻煩。下一篇來調整快取的設定,再把這些步驟交給 GitHub Actions,push 之後就自動部署ㄅ!

參考資料


上一篇
Day27 - 認識 S3+CloudFront,手動讓首頁上線
系列文
前端來點 AWS 技能樹! 共 28 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言