你好,你好!想用幾乎沒有花費的方式在AWS上部署一個網站,並且還帶有GitHub自動部署流程?這就是這篇文章要教你的,沒有拖泥帶水.
這個想法很簡單:找一個現成的倉儲(開源,MIT,最後有鏈接),了解背後運作的方式,並且適應到你的專案。可以是作品集、首頁、靜態文件、React、Vue、Vite、Astro的SPA。只要最後能生成HTML/CSS/JS,就行。
在代碼崩潰前,我們快速對齊三個概念。有經驗的話,請直接跳到實際操作部分.
AWS,這是什麼?
AWS是亞馬遜的雲服務。你不需要購買伺服器,插上電源然後祈禱它不會崩潰,而是按需租用"塊塊"基礎設施。從簡單的(在S3上存儲文件)到複雜的(管理的Kubernetes集群、多區域數據庫、生成式AI等)。
供宿主靜態網站,我們會使用四個基本小工具:
- S3:對象儲存。想像一下雲端中的一個資料夾,你把你的檔案放進去。
- CloudFront:全球CDN。將網站分發到AWS的全球邊緣伺服器,所以東京的人載入快速就像聖保羅的人一樣。
- ACM: SSL憑證管理器。免費HTTPS,自動更新。
- IAM: 控制誰能做什麼。權限、角色等。
而Cloudflare,在AWS之外,作為DNS供應商登錄。它的免費方案已經能解決,不需要購買Route 53。
基礎設施即代碼(IaC),是為了什麼?
歌劇摘要:你不需要點擊AWS控制台,而是在代碼文件中描述基礎設施。優點:
- 可在Git中進行版本控制.
- 使用一個命令即可部署到任何環境.
- 如果出錯,可以通過diff來檢查.
- 基礎設施的代碼審查,老兄.
最知名的工具有:Terraform、Pulumi、CloudFormation (來自AWS) 和 AWS CDK,我們要使用什麼?
AWS CDK,這是什麼?
CDK = Cloud Development Kit。它是用於在 AWS 上編寫基礎設施的「現代」方式。你不需要編寫巨大的 YAML/JSON(純 CloudFormation),而是編寫 TypeScript、Python、Java、Go 或 C#。CDK 將其編譯為 CloudFormation,然後 AWS 執行。
優勢:您獲得自動補全、類型檢查、高階抽象(稱為「構建式」)。您不必為 CloudFront 配置 20 個功能,包括 OAC、私有 S3 和桶策略,您只需實例化一個類別即可完成。
關於 CDK 堆疊的一個簡單例子:
export class MinhaStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const bucket = new s3.Bucket(this, 'MeuBucket', {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
encryption: s3.BucketEncryption.S3_MANAGED,
});
}
}
即時,這樣就會建立一個已啟用加密的私有 S3。無需點擊任何地方。
我們要搭建的架構如下:
網站的流程是這樣:
翻譯:
- 用戶在瀏覽器中訪問
seusite.com。 - Cloudflare 解析 DNS 並指向 CloudFront。
- CloudFront 透過 HTTPS (ACM 証書) 使用 OAC 來拉取 S3 個人化儲存空間的檔案.
- S3 從不會變成公開.
與它溝通的就只有 CloudFront.
- 而在部署方面:
main您會將 branch 推送到 __JHSNS_SEG_98a392ea_43__. - GitHub Actions 透過 OIDC 自動認證 AWS (無固定 access key,更安全).
- 執行
cdk deploy,進行s3 sync指令無效,清除 CloudFront 缓存。
很棒呢? 馬上部署運行吧。
存儲庫
專案已上傳,MIT 授權,隨意克隆:
github.com/markgerald/aws-cdk-static-site-starter
提供英文和葡萄牙文的文件版本。 在這篇帖子裡我將總結幸福的路徑.
前置條件
在做任何事之前,你需要:
- AWS帳戶(有免費套餐,可以免費玩)。
- 安裝Node.js 22+.
- 設定AWS CLI (
aws configure). - 在Cloudflare上擁有域作為權威DNS。
如果你從未安裝Node/AWS CLI,這裡有一個逐步教程:本地安裝.
要設定Cloudflare,請按照這個:Cloudflare中的域名、DNS和SSL/TLS.
克隆並設定.env
git clone https://github.com/markgerald/aws-cdk-static-site-starter.git
cd aws-cdk-static-site-starter
cp .env.example .env
打開.env沒有編輯器就無法調整。這是設定中的核心:
PROJECT_NAME=meu-site
DOMAIN_NAME=meusite.com
WWW_DOMAIN_NAME=www.meusite.com
AWS_ACCOUNT_ID=123456789012
AWS_REGION=eu-west-1
CERTIFICATE_REGION=us-east-1
ENABLE_SPA_FALLBACK=true
CREATE_GITHUB_OIDC_ROLE=false
GITHUB_OWNER=seuuser
GITHUB_REPO=seu-repo
GITHUB_BRANCH=main
GITHUB_OIDC_PROVIDER_ARN=
注意兩點:
-
CERTIFICATE_REGIONtem要成為us-east-1. CloudFront 只接受此區域的特定 ACM,是 AWS 的規則。 -
AWS_REGION可以是你想要的任何地方。我使用eu-west-1按預設,但sa-east-1(São Paulo) 功能相同.
安裝並進行 bootstrap
npm install
# Bootstrap nas duas regiões (cert e stack principal)
npx cdk bootstrap aws://123456789012/us-east-1
npx cdk bootstrap aws://123456789012/eu-west-1
Bootstrap 是 CDK 在賬戶上進行的一個 "初始設定"。創建資產儲存桶、設置部署角色等。每個區域運行一次即可忘記.
首次部署
npm run build
npm run build:site
npm test
npx cdk deploy --all --require-approval never
第一次,ACM 會停留等待 DNS 驗證。這是這樣的:AWS 需要確認域名是您的。它會提供一些奇怪的 CNAME 供您複製到 Cloudflare.
前往 AWS 控制台> ACM> 地區 us-east-1> 你的證書。它顯示了類似:
Name: _abc123.meusite.com
Value: _xyz789.acm-validations.aws
Type: CNAME
複製這些到 Cloudflare, DNS only (灰雲,無代理)。等待幾分鐘,ACM 標記 Issued 並繼續部署。
驗證的細節:教學雲端(Cloudflare) ACM 沒有儲存庫.
指定域名給 CloudFront
堆疊建立後,CDK 會回傳類似 d111111abcdef8.cloudfront.net 的輸出。前往 Cloudflare 並建立:
Type Name Target
CNAME @ d111111abcdef8.cloudfront.net
CNAME www d111111abcdef8.cloudfront.net
以 DNS 僅限模式開始. 若後來想啟用 Cloudflare 的橘色代理,請使用全模式 (嚴格模式) 在 SSL/TLS 上。絕不使用靈活模式 (會產生重定向迴圈).
開啟瀏覽器,訪問 https://meusite.com,應該會載入倉儲的範例頁面.
如何適用於您的網站
現在來到重點部分:如何安裝 至您的 網站不是範例位置.
網站文件夾是 website_src/. 預設帶有一個最小化的 React + Vite. 結構:
website_src/
├── favicon.svg
├── index.html
├── src/
│ └── (componentes React)
├── tsconfig.json
└── vite.config.ts
你有兩個選擇:
選項 1: 將你的專案整個放在 website_src/
更簡單。刪除內容。website_src/ 需要將您的專案導出(Next.js、Astro、Vue、純HTML,任何東西都可以)。調整 build:site 在 package.json 上以運行您的框架的建置。目前是這樣的:
"build:site": "vite build --config website_src/vite.config.ts"
如果您使用Astro,就變成這樣:
"build:site": "cd website_src && npm install && npm run build"
重要的在於的建置最終檔案需要放在website_dist/,因為是這個資料夾會讓部署程式上傳到S3。請將您的框架的輸出設定為指向那裡:
// vite.config.ts
export default defineConfig({
build: {
outDir: '../website_dist',
},
});
選項2:作為單一倉庫使用
您將您的網站放在一個獨立的倉庫中,產生檔案,然後放上去website_dist/ 只做部署。如果前端團隊和基礎設施團隊是分開的,那這就很有用。
純 HTML?沒問題。
如果你的網站只是 HTML/CSS/JS 靜態內容,直接把所有東西都放到 website_dist/:
mkdir -p website_dist
cp -r meu-site-pronto/* website_dist/
然後禁用 SPA fallback(當沒有客戶端路由時,不需要 fallback 到 index.html):
ENABLE_SPA_FALLBACK=false
部署網站
設定並編譯後:
npm run build:site
BUCKET_NAME=$(aws cloudformation describe-stacks \
--stack-name aws-cdk-static-site-starter-static-site \
--region eu-west-1 \
--query "Stacks[0].Outputs[?OutputKey=='WebsiteBucketName'].OutputValue" \
--output text)
DISTRIBUTION_ID=$(aws cloudformation describe-stacks \
--stack-name aws-cdk-static-site-starter-static-site \
--region eu-west-1 \
--query "Stacks[0].Outputs[?OutputKey=='CloudFrontDistributionId'].OutputValue" \
--output text)
aws s3 sync website_dist/ "s3://${BUCKET_NAME}" --delete --cache-control "public,max-age=300"
aws cloudfront create-invalidation --distribution-id "$DISTRIBUTION_ID" --paths "/*"
這個create-invalidation是用來強制 CloudFront 查找新版本。沒有這個,它可能會提供過期的快取,持續數分鐘或數小時。
提示:可以將這些放在腳本
deploy-site.sh中一次性執行.
在 GitHub Actions 中自動化所有操作
手動操作有助於學習。在生產環境中,您希望將代碼推送至 main 分支並自動更新網站.
這個倉庫已經包含兩個工作流程
-
.github/workflows/ci.yml:在 PR 和 push 時運行,執行 build/test/synth,無需 AWS 凭據。 -
.github/workflows/deploy.yml: 在 main 中推動,透過 OIDC 自動認證,執行cdk deploy,同步並失效.
OIDC 是一個很棒的機制:你不需要將 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY 作為密鑰存放在 GitHub(這些會在日誌中洩露),GitHub Actions 會請求一個臨時的 AWS 凭據,這個憑據信任 GitHub 的 OIDC 提供者。沒有固定金鑰,無需手動輪換。
為了建立具有 OIDC 認證的 IAM 角色,請在 .env 中啟用:
CREATE_GITHUB_OIDC_ROLE=true
GITHUB_OWNER=seuuser
GITHUB_REPO=seu-repo
GITHUB_BRANCH=main
重新運行 npx cdk deploy,複製 output GithubActionsRoleArn,並將其添加為 GitHub 中的 Repository Variable:
AWS_ROLE_ARN=arn:aws:iam::123456789012:role/...github-actions-deploy
與其他變數一起(與.env的相同鍵):
AWS_ACCOUNT_ID=123456789012
AWS_REGION=eu-west-1
DOMAIN_NAME=meusite.com
WWW_DOMAIN_NAME=www.meusite.com
PROJECT_NAME=meu-site
CERTIFICATE_REGION=us-east-1
ENABLE_SPA_FALLBACK=true
CREATE_GITHUB_OIDC_ROLE=false
GITHUB_OWNER=seuuser
GITHUB_REPO=seu-repo
GITHUB_BRANCH=main
這樣就可以在Actions中推送至main,並在Actions的build、deploy、sync、invalidation上變得聰明。所有都是自動的.
這個遊戲要花多少錢?
對於一個小網站(每月幾千次點擊),成本是每個月幾分錢 或免費,取決於用量:
- ACM:對CloudFront的公證書是免費的。
- S3:收存储和請求費用。小網站僅需幾分錢。
- CloudFront: 免費方案每月非常慷慨(1 TB 傳輸量 + 10M 請求)。除此之外,需要付費。
- Cloudflare DNS: 免費方案解析。
可能增加成本的:
- CloudFront 高流量(超出免費方案範圍)。
- 頻繁且廣泛的失效(
/*直接,每天多次)。 - 啟用 WAF、日誌、Lambda@Edge、CloudFront Functions 而無需
因此該專案有意不啟用這些功能。如果您需要,後續再啟用,並清楚成本
安全,豈能忘記
設定已預設包含:
- S3帶有
BlockPublicAccess從未暴露過。 - CloudFront 存取 S3 透過 OAC (現代方式),非 OAI 遺留方式.
- HTTP 自動重定向至 HTTPS.
- 工作流程使用 OIDC,無長壽存取金鑰.
在生產環境中,將部署角色的 AdministratorAccess 替換為權限較低的策略。readme 文件說明了如何操作.
而關於 "刪除所有內容" 的部分?
想結束這個玩笑嗎?先清空你的bucket(Bucket)吧。autoDeleteObjects他false為了避免自定義資源,有意識地):
BUCKET_NAME=$(aws cloudformation describe-stacks \
--stack-name aws-cdk-static-site-starter-static-site \
--region eu-west-1 \
--query "Stacks[0].Outputs[?OutputKey=='WebsiteBucketName'].OutputValue" \
--output text)
aws s3 rm "s3://${BUCKET_NAME}" --recursive
npx cdk destroy --all
不要忘記在 Cloudflare 也刪除 CNAMEs。
Pra 關閉
總結一下發生了什麼:
- 你學習 (或複習) 了 AWS、IaC 和 CDK.
- 在 AWS 上部署了一個靜態網站,帶有 HTTPS、全球 CDN 和 Cloudflare 的 DNS.
- 透過 GitHub Actions 配置了自動部署,並使用 OIDC.
- 幾乎沒有花錢在這上面.
這個專案是開源的,放在 github.com/markgerald/aws-cdk-static-site-starter. 喜歡就給個星星。如果發現錯誤或有建議,請發送 PR 或開啟 issue.
有疑問嗎?在下方留言,我會回覆.
謝謝,說完啦!👋













