React

Next.js 프로젝트를 Vercel로 배포 자동화 + Route 53으로 도메인 변경

solfa 2025. 3. 8. 16:18

1. Vercel 배포를 선택한 이유

동아리 내에서 팀 organization을 사용하고 있다. 원래는 AWS S3 버킷을 생성하고 배포하는 방식으로 진행하려 했다. 하지만 이번 프로젝트는 Next.js를 사용하고 있으며, 특히 API Route 기능을 활용하고 있다. 이러한 특성상 단순한 정적 빌드가 어렵다고 판단했다.

Next.js의 SSR(Server Side Rendering) 및 API Route를 포함한 프로젝트는 기본적으로 서버 환경이 필요하다. AWS에서 이를 운영하려면 Lambda나 EC2 같은 추가적인 설정이 필요하지만, 이는 유지보수 비용과 복잡도를 증가시킨다. 하는 방법이 없진 않지만!! 빠른 배포가 우선이었기에 빠르고 간편한 Vercel 배포를 선택했다.

 

Vercel은 Next.js의 공식 배포 플랫폼으로, Next.js의 모든 기능을 손쉽게 지원한다. 추가적인 설정 없이도 SSR과 API Route를 지원하고, 배포 속도가 빠르며 무료 플랜에서도 기본적인 기능을 사용할 수 있다.

 

이러한 이유로 팀 레포에서 직접 배포하는 대신, 내 개인 레포로 포크한 후 Vercel에서 배포하는 방식으로 진행했다.

 

왜냐면... 팀 레포에서 버셀 배포는 비용이 들기 때문... 근데 이렇게 개인 레포로 포크해서 하는게 합법적인 불법 (?) 인 것 같다

ㅎ...

 

2. 배포 자동화를 위한 GitHub Actions 설정

GitHub Actions를 이용한 레포 동기화 및 배포 자동화

개인 레포에서 배포를 진행하다 보니, 팀 레포와의 코드 동기화가 필요했다. 이를 위해 GitHub Actions를 활용하여 팀 레포(main 브랜치)에 변경 사항이 생기면 자동으로 내 개인 레포에 반영되도록 설정했다.

 

이를 위해 .github/workflows/deploy.yml 파일을 추가했다.

이 워크플로우는 하나의 GitHub 저장소에서 다른 저장소로 코드를 자동으로 동기화하고 배포하는 자동화 과정이다.

deploy.yml 코드 설명

