Next.js 배포 with S3+CloudFront+Github Actions

소해·2025년 2월 7일

next.js 배포

목록 보기
1/3
post-thumbnail

뒤늦게 알았는데 AWS에서 정적 사이트 배포에 권장하고 있는 것은 Amplify라고 한다. 만약 정적 사이트 배포 도구를 찾고 있다면, Vercel이나 Amplify를 먼저 써보는 게 좋을 것 같다.

사이드 프로젝트를 진행하는데, 정적인 페이지로 충분히 구성이 가능할 듯하여 next.js의 static export를 사용해 S3에 배포해보기로 하였다. 유튜브 영상 Deploy NextJS App to S3 and CloudFront using GitHub Actions을 참고하여, Github Actions를 통한 배포 자동화까지 함께 진행하였다.

  1. Next.js
  2. AWS : S3, CloudFront, IAM
  3. Github Actions

위의 순서대로 설정을 진행한다.

1. Next.js

Next.js의 staic export를 사용하면 빌드 실행 시 모든 페이지를 미리 렌더링하여, 각 페이지별 HTML 파일을 포함한 정적 파일들을 out 디렉토리에 생성한다. static export를 실행하기 위해서는 먼저 next.config에서 설정이 필요하다.

  1. output을 'export'로 설정해준다.

  2. images 설정을 한다. Image 컴포넌트의 최적화를 사용하려면 커스텀 로더를 설정해야 한다. 내 경우에는 따로 이미지 로더를 생성해놓지 않은 상태여서 unoptimized로 설정하였다. 참고: Image Optimization

  3. trailingSlashtrue로 설정한다. 이에 따라, 빌드 시 각 서브패스에 대하여 각각 디렉토리를 생성하고 그 안에 index.html 파일을 생성한다.

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: 'export',
  images: {
    unoptimized: true,
  },
  trailingSlash: true,
};

export default nextConfig;

위와 같이 설정 후 build를 실행하면 out 디렉토리가 생성되며, 각 페이지별 HTML 및 필요한 애셋들이 생성된 것을 확인할 수 있다.

이 파일들을 웹서버에 올리면 앱을 배포할 수 있다. 이를 위해 S3와 CloudFront를 사용해 보자.

2. AWS

AWS 설정 과정은 위에 링크 걸었던 동영상을 보면 더 편하다...

2-1. S3

1. Amazon S3 > Buckets > Create bucket

  • AWS Region 확인: 내 경우 ap-northeast-2
  • Bucket name 설정: ex) nextjs-s3-cloudfront
  • Object Ownership: ALS disabled
  • Block all public access 해제
  • 이후 다른 값들 기본값 그대로 설정(Bucket Versioning: disable, Default encryption: SSE-S3, bucket Key: enable)

2. Amazon S3 > Buckets

  • 버킷 목록에서 생성한 버킷을 확인 후, 버킷 정보 페이지를 확인
  • [Properties] 항목에서 맨 아래에 있는 Static website hosting을 Enable로 변경
    - Index document: index.html
    - Error document: 404.html
  • Static website hosting에서 Bucket website endpoint 확인
  • [Permissions] 항목에서 Bucket policy 설정
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::nextjs-s3-cloudfront/*"
        }
    ]
}
  • [Object] 항목에, out디렉토리 안에 있는 파일들을 모두 업로드. 드래그 앤 드랍 가능
  • 업로드 완료 후, Bucket website endpoint로 접속해 앱이 동작하는지 확인

2-2. CloudFront

1. CloudFront > Distributions > Create distribution

  • Origin domain: 2-1.에서 생성한 Bucket 선택
  • Viewer protocol policy: Redirect HTTP to HTTPs
  • Web Application Firewall: Do not(production 환경일 시 Enable 설정)
  • Default root object: index.html
  • 다른 값들은 기본값 그대로

    Origin domain 설정 시 website endpoint를 사용한다면, 사용자가 xxx.net/subpath로 접근 시 /subpath/로 redirect하며

2. CloudFront > Distributions

  • 생성된 distribution domain name 확인: 잘 접근되는지 확인해보자. 내 경우 적용되는 데 1분정도 걸렸던 것 같다.

2-3. IAM

1. IAM > Policies > Create policy
S3와 CloudFront에 접근할 수 있도록 하는 Policy를 먼저 정의한다.

  • JSON 선택하여, 아래와 같이 작성
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ListObjectsInBucket",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::nextjs-s3-cloudfront"
        },
        {
            "Sid": "AllObjectActions",
            "Effect": "Allow",
            "Action": "s3:*Object",
            "Resource": "arn:aws:s3:::nextjs-s3-cloudfront/*"
        },
        {
            "Sid": "InvalidateCF",
            "Effect": "Allow",
            "Action": "cloudfront:CreateInvalidation",
            "Resource": "*"
        }
    ]
}
  • policy name 지정 ex)s3-web-access-policy

2. IAM > Roles > Create Role

  • [Step1] Select trusted entity
    • Trusted entity type: Web identity
    • Identity provider: github OIDC provider
    • Audience: sts.amazonaws.com
    • GitHub organization: 자동화 적용할 프로젝트 repository가 속한 oganization
    • GitHub repository: 자동화 적용할 프로젝트의 repository
  • [Step2] Add permissions
    - 이전에 생성한 policy(s3-web-access-policy) 선택
  • [Step3] Name, review, and create
    - Role name 설정 ex) github-to-aws-oidc

위 작업을 통해 GitHub Actions 워크플로우에 S3와 CloudFront에 접근할 수 있는 권한을 부여하였다.
남은 일은 GitHub Actions가 어떤 작업을 수행할지 정의하는 것이다.

3. Github Actions

코드베이스 루트디렉토리에 .github/workflows 디렉토리를 생성하여 yaml 파일을 작성한다. main 브랜치에 push됐을 때 실행할 것이며, 실행할 작업들은 jobssteps 항목에서 단계별로 정의한다.

#.github/workflows/build-and-deploy.yaml
---
name: Build and Deploy NextJS App to S3 and CloudFront
on:
  push:
    branches: [main]
permissions:
  id-token: write
  contents: read
jobs:
  build-and-deploy:
    name: Build and Deploy
    runs-on: ubuntu-latest
    env: # steps에서 사용할 환경변수 정의
      NEXTJS_DIST: out
      AWS_REGION: ap-northeast-2
      S3_BUCKET: nextjs-s3-cloudfront # 2-1에서 생성한 bucket 이름
      CLOUDFRONT_DISTRIBUTION_ID: E20B08AK8JO7FN # 2-2에서 생성한 distribution ID

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS credentials from AWS account
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: arn:aws:iam::220218901823:role/github-to-aws-oidc
          aws-region: ${{ env.AWS_REGION }}

      - name: Install Dependencies
        run: |
          node --version
          yarn install --frozen-lockfile

      - name: Build Static Website
        run: yarn build

      - name: Sync files to S3 bucket
        run: |
          aws s3 sync --delete ${{ env.NEXTJS_DIST }} s3://${{ env.S3_BUCKET }}

      - name: Invalidate CloudFront cache
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ env.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

이제 main 브랜치에 commit이 push될 때마다 정의된 작업들을 수행하며 배포를 진행한다. 배포 과정은 레파지토리의 [Actions]에서 확인할 수 있다.

profile
Frontend Engineer

0개의 댓글