Skip to content

[feat] EC2 프론트엔드 자동 배포 워크플로우 추가#37

Merged
mgYang53 merged 3 commits intomainfrom
feat/deploy
Jan 31, 2026
Merged

[feat] EC2 프론트엔드 자동 배포 워크플로우 추가#37
mgYang53 merged 3 commits intomainfrom
feat/deploy

Conversation

@dkqpeo
Copy link
Contributor

@dkqpeo dkqpeo commented Jan 30, 2026

Summary

  • GitHub Actions를 활용한 프론트엔드 CD 파이프라인 구성
  • main, dev 브랜치에 PR이 merge될 때 자동으로 EC2에 정적 파일 배포
  • pnpm + Node 20 환경에서 빌드 후 SCP로 EC2 전송

작업 내용

  • .github/workflows/deploy.yml 추가
  • pull_request closed + merged 조건으로 merge 시에만 배포 실행
  • pnpm/action-setup@v4를 사용한 안정적인 pnpm 설치
  • 의존성 캐싱(cache: 'pnpm')으로 빌드 속도 최적화
  • 환경변수(VITE_API_URL, VITE_APP_URL)를 GitHub Secrets에서 주입
  • appleboy/scp-action으로 빌드 결과물 EC2 전송
  • 원자적 배포(디렉터리 rename 스왑)로 다운타임 및 부분 배포 방지

