Back to blog
Aug 17, 2025
5 min read

Astro 블로그 Vercel → AWS 이전기 (GoDaddy 도메인 사용)

Vercel에서 AWS S3 + CloudFront로 블로그를 이전한 과정과 경험담. GoDaddy 도메인을 Route53으로 이전하지 않고 CloudFront에 연결하는 방법, GitHub Actions 자동 배포 설정, 그리고 SPA 라우팅 문제 해결까지

Astro 블로그 Vercel → AWS 이전기 (GoDaddy 도메인 사용)

개요

  • 개인 도메인: angela-blog.com (GoDaddy에서 구매)
  • 이전 스택: Vercel + Astro
  • 현재 스택: AWS S3 + CloudFront + ACM + GoDaddy DNS + GitHub Actions
  • 이유: 비용 절감 & AWS 학습 겸용

1. 왜 이전했나?

  • Vercel 무료 플랜도 충분했지만, AWS로 옮겨 직접 인프라를 다뤄보고 싶었다
  • 정적 사이트(Astro)는 S3 + CloudFront 조합이 최적
  • 이미 GoDaddy에서 구매한 도메인이 있어서 Route53으로 이전하지 않고 그대로 연결하고 싶었다

2. 아키텍처 개요

  • S3 (서울, ap-northeast-2): 정적 파일 저장
  • CloudFront (글로벌 CDN): HTTPS 배포
  • ACM (버지니아 북부, us-east-1): SSL 인증서
  • GoDaddy DNS: 도메인 관리 (Route53 안 씀)
  • GitHub Actions: main push → 자동 빌드/배포

3. 세부 과정

(1) S3 버킷 생성 & 수동 업로드

yarn build   # Astro -> dist/ 생성
aws s3 sync ./dist s3://angela-blog --delete

(2) ACM 인증서 발급

  • 리전: us-east-1
  • 도메인: angela-blog.com, www.angela-blog.com
  • 검증: GoDaddy DNS에 CNAME 추가
  • 주의: GoDaddy는 Name 칸에 도메인을 자동으로 붙여줌 → 중복 입력하지 말 것
  • 상태: Issued

(3) CloudFront 배포 생성

  • Origin: angela-blog.s3.ap-northeast-2.amazonaws.com
  • Viewer protocol: Redirect HTTP → HTTPS
  • CNAMEs: angela-blog.com, www.angela-blog.com
  • SSL: ACM 인증서 선택

(4) GoDaddy DNS 설정

Route53 대신 GoDaddy DNS를 그대로 사용

  • www → CNAME → CloudFront 도메인 (예: dxxxx.cloudfront.net)
  • 루트 도메인 (angela-blog.com) → GoDaddy Forwarding으로 https://www.angela-blog.com 301 리다이렉트

GoDaddy에서 Forwarding 기능 제공
비용 아끼려면 이 방식 추천 (Route53 쓰면 DNS 이전 비용 발생)

(5) GitHub Actions 자동 배포

IAM 사용자 생성 → S3 + CloudFront 최소 권한 정책 부여

Access key 발급 후 GitHub Secrets 등록:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_REGION = ap-northeast-2
  • CF_DIST_ID = CloudFront 배포 ID

.github/workflows/deploy.yml 예시:

name: Deploy to S3 & Invalidate CF

on:
  push:
    branches: ["main"]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: |
          echo "YARN_IGNORE_PATH=1" >> $GITHUB_ENV
          corepack enable
          corepack prepare yarn@4.6.0 --activate
          corepack yarn install --immutable
          corepack yarn build
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}
      - run: aws s3 sync ./dist s3://angela-blog --delete
      - run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CF_DIST_ID }} --paths "/*"

4. 트러블슈팅

  • 인증서 Pending → GoDaddy DNS에 CNAME 오타 / 중복
  • ERR_CERT_COMMON_NAME_INVALID → CloudFront CNAMEs에 www 누락
  • 배포 후 변경 안 보임 → CloudFront Invalidation 실행

5. 경로(Path) 접근 시 AccessDenied 문제 해결

AWS S3 + CloudFront 조합으로 정적 사이트를 배포하면, /work 같은 폴더형 경로로 접속할 때 문제가 생깁니다.

브라우저는 …/work → S3에서 객체 work를 찾으려 하는데, 실제로는 work/index.html만 있어서 AccessDenied XML이 떨어집니다.

해결 방법 1) CloudFront Function으로 index.html 리라이트 (권장)

확장자가 없는 요청은 자동으로 …/index.html을 붙여주도록 설정합니다.

CloudFront → Functions → Create function → 아래 코드 추가:

function handler(event) {
  var req = event.request;
  var uri = req.uri;

  // 이미 파일(확장자 있는 경우)은 그대로
  if (uri.includes(".")) return req;

  // 루트 경로 → /index.html
  if (uri === "" || uri === "/") {
    req.uri = "/index.html";
    return req;
  }

  // 슬래시로 끝나면 index.html 붙이기
  if (uri.endsWith("/")) {
    req.uri = uri + "index.html";
    return req;
  }

  // 그 외 → /index.html 붙이기
  req.uri = uri + "/index.html";
  return req;
}

Publish 후,

CloudFront 배포 → Behaviors → Edit → Function associations → Viewer request에 연결

→ 이후 /work, /about, /posts/slug 모두 …/index.html로 매핑되어 정상 동작합니다.

Astro를 쓰는 경우 astro.config.mjs에서 trailingSlash: 'always'를 지정하면 빌드 산출물이 /path/ 형태가 되고, CloudFront Function과 조합하면 거의 완벽하게 정적 라우팅을 지원합니다.

해결 방법 2) SPA 폴백 (선택)

만약 프로젝트가 싱글 페이지 앱(SPA)라면, **존재하지 않는 경로도 전부 /index.html**로 리다이렉트하도록 CloudFront Error Pages를 설정할 수도 있습니다.

403 / 404 → Response code 200, Response page: /index.html

하지만 Astro 블로그처럼 정적 페이지가 많은 경우, Function 방식이 더 안정적이고 권장됩니다.

6. 마무리

  • Vercel도 편리하지만, AWS로 옮기니 구조가 보이고 직접 제어 가능
  • GoDaddy 도메인을 Route53으로 옮기지 않고도 CloudFront 배포 성공
  • ACM 인증서는 자동 갱신이라 관리 부담 없음
  • GitHub Actions 덕분에 main 푸시 → 자동 배포 완료

경로 라우팅 문제 해결

Astro 같은 정적 사이트는 모든 경로에 index.html이 존재하지만, S3+CloudFront는 기본적으로 index.html을 찾아주지 않습니다. 따라서 CloudFront Function으로 리라이트를 추가하는 게 사실상 필수입니다.

👉 이 작업을 해주고 나니 /work처럼 path만 입력해도 정상적으로 블로그가 열리게 되었고, Vercel에서처럼 편하게 라우팅을 쓸 수 있었습니다.