[TIL] Node.js 백엔드 초기 세팅 & Azure 배포

지현·2026년 7월 15일

부트캠프 미니프로젝트2 구움(Gooum)의 백엔드를 Python(FastAPI)에서 Node.js + TypeScript로 전환하고, Azure App Service에 GitHub Actions로 자동 배포까지 연결했다.

핵심 기능이 실시간 채팅, 동시 문서 편집이라 다수 클라이언트가 동시 접속해서 이벤트를 계속 주고받는 구조인데, Node.js의 이벤트 루프 기반 비동기 I/O가 이런 워크로드에 잘 맞고 Socket.io, Yjs 등 관련 라이브러리 생태계도 npm 쪽이 두터워서 스택을 바꾸기로 결정했다.


1. 로컬 Node.js + TypeScript 환경 세팅

패키지 초기화 및 설치

npm init -y

# 개발용 도구
npm install -D typescript tsx @types/node @types/express

# 운영용 라이브러리
npm install express dotenv

Node.js는 패키지를 프로젝트 폴더 안 node_modules에 설치하기 때문에 폴더 자체가 이미 격리된 환경이다. 파이썬의 venv 같은 가상환경 개념이 따로 필요 없다.

npm install할 때 -D(--save-dev) 옵션을 붙이면 devDependencies(개발용)로, 안 붙이면 dependencies(운영용)로 package.json에 기록된다.

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "rootDir": "./src",
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

TypeScript 컴파일러(tsc)가 .ts 파일을 어떻게 .js로 변환할지 정하는 설정 파일이다.

옵션의미
target컴파일된 JS가 어떤 자바스크립트 버전 문법을 쓸지 (ES2022)
module모듈 시스템 방식. CommonJS로 지정해 배포/라이브러리 호환성을 우선함
rootDir컴파일 대상 소스 파일들이 있는 루트 폴더 (src/)
outDir컴파일 결과물(.js)이 출력될 폴더 (dist/)
esModuleInteropimport express from 'express' 같은 ES Module 스타일 import 문법을 CommonJS 라이브러리에서도 에러 없이 쓸 수 있게 해줌
forceConsistentCasingInFileNames파일명 대소문자를 엄격하게 체크 (OS별로 대소문자 구분이 달라 생기는 오류 방지)
strict타입 검사를 엄격하게 적용 (null 체크, 암시적 any 금지 등)
skipLibChecknode_modules 안 라이브러리의 타입 정의 파일까지는 검사하지 않아 컴파일 속도를 높임
include컴파일 대상 파일 범위 지정 (src/ 하위 전체)

package.json

{
  "name": "gooum-be",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "tsx src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ureca-Gooum/Gooum-BE.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs",
  "bugs": {
    "url": "https://github.com/ureca-Gooum/Gooum-BE/issues"
  },
  "homepage": "https://github.com/ureca-Gooum/Gooum-BE#readme",
  "devDependencies": {
    "@types/express": "^5.0.6",
    "@types/node": "^26.1.1",
    "ts-node": "^10.9.2",
    "tsx": "^4.23.1",
    "typescript": "^7.0.2"
  },
  "dependencies": {
    "dotenv": "^17.4.2",
    "express": "^5.2.1"
  }
}
  • npm run dev : 로컬 개발 중 TS 파일 바로 실행 (tsx 사용, 별도 설정 없이 esbuild 기반으로 즉시 실행됨)
  • npm run build : TS → JS 컴파일 (dist/ 생성)
  • npm start : 컴파일된 JS로 실제 서버 구동 (배포 환경에서 사용)
  • "type": "commonjs" : 모듈 시스템을 CommonJS로 명시. tsximport 문법을 알아서 처리해주고, tsc 빌드나 일부 라이브러리와의 호환성을 위해 module(ESM)이 아닌 commonjs로 고정
  • ts-node는 devDependencies에 남아있지만 실제 실행은 tsx로 하고 있어 사실상 미사용 상태 (정리 대상)

기본 서버 코드 (src/server.ts)

import express, { Request, Response } from "express";
import dotenv from "dotenv";

dotenv.config();

const app = express();
// Azure가 임의로 부여하는 포트(process.env.PORT)를 우선적으로 사용하도록 설정!
const PORT = process.env.PORT || 8000;

app.use(express.json());

// 배포 테스트용 핑 API
app.get("/ping", (req: Request, res: Response) => {
  res.status(200).json({
    message: "pong! Node.js TS server is running on Azure!",
  });
});

app.listen(PORT, () => {
  console.log(`🚀 Server is running on port ${PORT}`);
});
  • dotenv.config()는 다른 코드가 process.env를 사용하기 전에 가장 먼저 실행되어야 하므로 파일 최상단에 둔다.
  • process.env.PORT || 8000 : 로컬에서는 8000번을 쓰고, 배포 환경(Azure)에서는 플랫폼이 지정한 포트를 우선 사용하도록 유연하게 작성.

.gitignore

# 환경 변수 및 비밀값
.env
.env.local

# 의존성 패키지 폴더
node_modules/

# 빌드 결과물
dist/
out/
build/

# 개발 도구 및 IDE 설정
.vscode/
.idea/

# OS 및 임시 파일
.DS_Store
Thumbs.db
npm-debug.log*

2. Azure App Service 생성

  • 게시(Publish): 코드(Code)
  • 런타임 스택: Node 20 LTS 또는 Node 22 LTS
  • 운영체제: Linux
  • 요금제: 테스트 단계면 Free(F1) 또는 최소 사양

기존에 다른 스택(Python 등)으로 쓰던 App Service가 있다면, 설정만 바꾸는 것보다 새로 생성하는 편이 안전하다. 내부 빌드 엔진이나 환경변수가 이전 스택 기준으로 남아 있어 오류가 나기 쉽다.


3. GitHub Actions로 자동 배포 연결

  1. Azure Portal → App Service → 배포 센터(Deployment Center)
  2. 원본(Source): GitHub 선택 후 계정 연동
  3. 배포할 레포지토리 / 브랜치(예: main) 선택 후 저장

저장하면 Azure가 자동으로 .github/workflows/*.yml 워크플로 파일을 레포지토리에 생성해준다. 이후 해당 브랜치에 push할 때마다 아래 과정이 자동으로 실행된다.

  1. 코드 checkout
  2. Node.js 설치
  3. npm installnpm run build
  4. 빌드 결과물 아티팩트 업로드
  5. Azure App Service에 배포

package.jsonbuild 스크립트가 정확히 정의돼 있어야 3번 단계가 정상 동작한다.


4. 시작 명령(Startup Command) 설정

Azure Portal → App Service → 구성(Configuration)일반 설정(General settings) → 시작 명령

포트는 명령어에 별도로 적을 필요 없다. 코드에서 process.env.PORT를 리슨하도록 작성했다면 Azure가 내부적으로 지정한 포트와 자동으로 맞물린다.


5. 포트 설정 (필요한 경우만)

Azure Linux App Service는 기본적으로 내부 포트를 8080으로 사용한다. 코드에서 process.env.PORT || 8000으로 작성해뒀다면 별도 설정 없이 자동으로 맞춰지지만, 만약 배포 후 502 Bad Gateway가 발생한다면 아래처럼 명시적으로 지정한다.

  • Azure Portal → 구성(Configuration) → 애플리케이션 설정(Application settings)
  • 이름: WEBSITES_PORT
  • 값: 실제 코드에서 사용 중인 포트 번호 (예: 8080)

6. 배포 확인

https://<앱이름>.azurewebsites.net/ping
{ "message": "pong! Node.js TS server is running!" }

Log stream에서 아래 메시지가 뜨면 정상 기동 상태다.

🚀 Server is running on port 8080


요약

  1. tsx로 TS 실행 환경 구성, dotenv로 비밀값 분리, .gitignore로 민감 정보 제외
  2. Azure에 Node.js 런타임(Linux)으로 App Service 생성
  3. 배포 센터에서 GitHub 레포 연결 → push할 때마다 GitHub Actions가 자동 빌드/배포
  4. 시작 명령은 node dist/server.js, 포트는 코드에서 process.env.PORT로 동적으로 대응
  5. 필요 시 WEBSITES_PORT 환경변수로 포트 명시

0개의 댓글