name: Auto-Sync and Deploy to Personal Repo
on:
  push:
    branches: ['main']

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false
      - name: Create and copy files
        run: |
          mkdir -p output
          cp -R ./* ./.[^.]* output/ 2>/dev/null || :
          rm -rf output/output
      - name: Pushes to another repository
        uses: cpina/github-action-push-to-another-repository@main
        env:
          API_TOKEN_GITHUB: ${{ secrets.AUTO_ACTIONS }}
        with:
          source-directory: 'output'
          destination-github-username: ssolfa
          destination-repository-name: ppusyung-tarot
          user-email: ${{ secrets.EMAIL }}
          user-name: ssolfa
          commit-message: ${{ github.event.commits[0].message }}
          target-branch: main

주요 내용

  1. push 이벤트 감지
    main 브랜치에 push가 발생하면 이 workflow가 실행된다.
  2. 코드 체크아웃
    actions/checkout@v4을 사용하여 팀 레포의 최신 코드를 가져온다.
  3. 파일 복사 및 준비
    mkdir -p output을 통해 output 디렉토리를 생성하고, 프로젝트 파일을 복사한다.
  4. 개인 레포로 코드 푸시
    cpina/github-action-push-to-another-repository@main 액션을 사용하여, 내 개인 레포(ppusyung-tarot)로 코드를 푸시한다.

 

미래의 나같은 사람들을 위해... 진짜 자세히 설명을 해보겠다

트리거 조건

on:
  push:
    branches: ['main']
  • 이 워크플로우는 'main' 브랜치에 코드가 푸시될 때마다 자동으로 실행된다.
  • 즉, 메인 브랜치에 변경사항이 생길 때마다 동기화 작업이 시작된다는 뜻!

작업 구성

jobs:
  build:
    runs-on: ubuntu-latest
  • 'build'라는 하나의 작업을 정의하며, 최신 Ubuntu 환경에서 실행된다.

단계별 실행 과정

1. 코드 체크아웃

- name: Checkout code
  uses: actions/checkout@v4
  with:
    fetch-depth: 0
    persist-credentials: false
  • actions/checkout@v4: GitHub의 공식 체크아웃 액션을 사용하여 현재 저장소의 코드를 워크플로우 환경으로 가져온다.
  • fetch-depth: 0: 전체 커밋 기록을 가져온다. 완전한 저장소 복사본을 위해 필요하다. depth를 자유롭게 1로 할 수도 있다!
    • fetch-depth: 1로 설정하면 최신 커밋만 가져오게 된다. 전체 Git 이력 대신 가장 최근 커밋만 체크아웃된다! 어차피 처음에 개인 레포로 포크 해올 때 전에 파일들은 전부 가져온 거나 다름이 없고! 현재 워크플로우에서는 단순히 파일을 복사하여 다른 저장소로 푸시하는 것이 목적이므로, fetch-depth: 1로 설정해도 기능적으로는 문제가 없다. 오히려 이게 더 효율적일수도?! 
  • persist-credentials: false: GitHub 기본 인증 정보를 유지하지 않는다. 이는 나중에 다른 인증 정보로 다른 저장소에 푸시하기 위함이다. 
    • 우리는 지금 두 개의 다른 저장소를 다루고 있다. 따라서 두 개의 다른 인증 정보가 필요하다. 기본 인증 대신 ${{ secrets.AUTO_ACTIONS }} 토큰을 사용하기 때문에 이걸 false로 설정해준다. true로 해도 되는지는... 안해봐서 모르겠다
  1.  

2. 파일 복사 및 준비

- name: Create and copy files
  run: |
    mkdir -p output
    cp -R ./* ./.[^.]* output/ 2>/dev/null || :
    rm -rf output/output

 

 

output 디렉토리를 만들고 모든 파일을 여기로 복사해서 이 output 디렉토리의 내용을 ssolfa/ppusyung-tarot 저장소로 푸시할거다.

  • mkdir -p output: 'output'이라는 디렉토리를 생성한다.
  • cp -R ./* ./.[^.]* output/ 2>/dev/null || ::
    • 현재 디렉토리의 모든 파일과 숨김 파일(.로 시작하는 파일)을 output 디렉토리로 복사한다.
    • 2>/dev/null || :: 오류 메시지를 무시하고, 명령이 실패해도 워크플로우가 계속 진행되도록 한다.
  • rm -rf output/output: 중첩된 output 디렉토리를 제거하여 무한 복사를 방지한다.

복사 과정이 필요한 이유

  1. 기술적 필요성: cpina/github-action-push-to-another-repository 액션은 특정 디렉토리 내용만 다른 저장소로 푸시하도록 설계되었다. 따라서 푸시할 내용을 별도 디렉토리에 준비해야 한다.
  2. 선택적 파일 제외 가능: 복사 단계에서 특정 파일이나 디렉토리를 제외할 수 있습니다. 현재 스크립트는 단순히 모든 것을 복사하지만, 필요하다면 여기서 .git 폴더나 특정 설정 파일을 제외할 수 있다. -> 귀찮아서 안했지만 ㅠ

3. 다른 저장소로 푸시

- name: Pushes to another repository
  uses: cpina/github-action-push-to-another-repository@main
  env:
    API_TOKEN_GITHUB: ${{ secrets.AUTO_ACTIONS }}
  with:
    source-directory: 'output'
    destination-github-username: ssolfa
    destination-repository-name: ppusyung-tarot
    user-email: ${{ secrets.EMAIL }}
    user-name: ssolfa
    commit-message: ${{ github.event.commits[0].message }}
    target-branch: main
  • cpina/github-action-push-to-another-repository@main: 다른 저장소로 코드를 푸시하기 위한 커뮤니티 액션을 사용한다.
  • 환경 변수:
    • API_TOKEN_GITHUB: ${{ secrets.AUTO_ACTIONS }}: 대상 저장소에 접근하는 데 필요한 GitHub 액세스 토큰을 설정
  • 설정 매개변수:
    • source-directory: 'output': 이전 단계에서 준비한 (복사한) 디렉토리!
    • destination-github-username: ssolfa: 대상 저장소의 소유자 -> 포크한 사람의 깃허브 닉네임
    • destination-repository-name: ppusyung-tarot: 동기화할 대상 저장소의 이름 -> 포크한 레포 이름
    • user-email & user-name: 커밋을 생성할 사용자의 정보 -> email도 명시해도 되는데 ㅜㅜ 이것만 개인정보라 가렸음 위에서 닉네임, 레포 이름 전부 시크릿 처리 해도 됨!
    • commit-message: ${{ github.event.commits[0].message }}: 원본 커밋 메시지를 그대로 사용한다.
    • target-branch: main: 대상 저장소의 어떤 브랜치에 푸시할지 지정

=> 따라서 이 워크플로우가 팀 레포의 'main' 브랜치에서 변경이 일어날 때마다 모든 파일을 'ssolfa/ppusyung-tarot' 저장소의 'main' 브랜치로 자동으로 복사해준다

GitHub Actions Secrets 설정하기

위의 workflow에서 secrets.AUTO_ACTIONS와 secrets.EMAIL을 사용하고 있다. 이를 설정하는 방법은 다음과 같다.

  1. GitHub에서 개인 레포의 Settings → Secrets and variables → Actions로 이동한다.
  2. New repository secret 버튼을 클릭하여 아래의 값을 추가한다.
    • AUTO_ACTIONS: GitHub Personal Access Token (PAT)
    • EMAIL: 커밋할 때 사용할 이메일 주소
  3. AUTO_ACTIONS 발급 방법
    • GitHub Settings → Developer settings → Personal access tokens에서 Fine-grained tokens를 생성한다.
    • repo 권한을 부여하여 team repo에서 개인 repo로 코드 푸시가 가능하도록 설정한다.
    • 생성된 토큰을 secrets.AUTO_ACTIONS에 등록한다.

이제 팀 레포에서 main 브랜치에 변경이 발생하면 자동으로 내 개인 레포에도 반영되며, 개인 레포에서 Vercel로 배포가 진행된다.

 

 

⬇️ 코드 전문 확인하기

 

https://github.com/yourssu/ppusyung-tarot/commit/74be5a7503993b3e9faeaeb1908d06a833ffe561

 

feat: 배포 자동화 yml 작성 · yourssu/ppusyung-tarot@74be5a7

ssolfa committed Feb 26, 2025

github.com

 


3. Route 53을 통한 도메인 연결

배포까지 했으면 도메인 연결이 필요하다. 기본적으로 Vercel이 제공하는 `project-name.vercel.app` 도메인 대신 우리 동아리 도메인을 사용해 볼 예정이다. 짜치는 도메인을 예쁘게 만들어보쟈

Vercel에서 도메인 추가하기

 

배포된 프로젝트의 Vercel 대시보드로 이동한다.

 

프로젝트 설정(Settings)에서 Domains 탭을 클릭한다.

 

 

"Add" 버튼을 클릭하고 원하는 서브도메인을 `[원하는이름].yourssu.com` 형태로 입력한다.

 

   - 예: `tarot.yourssu.com` 또는 `ppusyung.yourssu.com`

 

 

도메인을 추가하면 "Invalid Configuration" 메시지가 표시된다. 다행히~ 정상이다! DNS 레코드가 아직 설정되지 않았기 때문이다.

Vercel이 제공하는 CNAME 값(일반적으로 `cname.vercel-dns.com.` 형식)을 사용해서 밑에서 도메인을 연결할 거다.

 

Route 53에서 CNAME 레코드 추가하기

보통은 A 레코드와 CNAME 레코드를 함께 추가해야 하지만, yourssu.com 도메인은 이미 존재하므로 A 레코드는 설정하지 않고 CNAME만 추가한다.

 

도메인 설정의 기본 개념
일반적인 도메인 설정에서는 두 가지 DNS 레코드가 필요하다.

  • A 레코드: 특정 IP 주소에 도메인을 매핑하는 역할 - 도메인(example.com)을 서버의 IP 주소에 직접 연결
  • CNAME 레코드: 기존 도메인을 다른 도메인으로 연결하는 역할 - 서브도메인(project.example.com)을 다른 도메인으로 연결

동아리에서는 이미 yourssu.com 도메인의 A 레코드가 설정되어 있다! 따라서 우리는 CNAME 레코드만 추가하면 된다.

a 레코드 추가하는 방법은 이 걸 참고하면 될 것 같다.

 

https://velog.io/@jangsebari/AWS-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%A0%95%EC%A0%81-%EC%9B%B9-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%97%B0%EA%B2%B0

 

AWS 를 이용한 정적 웹 사이트 도메인 연결

들어가며 개발자로 지내는 동안 aws 를 사용하여 프로젝트를 빌드해서 배포하고 서버와 함께 운영해 본 경험이 있었다. 우여곡절 끝에 어쩌다보니 실행이 됐다며 기뻐했던 기억이 나는데... 좋아

velog.io

 

 

Route 53에서 레코드 생성하기

 

AWS 콘솔에 접속하여 Route 53 서비스로 이동한다.

이미 도메인을 등록해둔 상태, dns 관리를 클릭해서 호스팅 영역으로 들어간다.

 

 

기존 호스팅 영역(yourssu.com)을 선택한다.

 

 

"레코드 생성" 버튼을 클릭한다.

 

레코드 이름은 버셀에서 설정한 원하는 서브도메인 (예: tarot)

레코드 유형은 CNAME 레코드

값은 버셀에서 준 value -> cname.vercel.-dns.com. (마지막 점 까지 입력)
TTL은 기본 300으로 설정

단순 라우팅(Simple Routing) 선택  

 

이렇게 입력한 도메인과 Vercel에서 제공하는 도메인을 연결한다!

 

 

레코드를 생성하면 Vercel에서 설정한 도메인으로 정상적으로 접근 가능하다.

버셀 프로젝트 도메인에 들어가보면 Vercel의 도메인 상태가 "Invalid"에서 "Valid"로 변경되는 것도 볼 수 있다.

 

이제 원하는 서브 도메인으로 Vercel에 배포한 프로젝트에 접속할 수 있다!

728x90