개발 생산성을 극대화하는 Next.js 프로젝트 배포 자동화 방법에 대해 정리합니다.
보통 수정사항이 생기면, 빌드하고 서버에 SSH로 접속해서 파일 옮기고, 서비스를 재시작하는 반복작업이 필요합니다. 어떻게 보면 간단한 절차이긴 하지만 횟수가 많아지면 귀찮은 일이 될 수밖에 없죠. 수동으로 하던 배포 과정을 클릭 한 번(Git Push)으로 끝내는 효율적인 방법을 정리하고 소개합니다.

목표 아키텍처 및 준비물
구축할 시스템의 전체적인 흐름은 다음과 같고, 별도의 CI/CD 서버를 두지 않고 GitHub 자체 인프라를 활용하여 비용과 복잡도를 낮추고자 했습니다.
핵심 도구:
- GitHub Actions: 코드 변경을 감지하고 자공으로 작업을 수행하는 봇.
- SSH: 봇이 안전하게 서버에 접속하기 위한 보안 통로
- PM2: Node.js 앱을 무중단으로 관리해 주는 프로세스 관리자.
- Nginx Proxy Manager: 외부 도메일 요청을 내부 앱으로 연결해 주는 리버스 프락시
준비물
- 개발 완료된 Next.js 프로젝트
- SSH 접속이 가능한 호스팅용 리눅스 서버 (Node.js, Git, Nginx Proxy Manager 설치 필요)
STEP 1. 서버 기초 공사 (최초 1회 설정)
자동 배포를 위해서 서버에 앱이 돌아갈 수 있는 환경을 만들어줘야 합니다. 이 과정은 딱 한번 수동으로 진행합니다.
서버에 프로젝트 복제 및 실행
서비스를 호스팅 할 서버에 SSH 접속을 하고 원하는 위치에 프로젝트를 클론 하고, 의존성을 설치한 뒤 빌드합니다.
# 1. 프로젝트 클론
git clone https://github.com/사용자명/프로젝트명.git
cd 프로젝트명
# 2. 의존성 설치 및 빌드
npm install
npm run build
# 3. PM2 설치 (안 되어 있다면)
npm install -g pm2
PM2로 서비스 시작 및 설정 저장
PM2를 이용해 서비스를 시작합니다. 이때 '--name' 옵션을 사용해 프로세스에 고유한 이름표를 붙여줍니다. (설명을 위해서 'next-app'이라는 이름을 사용하겠습니다.)
# 'next-app'이라는 이름으로 서비스 시작 (기본 포트 3000)
pm2 start npm --name "next-app" -- start
# 서버 재부팅 시에도 자동 실행되도록 현재 상태 저장
pm2 save
pm2 startup
여기서 pm2 명령을 풀어쓰면, "next-app"이라는 이름으로 npm 엔진을 관리해 줘. npm을 실행할 때는 -- 뒤에 있는 인자를 전달해, 와 같습니다. 따라서 "npm run start" 명령을 pm2가 관리해 주는 거죠.
그리고 다음 명령으로 pm2가 실행하고 있는 모든 앱의 상태를 확인할 수 있습니다.
pm2 list
STEP 2. 보안 연결 설정 (GitHub Actions ↔ 호스팅 서버)
가장 중요한 보안 설정 단계입니다. GitHub의 봇(Actions)이 비번 없이 내 서버에 접속할 수 있도록 마스터키(SSH Key)를 발급하고 등록해야 합니다.
리눅스 서버에서 SSH 키 페어 생성
서버 터미널에서 아래 명령어를 입력하고 엔터를 계속 눌러서 키를 생성합니다.
ssh-keygen -t rsa -b 4096 -C "github-actions-deploy"
공개키(Public Key)를 서버에 등록
생성된 공개키를 '접속 허용 목록'에 추가합니다. 이렇게 되면 외부서버에서 이 키 페어를 이용해서 접속을 요청하면 비밀번호 없이 접속이 가능해집니다.
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
개인키(Private Key)를 GitHub에 등록
GitHub 봇에게 맡길 개인키를 확인하고 복사합니다. (절대 외부 노출이 되지 않도록 주의하세요.) 아래 명령어로 나온 내용 전체를 복사합니다.
cat ~/.ssh/id_rsa
주의: 아래 예시와 같인 "-----BEGIN..." 부터 "...KEY-----"까지를 모두 복사해야 합니다.
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
NhAAAAA....
... 중략 ...
....UlJy7H+mpWWMZvPPvYOJ4ufc7+6YboSG7GiyphH7GKAAwnbtPQCwKN216JFIHDyT09E
vuQGS/hkKn0AAAATZ2l0aHViLWFjdGlvbi1kZXBseQ==
-----END OPENSSH PRIVATE KEY-----
이제 GitHub 저장소 페이지로 이동해서 Settings > Secrets and variables > Actions 메뉴에서 New repository secret을 클릭하여 아래 4가지 정보를 등록합니다.

New repository secret 버튼을 클릭할 때마다 1개씩 값을 등록할 수 있어서 4번 반복해서 등록합니다.
| Name | Value |
| HOST | IP 주소 또는 도메인 주고 |
| USERNAME | 접속 계정명 (예: root) |
| KEY | 위에서 복사한 개인키 전체 내용 |
| PORT | SSH 접속포트 (예: 22) |
참고로 저는 SSH 접속 포트를 기본 포트인 22번이 아닌 다른 포트를 사용하고 있었는데 GitHub 쪽에서 다른 포트로는 접속이 되지 않아서 일단 22번 포트로 했습니다.
STEP 3 배포 지지서(Workflow) 작성
이제 Github Actions 봇이 수행할 작업 지지서를 작성합니다. 프로젝트 푸트에 '.github/workflows/deploy.yml' 파일을 생성하고 아래 내용을 작성합니다.
name: Deploy to Production Server
on:
push:
branches: [ main ] # 'main' 브랜치에 코드가 푸시되면 실행
jobs:
deploy:
runs-on: ubuntu-latest # GitHub 호스트에서 실행
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "18" # or your required version
- name: Set up SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts
- name: Deploy to server
run: |
ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no \
${{ secrets.USERNAME }}@${{ secrets.HOST }} "bash -l -c '
cd /home/${{ secrets.USERNAME }}/실제/프로젝트/폴더명 && \
git fetch origin && \
git reset --hard origin/main && \
git clean -fd && \
source ~/.nvm/nvm.sh && \
npm install && \
npm run build && \
npm prune --production && \
pm2 reload next-app
'"
여기서 핵심은 "pm2 reload next-app" 명령은 기존 프로세스를 유지하면서 새 코드를 적용하기 때문에 다운타임을 최소화 한 배포가 가능합니다.
STEP 4. Nginx Proxy Manager 설정
마지막으로 외부 도메인 요청을 내부의 Next.js앱으로 연결해 줍니다. Next.js는 PM2에 의해 기본적으로 3000번 포트에서 실행됩니다. 그래서 호스팅 할 도메인명을 설정하고, 앱이 호스팅 되고 있는 IP주소를 입력하고 포트번호를 3000으로 맞춰 줍니다. 그리고 필요에 따라 SSL 인증서 설정도 해 줍니다.

마무리: 이제 "Push"만 하세요
모든 설정이 끝났습니다. 이제 개발을 하는 PC에서 코드 수정을 하고 'git push prigin main'만 하면 GitHub Action탭에서 배포 파이프라인이 자동으로 동작합니다. 이 아키텍처는 초기 설정이 조금 번거로울 수 있지만, 한번 구축해 두면 개발에만 집중할 수 있는 쾌적한 환경이 됩니다. 유지보수 측면에서도 관리가 용의 하겠죠.
끝.
'Software > JS & TS & React' 카테고리의 다른 글
| React, Next.JS 프로젝트의 심각한 취약점(CVE-2025-55182) 점검 및 업데이트 방법 (1) | 2025.12.09 |
|---|---|
| 리액트 개발서버 포트번호 변경: 3000번이 아닌 다른 번호로 설정하기! (0) | 2024.08.21 |
| nodemon 사용법 (2) | 2023.07.09 |
| 전역변수 없이 속성으로 자식 컴포넌트에 데이터 전달하기 (0) | 2023.02.27 |
댓글