iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
Modern Web

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

Day30 - 回顧兩條部署路線,前端該怎麼選?

  • 分享至 

  • xImage
  •  

終於來到最後一天了!這 30 天,我們把一個 Next.js 專案從 Docker 化開始,送上 EC2、接上 Domain 和 HTTPS、交給 GitHub Actions 自動部署,最後又換一條路,用 S3+CloudFront 讓它上線。今天來回顧這兩條路,再整理一份「前端要怎麼選」的判斷方法ㄅ!

30 天走過的路

階段 文章 做了什麼
起步 Day1~Day5 認識雲服務、建立 AWS 帳號、IAM 和 AWS CLI
Docker Day6~Day9 跑第一個 container,用多段式 Dockerfile 把 Next.js 打包成 Image
EC2 Day10~Day13 開 EC2、用 Session Manager 連進去、把 Image 推上 ECR 跑起來
網路 Day14~Day18 IP、Port、VPC、路由表,以及固定 IP 的 Elastic IP
Domain 與 HTTPS Day19~Day22 DNS、Cloudflare 的 Record、TLS 憑證,用 Caddy 開 HTTPS
自動化與維運 Day23~Day26 IaC 與 CI/CD 的觀念、OIDC、deploy.yml,以及上線之後要顧的事
S3+CloudFront Day27~Day29 靜態匯出、私有 bucket+OAC、ACM 憑證、Cache 規則和自動部署

最後的架構圖

兩條路放在一起,就是這 30 天做出來的全部:
https://ithelp.ithome.com.tw/upload/images/20261014/201797938u7nyjvKHo.png
同一份程式碼,push 到 main 一次,兩條路會各自 build、各自部署。差別在使用者連進來的時候:EC2 那條路有一台 Server 在跑 Next.js,S3 那條路只有 build 好的檔案。

兩條路比一比

EC2 S3+CloudFront
網站是什麼 一個一直在跑的 Next.js Server 一堆 build 好的 HTML、CSS、JS
能做的事 Next.js 的功能都能用:API route、讀 cookie、每次請求才產生的頁面 提供 build 好的 HTML、CSS、JS,瀏覽器仍能呼叫另外部署的 API
費用 開著就收錢,一個月大約 13 美元 照用量計算,小網站幾乎是 0
要顧的事 作業系統更新、Docker、Caddy、logs(Day26) 幾乎沒有,S3 和 CloudFront 都是 AWS 在顧
離使用者多遠 一台主機在台北,使用者越遠越慢 CloudFront 在世界各地都有據點
流量突然變大 t3.micro 撐不住,要自己換機型或加機器 CloudFront 自己扛
部署 大約 3 分鐘,換 container 那一兩秒會回 502(Day25) 大約 3 分鐘,網站不會中斷(Day29)
憑證 Caddy 跟 Let's Encrypt 申請,Caddy 自己續期 ACM 發的,ACM 自己續期

前端要怎麼選?

Day1 提過:這次的專案是 Next.js SSR,需要一台真的在跑 Node 的機器;如果專案是純靜態的 SPA,路線會不一樣。走完兩條路之後,可以把這句話變成一個問題來問自己:

上線之後,是把 npm run build 產生的資料夾放上去就好,還是要有一個 npm start 一直開著?

如果是資料夾放上去就好,就走 S3+CloudFront;如果是要一直開著,就走 EC2。接下來分幾種情況來看。

先看專案類型

專案 怎麼選
Vite+React 或 Vue 的 SPA、Astro、VitePress、作品集、活動頁 build 出來就是 HTML、CSS、JS,走 S3+CloudFront
Next.js、Nuxt 這類可以在 Server 上產生頁面的框架 要看用了哪些功能,Next.js 的話看下一段

Next.js:用 output: 'export' build 一次

最快的初步檢查,就是加上 output: 'export' 實際 build 一次,看看錯誤和警告。不過 build 成功不代表所有功能都正常,例如 rewrites、redirects、headers 不會隨靜態檔案一起生效,上線後還是要實際測試。Next.js 文件列出的不支援功能,換成前端常見的情境是這樣:

用到了 常見的情境
cookies()、會讀 request 的 Route Handler 依照登入狀態顯示不同內容、用 API route 接表單
Server Actions 表單送出之後在 Server 上執行
Proxy(Next.js 15 以前叫 Middleware) 沒有登入就導去登入頁
ISR 每隔一段時間重新產生頁面
動態路由,但沒有 generateStaticParams 文章頁、商品頁的 id 是使用者新增的,build 的時候不知道有哪些
next.config 裡的 rewrites、redirects、headers 轉址、加 header
next/image 預設的圖片壓縮 這個有解:Day27 用的 images.unoptimized

一個都沒用到,就走 S3+CloudFront。有用到的話,先想想能不能換掉,例如資料改在瀏覽器裡抓;換不掉,就走 EC2。

後端在別台,前端就一定能放 S3 嗎?

不一定,要看前端怎麼接後端。用 Vite 做的 SPA,在瀏覽器裡直接呼叫後端的 API,前端就只是一包靜態檔案,可以放 S3。但如果在前端專案裡用 Next.js 的 API route 當中間層,例如把 API key 藏在 Server 上,或是由 Server 幫忙設定 HttpOnly 的 cookie,這一層就需要 Server。像我的 side project 就是這樣:後端是另一台 Server,但前端有登入、上傳這些要經過 API route 處理的功能,所以正式站還是只能走 EC2。

兩條也可以一起走