배포 흐름

  1. main 또는 dev 브랜치에 PR merge
  2. pnpm 설치 → Node 20 설정 → 의존성 설치 → pnpm build
  3. dist/*를 EC2 /tmp/fe-deploy로 SCP 전송
  4. /tmp/fe-deploy 권한 설정 → 기존 디렉터리를 dokdok-old로 이동 → 신규 디렉터리를 dokdok으로 원자적 스왑 → 이전 버전 삭제

사전 설정 필요 (GitHub Secrets)

Secret 설명
EC2_HOST EC2 퍼블릭 IP
EC2_USER SSH 접속 유저명
EC2_SSH_KEY EC2 SSH 프라이빗 키
VITE_API_URL 백엔드 API 주소
VITE_APP_URL 프론트엔드 도메인

Test plan

  • GitHub Secrets 설정 완료 확인
  • dev 브랜치에 PR merge 후 Actions 워크플로우 정상 실행 확인
  • EC2 /var/www/dokdok/에 빌드 파일 배포 확인
  • 배포 중 다운타임 없이 원자적 스왑 정상 동작 확인
  • https://dokdok.site 접속 시 프론트엔드 정상 렌더링 확인

Summary by CodeRabbit

  • Chores
    • 주요 브랜치(main, dev)에 대한 자동 배포 워크플로가 추가되었습니다. PR 병합 시 애플리케이션을 빌드하고 원격 서버에 배포하도록 구성되어 있습니다.
    • 빌드 및 배포 과정에서 필요한 환경 변수와 인증 정보는 시크릿을 통해 안전하게 사용됩니다.

✏️ Tip: You can customize this high-level summary in your review settings.

EC2에 프론트엔드 정적 파일을 자동 배포하는 GitHub Actions 워크플로우를 추가합니다.
main, dev 브랜치 push 시 pnpm 빌드 후 SCP로 EC2에 배포합니다.
@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

워크스루

PR이 main 또는 dev 브랜치로 머지(닫힌 PR에서 merged)될 때 트리거되는 새 GitHub Actions 워크플로우(.github/workflows/deploy.yml)가 추가되었습니다. 워크플로우는 pnpm/Node.js 설치 및 캐시 복구, 의존성 설치(frozen lockfile), 환경변수로 빌드, dist/*를 EC2로 SCP 전송 후 SSH로 원격에서 웹 루트 교체·소유권·권한 설정·정리(백업 포함)를 수행하며 SSH 접속 정보는 GitHub Secrets를 사용합니다.

변경 사항

Cohort / File(s) Summary
GitHub Actions 배포 워크플로우
​.github/workflows/deploy.yml
PR이 main/dev로 병합될 때 실행되는 배포 파이프라인 추가. pnpm(v10.28.0) 및 Node.js(v20) 설정, pnpm 캐시 복구, pnpm install --frozen-lockfile, 빌드 시 VITE_API_URL/VITE_APP_URL를 GitHub Secrets에서 주입, dist/*를 EC2에 SCP로 전송, SSH로 원격에서 /tmp/fe-deploy로 이동 후 /var/www/dokdok 교체·소유권(www-data)·권한 설정·임시파일 및 이전 배포 백업(/var/www/dokdok-old) 처리. SSH 호스트·유저·키 정보는 Secrets 사용.

Sequence Diagram(s)

sequenceDiagram
  participant GH as GitHub Actions
  participant Runner as Runner (ubuntu-latest)
  participant Secrets as GitHub Secrets
  participant EC2 as EC2 Host

  GH->>Runner: 워크플로우 트리거 (PR merged to main/dev)
  Runner->>Runner: checkout
  Runner->>Runner: setup pnpm (v10.28.0) & Node.js (v20)
  Runner->>Secrets: 접근(SSH key, HOST, USER, VITE_*)
  Runner->>Runner: pnpm install --frozen-lockfile (pnpm cache)
  Runner->>Runner: pnpm build (env from Secrets)
  Runner->>EC2: scp dist/* (credentials from Secrets)
  Runner->>EC2: ssh -> mkdir /tmp/fe-deploy, mv, chown www-data, chmod, backup /var/www/dokdok -> /var/www/dokdok-old
  EC2-->>Runner: deploy result
  Runner-->>GH: workflow 완료/실패
Loading

문제 → 영향 → 대안:

  • 문제: PR 병합 시 자동으로 프로덕션에 배포됨.
  • 영향: 잘못된 빌드나 환경변수 누락 시 서비스 중단 가능성.
  • 대안: 스테이징 배포 흐름 추가 및 배포 전 검증/롤백 단계(헬스체크, 블루그린 또는 버전별 디렉토리)를 도입.

평가 항목

🎯 2 (Simple) | ⏱️ ~12분

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경사항의 핵심을 명확하게 설명하고 있습니다. 'EC2 프론트엔드 자동 배포 워크플로우 추가'는 새로운 GitHub Actions 배포 워크플로우 추가라는 주요 변경사항을 정확히 반영합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/deploy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @.github/workflows/deploy.yml:
- Around line 3-6: CI currently deploys both branches listed in on.push.branches
(main and dev) to the same target, causing dev to overwrite production; update
the workflow by making the deploy job conditional on the branch (use github.ref
or if: startsWith(github.ref, 'refs/heads/dev') / 'refs/heads/main') and set
branch-specific deploy destinations (e.g., use a different target for dev versus
main) or attach an environment with required reviewers for the main branch;
modify the deploy job (the job named "deploy" or the steps that perform the
rsync/ssh copy) to select the destination path and/or environment based on the
branch to prevent accidental overwrites.
- Around line 51-55: Current approach removes /var/www/dokdok with rm -rf then
moves /tmp/fe-deploy into place, risking downtime or partial deploys; instead
implement an atomic swap: copy or move the contents of /tmp/fe-deploy into a new
sibling directory (e.g. /var/www/dokdok_new), set ownership/permissions there
(chown/chmod), then use a single rename (mv) to atomically replace
/var/www/dokdok with the new directory and finally remove the old backup
directory; update the workflow steps that currently run sudo rm -rf
/var/www/dokdok, sudo mv /tmp/fe-deploy/* /var/www/dokdok/, sudo chown -R
www-data:www-data /var/www/dokdok and rm -rf /tmp/fe-deploy to follow this
create-set-permissions-atomic-rename-remove-old pattern.
- Around line 34-49: Add SSH host key verification to both the
appleboy/scp-action@v0.1.7 and appleboy/ssh-action@v1.2.0 steps by passing a
fingerprint input (e.g., fingerprint: ${{ secrets.SSH_HOST_FINGERPRINT }});
compute the server's SSH host key fingerprint (SHA256) and store it in the
secret, then add the fingerprint input to the scp step and the ssh step so the
actions verify the host key before connecting.

Comment on lines +3 to +6
on:
push:
branches: [main, dev]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

dev/main 동일 경로 배포 위험
문제: main과 dev가 모두 /var/www/dokdok로 배포됩니다.
영향: dev 푸시가 운영을 덮어써 예기치 않은 서비스 변경이 발생할 수 있습니다.
대안: 브랜치별 배포 경로 분리(예: /var/www/dokdok-dev) 또는 환경 보호/승인 게이트를 적용하세요.

Also applies to: 51-54

🤖 Prompt for AI Agents
In @.github/workflows/deploy.yml around lines 3 - 6, CI currently deploys both
branches listed in on.push.branches (main and dev) to the same target, causing
dev to overwrite production; update the workflow by making the deploy job
conditional on the branch (use github.ref or if: startsWith(github.ref,
'refs/heads/dev') / 'refs/heads/main') and set branch-specific deploy
destinations (e.g., use a different target for dev versus main) or attach an
environment with required reviewers for the main branch; modify the deploy job
(the job named "deploy" or the steps that perform the rsync/ssh copy) to select
the destination path and/or environment based on the branch to prevent
accidental overwrites.

Comment on lines +34 to +49
- name: Deploy to EC2
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
source: "dist/*"
target: "/tmp/fe-deploy"
strip_components: 1

- name: Move files and set permissions
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

appleboy scp-action ssh-action host key verification fingerprint known_hosts

💡 Result:

appleboy/ssh-action and appleboy/scp-action don’t use a known_hosts input; instead, they support SSH host key verification via a SHA256 host fingerprint (and proxy_fingerprint for jump hosts). [1][2]

How to do host key verification (recommended):

  1. Get the server’s host-key fingerprint (SHA256) on the server (example for ed25519):

    ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub | cut -d ' ' -f2

    (Use the matching host key type your server actually uses.) [1]

  2. Store that output as a GitHub Secret, e.g. SSH_FINGERPRINT.

  3. Pass it to the action:

    ssh-action

    - uses: appleboy/ssh-action@v1
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.KEY }}
        fingerprint: ${{ secrets.SSH_FINGERPRINT }}
        script: whoami

    [1]

    scp-action

    - uses: appleboy/scp-action@v1
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.KEY }}
        fingerprint: ${{ secrets.SSH_FINGERPRINT }}
        source: dist/*
        target: /var/www/app

    [2]

If you specifically need known_hosts-style pinning, you’d typically do that with OpenSSH directly (e.g., ssh-keyscan to write ~/.ssh/known_hosts) and then run scp/ssh yourself—but for these appleboy/* actions, the built-in mechanism is the fingerprint input. [1][2]


SSH 호스트 키 검증 누락
문제: SCP/SSH 단계에서 호스트 키 검증이 설정되지 않았습니다.
영향: 중간자 공격(MITM)에 취약합니다.
대안: 서버의 SSH 호스트 키 지문(SHA256)을 구한 후 fingerprint 입력값으로 전달하세요.

- uses: appleboy/scp-action@v0.1.7
  with:
    host: ${{ secrets.EC2_HOST }}
    username: ${{ secrets.EC2_USER }}
    key: ${{ secrets.EC2_SSH_KEY }}
    fingerprint: ${{ secrets.SSH_HOST_FINGERPRINT }}
    source: "dist/*"
    target: "/tmp/fe-deploy"
    strip_components: 1

SSH 호스트 지문 확인: ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub | cut -d ' ' -f2

🤖 Prompt for AI Agents
In @.github/workflows/deploy.yml around lines 34 - 49, Add SSH host key
verification to both the appleboy/scp-action@v0.1.7 and
appleboy/ssh-action@v1.2.0 steps by passing a fingerprint input (e.g.,
fingerprint: ${{ secrets.SSH_HOST_FINGERPRINT }}); compute the server's SSH host
key fingerprint (SHA256) and store it in the secret, then add the fingerprint
input to the scp step and the ssh step so the actions verify the host key before
connecting.

push 트리거 대신 pull_request closed + merged 조건으로 변경하여
main, dev 브랜치에 PR이 merge될 때만 배포가 실행되도록 수정합니다.
rm -rf 후 mv 방식 대신 디렉터리 rename 스왑으로 변경하여
배포 중 다운타임 및 부분 배포 문제를 방지합니다.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/deploy.yml:
- Around line 52-59: The deploy script can fail on first run because the sudo mv
/var/www/dokdok /var/www/dokdok-old command will error if /var/www/dokdok
doesn't exist; modify the script to tolerate a missing source by either
appending a no-op-on-failure operator (i.e., make the mv resilient) or by
wrapping that mv in a conditional existence check that only runs the move when
/var/www/dokdok is present, and keep the subsequent sudo mv /tmp/fe-deploy
/var/www/dokdok and cleanup steps unchanged so the rest of the deployment
proceeds.

Comment on lines +52 to +59
script: |
sudo mkdir -p /tmp/fe-deploy
sudo chown -R www-data:www-data /tmp/fe-deploy
sudo chmod -R 755 /tmp/fe-deploy
sudo rm -rf /var/www/dokdok-old
sudo mv /var/www/dokdok /var/www/dokdok-old
sudo mv /tmp/fe-deploy /var/www/dokdok
sudo rm -rf /var/www/dokdok-old No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

첫 배포 시 스크립트 실패 가능

문제: Line 57에서 /var/www/dokdok가 존재하지 않으면 mv 명령이 실패합니다.
영향: 첫 배포 또는 디렉터리가 없는 환경에서 전체 배포가 중단됩니다.
대안: || true 추가 또는 조건부 체크를 적용하세요.

🔧 수정 제안
             sudo mkdir -p /tmp/fe-deploy
             sudo chown -R www-data:www-data /tmp/fe-deploy
             sudo chmod -R 755 /tmp/fe-deploy
             sudo rm -rf /var/www/dokdok-old
-            sudo mv /var/www/dokdok /var/www/dokdok-old
+            sudo mv /var/www/dokdok /var/www/dokdok-old || true
             sudo mv /tmp/fe-deploy /var/www/dokdok
             sudo rm -rf /var/www/dokdok-old
🤖 Prompt for AI Agents
In @.github/workflows/deploy.yml around lines 52 - 59, The deploy script can
fail on first run because the sudo mv /var/www/dokdok /var/www/dokdok-old
command will error if /var/www/dokdok doesn't exist; modify the script to
tolerate a missing source by either appending a no-op-on-failure operator (i.e.,
make the mv resilient) or by wrapping that mv in a conditional existence check
that only runs the move when /var/www/dokdok is present, and keep the subsequent
sudo mv /tmp/fe-deploy /var/www/dokdok and cleanup steps unchanged so the rest
of the deployment proceeds.

@dkqpeo dkqpeo self-assigned this Jan 30, 2026
@dkqpeo dkqpeo requested a review from a team January 30, 2026 12:23
@dkqpeo dkqpeo added the docs 문서 작성 및 수정 label Jan 30, 2026
Copy link
Contributor

@mgYang53 mgYang53 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다 👍

@mgYang53 mgYang53 merged commit b6c15f6 into main Jan 31, 2026
1 check passed
@dkqpeo dkqpeo deleted the feat/deploy branch January 31, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs 문서 작성 및 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants