GitHub Actions로 프론트엔드 배포하기

왔다 정보리·2026년 2월 17일

기존에 OCI DevOps로 빌드-배포 파이프라인을 설정하다가 잘 되지 않아 GitHub Actions를 사용하여 파이프라인을 구축하게 되었다. GitHub Actions를 사용하니 복잡한 설정 없이 deploy.yml 파일 하나로 자동 배포 설정이 가능했고, 막히고 있던 프론트엔드 배포를 빠르게 완료할 수 있었다.


GitHub Actions


GitHub Actions

GitHub에서 제공하는 CI/CD 플랫폼이다. 레포지토리에 특정 이벤트(푸시, PR 등)가 발생하면 자동으로 정의된 작업을 실행시킬 수 있다. .github/workflows/ 디렉토리에 YAML 파일을 만들면 설정이 완료된다.

장점

  1. GitHub가 제공하는 러너에서 실행되어 별도 CI/CD 서버가 필요 없다
  2. SSH 키, API 키 등을 GitHub에서 안전하게 관리할 수 있다
  3. 워크플로우 실행 로그를 GitHub Actions 탭에서 바로 확인할 수 있다
  4. 파일 전송, SSH 접속 등 다양한 액션을 가져다 쓸 수 있다

GitHub Actions로 프론트 배포하기


1. 서버 환경 구성

컨테이너역할
nginx-proxySSL 인증서 처리 + 리버스 프록시
frontendnginx:alpine 기반, Vite 빌드 정적 파일 서빙
backendSpring Boot 애플리케이션

서버 환경은 각 프로젝트에 맞게 구성하면 된다. 이번 프로젝트의 경우, Docker Compose로 여러 컨테이너를 띄워서 프론트, 서버 환경을 구성했다. 클라이언트 요청은 nginx-proxyfrontend 순서로 전달되며, Vite로 빌드된 정적 파일은 frontend 컨테이너의 /usr/share/nginx/html/에서 서빙한다. 배포 시 이 경로의 파일만 교체하고 Nginx를 리로드하면 반영된다.

2. Secrets 등록

Secret 이름설명
SSH_PRIVATE_KEY운영 서버 접속을 위한 SSH 개인키
INSTANCE_IP운영 서버의 공인 IP 주소
VITE_SERVER_URL_API백엔드 API 서버 주소
VITE_GOOGLE_MAPS_API_KEY프로젝트 환경 변수

Repository → Settings → Secrets and variables → Actions에서 등록한다. GitHub Actions에서 SSH 접속과 환경 변수를 사용하려면 먼저 Secrets를 등록해야 한다. Secrets는 워크플로우 로그에 자동으로 마스킹 처리된다.

3. 워크플로우 파일 정의

name: Build and Deploy Frontend

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

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

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm install

      - name: Build
        env:
          VITE_SERVER_URL_API: ${{ secrets.VITE_SERVER_URL_API }}
          VITE_GOOGLE_MAPS_API_KEY: ${{ secrets.VITE_GOOGLE_MAPS_API_KEY }}
        run: npm run build

      - name: Deploy to Instance
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.INSTANCE_IP }}
          username: ubuntu
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: "dist/*"
          target: "/tmp/deploy"
          strip_components: 1

      - name: Update Frontend Container
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.INSTANCE_IP }}
          username: ubuntu
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            echo "=== Deploying to frontend container ==="
            docker exec frontend sh -c "rm -rf /usr/share/nginx/html/*"
            docker cp /tmp/deploy/. frontend:/usr/share/nginx/html/
            docker exec frontend nginx -s reload
            rm -rf /tmp/deploy
            echo "✓ Deployment complete!"

.github/workflows/deploy.yml 파일에 전체 배포 프로세스를 정의한다. main 브랜치에 푸시하면 워크플로우가 자동으로 실행된다.

3-1. 실행 환경

GitHub가 제공하는 Ubuntu 러너에서 작업을 실행한다. 서버를 따로 관리하지 않아도 되며, 작업이 끝나면 자동으로 정리된다.

3-2. Steps 상세

1. 코드 체크아웃 및 Node.js 설정

레포지토리 코드를 가져오고 Node.js 18 버전을 설치한다.

2. 의존성 설치
npm install로 의존성을 설치한다. 매번 클린 환경에서 시작하므로 로컬 환경 차이로 인한 문제가 없다.

3. 빌드
환경 변수를 설정하고 npm run build를 실행한다. Vite가 빌드할 때 환경 변수 값을 읽어서 번들에 포함시키기 때문에, import.meta.env.VITE_SERVER_URL_API 같은 코드가 실제 값으로 치환된다.

4. SCP로 파일 전송
appleboy/scp-action을 사용해 SSH를 통해 빌드 결과물을 운영 서버로 전송한다. strip_components: 1 옵션으로 dist/ 폴더 구조를 제거하고 내부 파일만 전송하여, /tmp/deploy/index.html 형태로 저장된다.

5. SSH로 배포 스크립트 실행

docker exec frontend sh -c "rm -rf /usr/share/nginx/html/*"  # 기존 파일 삭제
docker cp /tmp/deploy/. frontend:/usr/share/nginx/html/      # 새 파일 복사
docker exec frontend nginx -s reload                         # Nginx 리로드
rm -rf /tmp/deploy                                           # 임시 디렉토리 정리

docker cp에서 점(.)은 "현재 디렉토리의 모든 내용"을 의미한다. 기존 파일 삭제와 새 파일 복사 사이에 짧은 공백이 생길 수 있으므로 완전한 무중단 배포는 아니지만, nginx -s reload는 기존 연결을 끊지 않고 설정을 반영하므로 리로드 자체는 무중단으로 처리된다.

4. Nginx 설정

server {
    listen 443 ssl;
    server_name roominus.kr;

    # ... SSL 설정 생략

    # 모든 요청을 frontend 컨테이너로 프록시
    location / {
        proxy_pass http://frontend:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 정적 파일은 1년 캐싱 (Vite가 파일명에 해시를 붙이므로 캐시 무효화 걱정 없음)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        proxy_pass http://frontend:80;
        proxy_set_header Host $host;
        expires 1y;
        add_header Cache-Control "public, no-transform";
        access_log off;
    }
}

frontend는 Docker Compose의 서비스명으로, Docker 네트워크 내부에서 컨테이너를 찾는다. 배포 시 frontend 컨테이너 내부의 /usr/share/nginx/html/ 파일만 교체하면 이 설정이 새 파일을 서빙한다.

마치며


OCI DevOps를 사용하면서 막히는 부분이 많았는데 GitHub Actions 덕분에 프론트 배포를 빠르게 마무리할 수 있었다. 물론 각각의 장단점이 있겠지만, 복잡한 세팅이 필요없는 경우에는 GitHub Actions를 활용하면 좋을 것 같다.

참고 자료

GitHub Actions 공식 문서
appleboy/scp-action - GitHub
appleboy/ssh-action - GitHub

profile
왔다 정보리

0개의 댓글