不一定要二選一。像是有些網站有登入和上傳功能,所以放在 EC2;另外把首頁用成像是展示用的,資料是寫死的,就放在 S3+CloudFront。正式站用原本的 Domain,展示版用另一個 Subdomain,各自部署,互不影響。
如果你的 SPA 有好幾個頁面,例如 /about,放上 S3 之後還要多設一個 custom error response:遇到 403 時回傳 /index.html,狀態碼改成 200。不然在 /about 按重新整理,S3 找不到 about 這個檔案,就會看到 403。設定的地方跟 Day28 的 404 頁面一樣,同一個錯誤碼只能設一種回應,SPA 就改成回傳 /index.html。

還有第三條:交給平台

Day1 提到的 Vercel、Zeabur、GitHub Pages 這類部署平台,還是讓網站上線最快的方法。Day10 說選 EC2,是想親手把流程跑過一遍,看看平台幫我們做了什麼。現在回頭看,平台默默做掉的事,就是這 30 天的內容:build、HTTPS 憑證、CDN、push 之後自動部署。知道這些之後,遇到平台的限制,或是公司要求放在自己的 AWS 帳號時,就知道該從哪裡下手了。

不用了,怎麼收掉?

練習完不打算繼續用的話,記得把資源收掉。原則是由外往內:先拿掉使用者連進來的入口(DNS),再刪後面的服務,最後才刪權限。

  1. GitHub:到 Actions Tab,把 Deploy to EC2 和 Deploy static site 都設成 Disable workflow,或是直接刪掉兩個 workflow 檔,不然之後每次 push 都會部署失敗。
  2. Cloudflare:刪掉 example.com 的 A Record、www 和 static 的 CNAME。ACM 驗證用的那筆 CNAME 先留著。
  3. CloudFront:先按 Disable,等 Last modified 變回日期和時間,才能按 Delete。如果 Day27 選的是 Free 這類固定月費的方案,要先取消方案,等這個計費週期結束才能刪。distribution 刪掉之後,左邊選單 Origin access 裡的 OAC 也可以一起刪掉。
  4. ACM:切到 us-east-1,刪掉那張憑證,再回 Cloudflare 刪掉驗證用的 CNAME。
  5. S3:先 Empty 清空 bucket,再 Delete。如果之後還可能用到這個名稱,AWS 文件建議清空就好、不要刪,空的 bucket 不會收儲存的費用。
  6. EC2:把 instance Terminate,再到 Elastic IPs 選 Release Elastic IP addresses。終止 EC2 不會自動釋放 Elastic IP,不釋放就會一直收費。最後可以把 Security group 也刪掉。
  7. ECR:刪掉 my-app 這個 repo,裡面的 Image 會一起刪除。
  8. CloudWatch:刪掉 Day26 建立的告警,以及 SNS 的 topic。
  9. IAM:刪掉 gha-deploy-role、ec2-app-role。GitHub 的 OIDC 身分提供者如果沒有別的 repo 在用,也可以一起刪掉。
  10. Billing:隔一兩天回來看一次,確認沒有新的費用。Budgets 的預算通知不用錢,可以留著。

順序為什麼重要?

  • 先刪 DNS,再刪 Elastic IP 和 CloudFront:Elastic IP 釋放之後會回到 AWS 的 IP 池,可能分配給別人。如果 DNS 還指著它,我們的網域就會連到別人的 Server,這叫做 dangling DNS。
  • 先刪 CloudFront,再刪 S3 bucket:bucket 的名稱全世界只能有一個,刪掉之後別人可以拿去用。如果 distribution 還指著這個名稱,就可能把別人 bucket 裡的檔案送到你的網址上。AWS 的文件也寫明,要先刪 distribution,再刪當作 origin 的 bucket。

Domain 是一年一年續約的,如果不打算繼續用,記得到 Cloudflare 關掉自動續約。

回頭看,最值得記住的幾個坑

  • Mac 的 M 系列晶片 build 出來的是 arm64 的 Image,EC2 是 x86,要加 --platform linux/amd64(Day13)
  • EC2 Stop 再 Start 之後,自動指派的公網 IP 會變,要用 Elastic IP 固定(Day18)
  • .dev、.app 這類網域,瀏覽器一律要求 HTTPS(Day20)
  • 新建的 GitHub repo,OIDC token 的 sub 換了新格式,照舊教學寫的 trust policy 會被擋下來(Day24)
  • workflow 檔要放在被 push 的那個 branch 上,docker image prune 要加 -a 才清得掉舊版本(Day25)
  • CloudFront 的建立流程裡沒有 Default root object,要建好之後再補(Day27)
  • 給 CloudFront 用的 ACM 憑證一定要在 us-east-1(Day28)
  • S3 不會幫檔案加 Cache-Control,沒設的話 CloudFront 預設放 24 小時,瀏覽器也會自己猜(Day29)

這些坑大多是「照著做卻跑不起來」的那種,錯誤訊息也不一定直接告訴你原因。Day1 說過,現在可以請 AI 帶著部署,但觀念還是要懂,不然 AI 不小心失控的時候才來得及阻止它!

完賽!

謝謝每一位看到這裡的人!這個系列從帳號都還沒開,一路走到兩條路都能 push 就自動部署。也希望這系列可以對同樣想替自己的專案點一下 AWS 技能樹的前端工程師有一點幫助。我們下次見ㄅ!

資安小提醒:收掉資源的時候,先刪 DNS Record,再釋放 Elastic IP 或刪除 CloudFront,避免 Domain 指向別人的資源。用完的 access key、IAM Role 和 OIDC 身分提供者也記得一起刪掉。

參考資料


上一篇
Day29 - 設好 Cache,讓 GitHub Actions 自動部署到 S3+CloudFront
系列文
前端來點 AWS 技能樹! 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言