이전의 EC2로 Next.js 배포하기 포스팅
[AWS EC2] Next.js 프로젝트 배포하기 (ubuntu + nginx + pm2)
[AWS EC2] Next.js 프로젝트 배포하기 (ubuntu + nginx + pm2)
들어가기 전에 다음 과정은 매우 간단한 Next.js App Router 프로젝트를 배포하는 과정입니다. AWS 가입 과정, 탄력적 IP연결, HTTPS설정, 도메인 등록, Docker 사용, 환경 변수 관리 등의 내용은 이 글에 포
unhandled.tistory.com
위 포스팅은 AWS EC2에서 Next.js를 배포하는 과정을 담은 글입니다. 글에는 EC2 인스턴스 가상 서버 위에 nvm(Node.js)를 설치하는 과정이 있습니다. (nvm은 여러 버전의 노드를 쉽게 switch 해서 사용할 수 있게 해주는 노드 버전 매니저입니다. 즉 nvm을 설치한 것은 Node.js를 설치한 것입니다.)
왜 Node를 설치하는 과정이 포함될까요?
프로젝트를 배포하는 과정
프로젝트를 배포한다는 것은 다음과 같은 과정을 거칩니다.
1. 프로젝트를 빌드하고
2. 빌드로 생성된 결과물을 배포합니다.
이 두 과정을 나누어서 생각해야 합니다.
첫 번째 과정 : 빌드하기
프로젝트를 빌드하는 과정에서는 노드가 반드시 필요합니다. 이는 Webpack, Vite와 같은 빌드 도구들이 전부 노드 환경에서 실행되고, npm, yarn 등의 패키지 매니저도 전부 노드 기반이기 때문입니다. 이 부분은 Next.js에만 국한되는 것이 아니라 순수 리액트나 뷰에서도 동일합니다.
Next.js가 이 빌드 부분에서 리액트와 다른 한 가지가 있습니다. Next.js에서의 SSG 페이지(+ISR)가 있으면 이 빌드타임에 렌더링이 발생합니다. (순수 리액트의 렌더링은 어떤 경우에도 빌드타임에(서버에서) 발생하지 않습니다.)
즉 Next.js를 빌드할 때 Node가 필요한 이유는 두 가지인 것입니다.
1. 빌드 도구와 패키지 매니저 등이 노드 환경을 필요로 한다. (이건 리액트와 동일)
2. SSG 페이지를 생성할 때 서버에서의 렌더링을 발생시켜야 한다. (SSG 페이지는 이 빌드 시점을 기준으로 html+css+js가 실행된 결과물을 렌더링하고 최종 html을 반환합니다.)
두 번째 과정 : 배포하기
그럼 이제 빌드로 생성된 결과물을 배포하는 과정이군요. Next.js의 배포 환경에는 노드가 필요할까요? 이건 일반적으로 "그렇다"입니다! SSR(서버 사이드 렌더링)을 한다면 반드시 필요합니다.
(근데 일반적으로 그렇다는 건.. 안 그런 경우도 있다는 것 아닌가요?
그렇습니다!
하지만 그를 살펴보기 전에 다음 내용부터 봐주세요. )
SSR(서버 사이드 렌더링)을 위한 Node.js가 필요해
Next.js의 서버 컴포넌트의 코드는 이 서버(EC2 인스턴스의 가상 서버)에서 실행됩니다. 이것이 바로 서버 사이드 렌더링(Server Side Rendering)입니다.
그런데 자바스크립트는 원래 웹 브라우저 환경이 아니면 실행할 수 없습니다. 웹 전용 언어로 만들어졌기 때문이지요. 그런데 EC2 인스턴스는 웹 브라우저 환경이 아닙니다. 그러면 웹 브라우저가 아닌 다른 곳에서 자바스크립트가 실행되게 하려면 어떻게 해야 할까요? 그것은 바로 자바스크립트 런타임 환경, 즉 Node.js를 설치하는 것입니다. (자바스크립트 런타임은 deno 등 다른 것들도 있지만 여기서는 Node을 기준으로 이야기하겠습니다.)
리액트의 경우
순수 리액트 프로젝트라면 자바스크립트 코드가 서버에서 실행될 일이 없습니다.(즉, 서버 사이드 렌더링이 발생할 일이 없습니다.) 그러므로 배포 서버에 Node.js를 설치할 필요가 없습니다. 이 부분이 Next.js와 순수 리액트(SSR이 발생하지 않는) 간의 배포 과정에서의 가장 큰 차이점이라고 할 수 있습니다.
그러니까 서버 사이드 렌더링을 위한 Node.js는 배포 서버에 있어야 합니다!
빌드 환경 == 배포 환경인 경우
저 EC2 포스팅에서 EC2 인스턴스는 빌드 서버이자 배포 서버였습니다. EC2 위에 프로젝트를 클론해와서 빌드한 후 배포한 것이니 하나의 환경(EC2 인스턴스)에서 빌드와 배포가 같이 진행된 것이죠.
이 경우는 빌드를 위해 이미 Node를 설치했으므로, SSR이 발생하는 경우 이 설치된 Node를 그냥 가져다 사용하면 됩니다.
(그리고 저는 배포 과정에서 PM2를 사용했는데 이는 결국 노드 위에서 동작하는 프로세스 매니저라 Next.js의 SSR까지 고려하지 않아도 어차피 PM2를 쓴다면 노드는 필요했습니다.)
그런데 이렇게 EC2가 빌드 서버이지 배포 서버인 경우는 드뭅니다. 저는 도커와 젠킨스 등 다른 CI/CD 툴에 대한 지식이 없어서 간소화한 방식을 택한 것입니다. 현업이나 팀 프로젝트에서는 빌드서버가 곧 배포서버는 아닌 경우가 대부분입니다. 즉, 두 과정이 발생하는 환경이 분리되어 있습니다.
빌드 환경!= 배포 환경인 경우
빌드는 젠킨스 같은 CI/CD툴에서도 할 수 있고 도커 컨테이너 내에서도 할 수 있죠. 이 경우 빌드 서버는 더 이상 EC2가 아닙니다. 이제 빌드를 위해 설치한 노드는 배포 환경과는 별개입니다. 이 말은 SSR을 위한 Node.js를 배포 서버에 별도로 설치해야 된다는 것입니다.
젠킨스에서 빌드한다면? (도커는 없음)
빌드는 젠킨스에서 따로 하고 EC2로 배포한다면, EC2에 노드가 있어야 SSR이 가능합니다.
도커를 쓴다면 이제 EC2의 노드 런타임 여부는 중요하지 않아
도커는 쓰는 시점에서 이제 EC2 위의 노드 설치 여부는 중요하지 않습니다. 도커 컨테이너는 어쨌든 EC2로 서빙되니 EC2 서버 위에 있는 것이긴 하지만 도커 컨테이너는 고립된 컨테이너이기 때문에 컨테이너 외부 환경의 영향을 받지 않기 때문입니다. 이때 배포 서버는 곧 "도커 컨테이너 내"가 되므로 이 배포 서버에서 노드를 사용하려면 도커파일에 노드를 설치하는 과정이 존재해야 합니다.
배포 서버에 Node가 없어도 Next.js를 배포할 수 있는 경우
이것이 가능한 상황은 딱 하나입니다.
Next.js 프로젝트에 output: export 설정을 적용한 후 빌드한 결과물을 배포해야 한다는 것입니다.
next.config.js
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',
}
module.exports = nextConfig
Static Exports(정적 배포)란 무엇일까요?
간략하게 말한다면 Next.js의 서버 관련 기능을 배제하고 사용하겠다는 것입니다. 이로 인해 "사용자한테 빨리 보인다"라는 이점을 얻을 수 있게 되고 여기서 포기한 서버 관련 기능 중 하나가 바로 SSR입니다. 더 이상 SSR을 사용하지 않는다는 것은 배포 서버의 자바스크립트가 실행되지 않는다는 것이고, 이 자바스크립트를 실행할 수 있게 해주는 노드 런타임 또한 필요로 하지 않는다는 것입니다.
❓ 잠깐요! 프로젝트 내에 SSR이 없고 SSG+CSR 페이지만 있다면 output: "export"는 안 추가해도 되나요? ❓
→ 이건.. 나중에 다루겠지만 이 상황에서는 정상적인 배포가 불가능합니다.
Next.js를 EC2로 배포할 때 EC2에 노드를 설치해야 합니까?
위 소제목에 대해 상황 따라 분기를 나누어 답변해 보겠습니다.
1. EC2에서 빌드도 하고 배포도 하는 경우
→ 해야 합니다. (EC2가 빌드를 담당하는 순간 Node는 반드시 필요)
2. EC2로 배포하지만 빌드는 다른 곳에서 하는 경우
이 경우는 빌드를 jenkins와 같은 다른 CI/CD 툴이나 도커 컨테이너 내에서 하는 경우겠지요.
2-1. 도커를 사용하지 않는 경우
→ 해야 합니다. (SSR/ISR시 에러, SSG+CSR만 쓴다 해도 정상 배포 불가능)
2-2. 도커를 사용하는 경우
→ EC2에는 안 해도 되지만 도커파일에는 노드 설치 과정이 필요합니다. (도커 컨테이너 내부는 EC2와 분리되어 있는 고립된 환경이기에 SSR시 컨테이너 내의 노드 런타임이 필요합니다.)
2-3. 프로젝트를 static exports(정적 배포)의 방식으로 내보내려는 경우
→ 안 해도 됩니다. 다만 정적 배포의 목적과 의미를 알고 있어야 하며, 이 경우에도 빌드 과정에서의 노드는 필요합니다.(근데 이럴 거면 EC2가 아닌 S3 쓰는 게 더 효율적) 이 상황에서는 도커 유무도 상관없습니다.
결론
이 글의 제목인
"AWS EC2에 Next.js를 배포할 때 Node.js를 설치해야 합니까?"
라는 질문에 대한 답은
"일반적으로는 그렇다. 하지만 예외는 있다."
입니다.
+)
Vercel 배포 (PaaS)
Next.js 프로젝트를 Vercel를 통해 배포한다면 개발자가 직접 노드를 설치할 필요가 없습니다. 이미 플랫폼 배포 환경에 다 준비가 되어있을 테니까요. (Next.js는 배포 시 타 플랫폼 호환성 이유가 있는 경우가 있으므로 여기서는 Vercel만을 기준으로 말하겠습니다.) 프론트엔드 개발자는 인프라 세팅을 직접 하지 않고도 손쉽게 배포를 할 수 있지만 그 이면에서 일어나는 일들은 알지 못하게 됩니다.
AWS EC2 배포 (IaaS)
이 경우 EC2는 단지 가상 서버를 대여하는 것일 뿐이고 배포를 위한 환경설정은 전부 개발자가 직접 해주어야 합니다. Vercel에서는 추상화되었기에 거쳐야 할 필요가 없던 설정들을 직접 해야 한다는 것이지요. 여러 우여곡절을 겪을 일이 생기겠지만 위의 그 이면에서 일어나는 일들을 알 수 있게 되는 것입니다.
마무리
마지막에 뜬금없이 위 문단들을 덧붙인 이유는 사실 오늘의 주제는 Vercel과 같은 PaaS 방식의 배포만 경험해 보았더라면 꺼내지 않았을 주제이기 때문입니다. 배포는 인프라 엔지니어의 영역이기에 어찌 보면 프론트엔드 개발자에게 요구되는 핵심 역량은 아닙니다. 지금까지는 분명히 그랬던 것 같은데 앞으로는 아닐 수도 있다는 생각이 들어서요. Next.js를 이해하기 위해서는 인프라 영역에서의 지식이 필요하다고 느꼈습니다.
'FE > Next.js' 카테고리의 다른 글
[Next.js] App Router는 SPA(Single Page Application)인가? (0) | 2025.05.20 |
---|---|
[Next.js] AWS EC2에 Docker와 Node없이 Next.js 정적 배포(Static Exports)하기 (0) | 2025.05.18 |
[Next.js] 왜 Next.js는 "풀스택" 프레임워크라고 불리는가? (0) | 2025.05.03 |
[Next.js] 포트폴리오 성능 점수 100점 도전하기 (feat. 라이트하우스, 폰트 최적화) (0) | 2025.05.01 |
[Next.js] Yarn berry로 Next.js 프로젝트 시작하기 (0) | 2025.03.13 |