본문 바로가기
AI Journey/웹

리눅스 환경에서 Node.js/Express로 웹 서버 구동하기

by 보눔비스타 2026. 1. 8.

가상화 기술과 클라우드 환경이 보편화되면서 웹 애플리케이션의 구조는 거대한 모놀리식(Monolithic) 형태에서 가볍고 유연한 마이크로서비스 형태(MSA)로 변화하고 있다.

특히 Docker 컨테이너나 Kubernetes Pod 환경에서는 애플리케이션이 얼마나 '가볍게' 구동될 수 있는지가 관건이다.

이러한 트렌드 속에서 기존의 Apache/Nginx와 Tomcat 조합보다 훨씬 경량화된 Node.jsExpress.js가 백엔드 개발의 핵심 도구로 자리 잡았다.

리눅스(Ubuntu) 환경에서 Node.js 개발 환경을 구축하고, 버전 호환성 문제를 해결하며 간단한 웹 서버를 띄우는 과정을 단계별로 정리한다.

1. 환경 구축: NVM을 이용한 Node.js 설치

리눅스 시스템의 패키지 매니저(apt)를 통해 Node.js를 설치할 수도 있지만, 개발 과정에서는 프로젝트별로 요구하는 Node 버전이 다를 수 있다.

NVM(Node Version Manager)은 시스템 전역이 아닌 사용자 영역에서 Node.js 버전을 독립적으로 관리하게 해주는 도구로, 여러 프로젝트를 동시에 진행할 때 버전 충돌을 막아준다.

NVM을 사용하면 use 명령어를 사용해 원하는 Node 버전으로 옮겨가며 유연하게 사용할 수 있다.

1-1. NVM 설치 및 설정

먼저 curl 명령어를 사용하여 NVM 설치 스크립트를 다운로드하고 실행한다.

curl로 가져온 스크립트는 홈 디렉토리의 .nvm 폴더에 소스 코드를 클론하고, .bashrc 파일에 실행 경로를 저장한다.

# NVM 설치 스크립트 다운로드 및 실행
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

# 쉘 설정 파일 갱신 (터미널 재시작 없이 nvm 명령어 사용을 위해)
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

 

1-2. Node.js 설치 및 호환성 이슈 해결 (Troubleshooting)

최신 버전의 Node.js를 설치하려다 보면, 구형 리눅스 OS의 시스템 라이브러리(glibc) 버전과 충돌이 발생할 수 있다.

# 최신 버전(v24) 설치 시도
nvm install 24
node -v
# 에러 발생: 
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found

 

위와 같은 에러는 OS의 C 라이브러리 버전이 낮아서 발생한다.

무조건 최신 버전을 쓰기보다, 현재 시스템 환경과 호환되면서도 안정적인 LTS(Long Term Support) 버전을 선택하는 것이 중요하다.

여기서는 호환성이 좋은 v16 버전을 설치하여 진행한다.

# 호환 가능한 버전(v16) 설치 및 사용 설정
nvm install 16
nvm use 16

# 버전 확인
node -v 
# 출력 예시: v16.20.2

 

2. 프로젝트 초기화 및 패키지 관리

Node.js 환경이 준비되었다면, 웹 애플리케이션 프로젝트를 생성하고 초기화한다.

2-1. 디렉토리 생성 및 npm init

프로젝트를 위한 폴더를 만들고 npm init을 실행한다.

mkdir user-service-api
cd user-service-api

# 프로젝트 초기화 (package.json 생성)
npm init
  • npm init 명령어는 프로젝트의 이름, 버전, 진입점(entry point) 등을 묻고, 그 결과를 담은 package.json 파일을 생성한다.

2-2. Express 프레임워크 설치

Express란?

Node.js를 위한 웹 애플리케이션 프레임워크다.

Java의 JSP/Spring, Python의 Django/Flask와 같은 역할을 하지만 훨씬 가볍고 설정이 간편하다.

웹 서버 기능을 구현하기 위해 Express.js를 설치한다.

npm install --save express
  • --save 옵션(최신 npm에서는 생략 가능)은 package.json의 dependencies 항목에 express를 추가한다는 의미다. 이로써 이 프로젝트가 express에 의존하고 있음을 명시한다.

3. 웹 서버 구현 및 아키텍처 이해

이제 실제로 코드를 작성하여 서버를 구동해본다.

3-1. 서버 코드 작성 (index.js)

nano나 vi 에디터를 이용해 index.js 파일을 생성하고 다음 코드를 작성한다.

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

 

  • require('express') : 설치된 express 모듈을 불러온다.
  • app.get('/', ...) : 루트 경로(/)로 들어오는 HTTP GET 요청에 대해 "Hello World!"를 응답한다.
  • app.listen(port) : 3000번 포트에서 요청 대기 상태(Listen)로 진입한다.

3-2. 소켓(Socket)과 웹 서버의 개념

여기서 port와 listen의 의미를 이해하는 것이 중요하다.

  • 소켓(Socket): 네트워크상에서 데이터를 주고받기 위한 창구로, '서버 IP 주소 + 포트 번호'의 조합으로 구성된다. 외부 클라이언트는 이 소켓 주소를 통해 서버에 접속한다.
  • 경량화된 웹 서버: 과거에는 Apache와 같은 무거운 웹 서버 소프트웨어를 별도로 띄우고 그 위에서 애플리케이션을 돌렸다. 하지만 Node.js 환경에서는 코드 몇 줄만으로 내장된 라이브러리를 통해 자체적인 웹 서버 기능을 수행한다.

 

 

4. 서버 실행 및 테스트

작성한 코드를 실행하여 서버를 구동한다.

# 서버 실행
node index.js
# 출력: 
Example app listening on port 3000

 

서버가 정상적으로 실행되었다면, 다른 터미널 창을 열거나 브라우저를 통해 접속을 확인한다.

GUI 환경이 아닌 경우 터미널 기반 브라우저나 curl을 사용할 수 있다.

 
 

5. 정리

Node.js와 Express는 다음 두 가지 관점에서 클라우드 네이티브 시대에 가장 적합한 아키텍처를 이해하는 데 필수적이다. 
  • 경량화 트렌드: 별도의 웹 서버 설치 없이 코드 몇 줄로 서버를 띄우는 방식은 클라우드 및 컨테이너(Docker) 환경에 최적화되어 있다.
  • 확장성: 이 기초 위에 Jenkins와 같은 CI/CD 도구를 연동하면 코드 변경 시 자동으로 빌드 및 배포가 이루어지는 파이프라인을 구축할 수 있으며, 이는 DevOps의 핵심이다.