Azure Static Web Apps — 가이드 사이트 배포
docs-site/ 의 Docusaurus 빌드 결과물을 Azure Static Web Apps (ASWA) Free
티어에 배포합니다. 트레이딩 봇 인프라(VM + ACR)와는 별도의 리소스 그룹으로
운영해 비용·권한·라이프사이클을 분리합니다.
목표 토폴로지
┌──────────────────────────┐ ┌──────────────────────────┐
│ GitHub: genonai/quant-ai │ │ Azure: koreacentral │
│ │ │ │
│ docs-site/** ──push──▶ │ │ ┌──────────────────────┐ │
│ │ deploy │ │ Static Web App │ │
│ Actions: │ token │ │ (quantai-docs) │ │
│ docs-deploy.yml ────────┼────────▶│ │ Free tier │ │
│ │ │ │ defaultHostname: │ │
│ │ │ │ *.azurestaticapps.net│ │
│ │ │ └──────────────────────┘ │
└──────────────────────────┘ └──────────────────────────┘
│
▼
┌──────────────────┐
│ Azure Front Door │
│ (글로벌 CDN, 자동) │
└──────────────────┘
| 항목 | 값 |
|---|---|
| 리소스 그룹 | quantai-docs-rg |
| 리전 (control plane) | koreacentral (CDN은 글로벌) |
| 리소스 이름 | quantai-docs |
| SKU | Free (월 $0, 100GB egress, 0.5GB storage) |
| 태그 | Owner=ttagu99, Department=quant-ai, CostCenter=docs, Environment=production |
GenOS 정책상 모든 Azure 리소스는 Owner, Department, CostCenter,
Environment 4개 태그를 필수로 갖습니다. Bicep 템플릿(
infra/azure/static_web_app.bicep)과 배포 스크립트(
scripts/docs/deploy_static_web_app.sh)는 모두 이 정책을 자동 적용합니다.
직접 Portal에서 만들 경우 누락하면 정책 위반으로 거부됩니다.
1. 사전 요구 사항
- Azure CLI (
az login완료, Static Web Apps 쿼터 보유 구독) - GitHub CLI (
gh auth login,genonai/quant-airepo의reposcope) - Bicep CLI (최신
az에 번들). 검증은az bicep build로 가능 - 로컬에서 docs 빌드가 한 번 성공:
cd docs-site && npm ci && npm run build
2. 첫 배포 (수동, 1회)
배포 스크립트 한 줄로 ① 리소스 그룹 생성 → ② Bicep 적용 → ③ 배포 토큰 추출 → ④ GitHub repo secret 등록까지 끝납니다.
chmod +x scripts/docs/deploy_static_web_app.sh
./scripts/docs/deploy_static_web_app.sh
스크립트 실행 후 출력에 다음이 보입니다.
✅ Done.
Default hostname : https://quantai-docs.azurestaticapps.net
GitHub secret : AZURE_STATIC_WEB_APPS_API_TOKEN (set on genonai/quant-ai)
수동으로 단계를 쪼개고 싶다면 다음 시퀀스와 동치입니다.
# (a) 리소스 그룹
az group create \
--name quantai-docs-rg \
--location koreacentral \
--tags Owner=ttagu99 Department=quant-ai CostCenter=docs Environment=production
# (b) Bicep 적용
az deployment group create \
--resource-group quantai-docs-rg \
--template-file infra/azure/static_web_app.bicep \
--parameters name=quantai-docs sku=Free
# (c) 배포 토큰
TOKEN=$(az staticwebapp secrets list \
--name quantai-docs \
--resource-group quantai-docs-rg \
--query properties.apiKey -o tsv)
# (d) GitHub secret 등록
printf '%s' "$TOKEN" | gh secret set AZURE_STATIC_WEB_APPS_API_TOKEN \
--repo genonai/quant-ai --body -
unset TOKEN
- 토큰은 절대 커밋 금지.
.env, 노트, 채팅 등 어디에도 저장하지 마세요. - 누출 의심 시
az staticwebapp secrets reset --name quantai-docs --resource-group quantai-docs-rg로 즉시 재발급 후 GitHub secret을 갱신합니다. - 워크플로의
secrets.AZURE_STATIC_WEB_APPS_API_TOKEN외에 다른 곳에서 참조하지 않습니다.
3. URL 확인 및 docusaurus.config 동기화
배포가 끝나면 기본 호스트네임이 https://<app-name>.azurestaticapps.net
형태로 발급됩니다. docs-site/docusaurus.config.ts의 url 필드를
실제 값으로 갱신하세요(혹은 배포 시 DOCS_SITE_URL 환경변수로 주입).
url: process.env.DOCS_SITE_URL ?? 'https://quantai-docs.azurestaticapps.net',
이 값이 사이트맵·canonical·OG 메타데이터에 모두 반영됩니다.
4. 자동 배포 (GitHub Actions)
.github/workflows/docs-deploy.yml 가 다음을 처리합니다.
- push to main +
docs-site/**변경 → 프로덕션 배포 (production environment의 manual approval rule이 있으면 게이트 적용) - pull_request +
docs-site/**변경 → PR preview URL 생성 (PR 댓글로 자동 게시). PR close/merge 시 자동 정리 - workflow_dispatch → 수동 재배포 (토큰 회전 후 재시도 등)
빌드 단계는 다음 순서로 동작합니다.
- Node 22 setup +
npm ci(cache key는docs-site/package-lock.json) npm run build— Docusaurus 빌드 (onBrokenLinks=warn기본)staticwebapp.config.json을build/로 복사Azure/static-web-apps-deploy@v1호출 (skip_app_build=true)- 배포 결과를 GitHub step summary에 기록
Repo Settings → Environments → production 에서 "Required reviewers"를
설정하면 main에 머지된 docs-site 변경이 즉시 배포되지 않고 승인을 거칩니다.
첫 배포가 안정화될 때까지 권장합니다.
5. 라우팅·헤더·캐시 (staticwebapp.config.json)
docs-site/staticwebapp.config.json에서 다음을 관리합니다.
| 항목 | 값 |
|---|---|
/assets/* 캐시 | public, max-age=31536000, immutable (Docusaurus 해시 자산) |
/img/* 캐시 | public, max-age=86400 |
| 검색 인덱스 | public, max-age=300, must-revalidate |
navigationFallback | /404.html rewrite (Docusaurus 404 페이지 활용) |
| 보안 헤더 | HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy, CSP |
| MIME types | .webmanifest, .woff2, .md, .mdx |
CSP는 정적 사이트 기본값('self' + inline)으로 설정되어 있어 외부 위젯
(예: 구글 애널리틱스)을 추가하면 그에 맞춰 script-src / connect-src 를
확장해야 합니다.
6. 커스텀 도메인 (옵션)
기본 *.azurestaticapps.net 외에 사용자 도메인을 붙이려면 다음 순서를
따릅니다.
# (1) DNS 측 — CNAME 레코드
# docs.quant-ai.example.com CNAME quantai-docs.azurestaticapps.net
# (2) Azure 측 — 도메인 등록 + 검증
az staticwebapp hostname set \
--name quantai-docs \
--resource-group quantai-docs-rg \
--hostname docs.quant-ai.example.com
apex 도메인(quant-ai.example.com)을 쓰려면 CNAME 대신 TXT 검증으로
--validation-method dns-txt-token을 지정합니다. Bicep 템플릿에는 옵션
파라미터 customDomain이 준비되어 있어 IaC로도 등록 가능합니다.
7. 모니터링 (옵션)
기본 ASWA Free 티어는 Application Insights 통합을 지원하지 않습니다(Standard 이상에서 가능). 대안으로:
- Azure Portal → Static Web Apps → Metrics: 요청 수, 에러율, 대역폭
- Azure Monitor: 리소스 진단 설정에서 활동 로그를 Log Analytics로 전송
- GitHub Actions step summary: 배포 성공/실패 즉시 확인
- Cloudflare 등 외부 RUM: 이 프로젝트 범위에선 미사용
추후 트래픽이 증가하면 Standard로 업그레이드해 Application Insights 연결을 검토합니다(월 ~$9/app, 분당 ~100만 요청 무료 한도).
8. 트러블슈팅
| 증상 | 점검 |
|---|---|
| 배포 워크플로 401 / 403 | 토큰 만료 또는 회전 미반영. scripts/docs/deploy_static_web_app.sh 재실행 → secret 갱신 |
| PR preview URL이 PR 댓글에 안 뜸 | permissions: pull-requests: write 누락 또는 fork PR (Azure SWA는 fork PR에 제한 적용) |
| 정적 자산 404 | output_location 지정 오류. 워크플로에서 app_location: docs-site/build, skip_app_build: true 가 맞는지 확인 |
| 한국에서 첫 응답 지연 | ASWA는 글로벌 CDN을 자동 활용. 첫 cold cache miss는 정상이며 이후 지연 감소 확인 |
az bicep build 경고 | az upgrade && az bicep upgrade로 최신 컴파일러 |
관련 페이지
- Azure VM 배포 (운영 봇)
- Docker Compose 설치
- 환경변수 카탈로그
- 코드 위치
infra/azure/static_web_app.bicep.github/workflows/docs-deploy.ymldocs-site/staticwebapp.config.jsonscripts/docs/deploy_static_web_app.sh