Windows server에서 Node.js 기반 API 서버 구동 - waegari/waegari.github.io GitHub Wiki

Windows server에서 Node.js 기반 API 서버 구동

이 문서에서는 Windows Server 환경에서 NodeJS 기반 API 서버를 nginx, pm2를 통해 구동하고, GitHub Actions을 활용하여 자동 배포하는 시스템을 구축하는 방법을 설명합니다.

목차

  1. 개요
  2. nginx 설정
  3. PM2로 프로세스 관리
  4. GitHub Actions Runner를 통한 자동 배포
  5. win-acme로 인증서 발급 및 관리

1. 개요

✅ 구성 요소

  • Windows Server (운영체제)
  • Node
  • nginx
    • 고성능・저메모리 웹서버 구축
    • 리버스 프록시 기능을 통해 보안 강화
  • PM2 (프로세스 관리 도구)
    • pm2로 node.js 프로세스를 관리
    • 자동 로드 밸런싱
    • 무중단 배포
  • win-acme
    • ssl 인증서 무료 발급 및 자동 갱신
  • GitHub Actions self-hosted runner
    • 자동 배포

✅ 필수 프로그램 설치

  • Node.js
  • Git
  • PM2
    • 프로젝트 루트 경로에서 npm install -g pm2 명령으로 설치
  • nginx

✅ 프로젝트 구조 예시

D:\프로젝트 루트\
├── dist\
├── src\
├── ecosystem.config.js  # pm2 관련 설정
├── package.json # nestJS 관련 설정
└── ...
D:\actions-runner\ # Github Actions
D:\배포 관련 설정\
├── deploy.ps1  # Github Actions에 의해 실행될 PowerShell 스크립트
└── ...
D:\pm2-resurrect.bat # pm2 resurrect 명령어

2. nginx 설정

  • 오픈소스 웹서버 애플리케이션
  • 경량 & 고성능 지향
  • HTTP 서버, 리버스 프록시, 로드밸런싱 등 기능

📋 설정 순서

  • 설치
  • nginx.conf 설정
  • 설정이 완료되면 nginx.exe를 실행(수정 후에는 반드시 nginx 종료 후 재실행)
  • nginx를 windows 서비스로 등록

✅ nginx.conf 설정

http {
  include       mime.types;
  default_type  application/octet-stream;
  
  # 로그 포맷 설정
  log_format custom '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "auth: " "$http_authorization"';

  access_log logs/access.log custom;
  sendfile        on;
  keepalive_timeout  65;

  # http(포트번호: 80) 요청은 https로 리다이렉션
  server {
      listen       80;
      server_name  도메인.com www.도메인.com;
      return 301 https://$host$request_uri

      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
          root   html;
      }
  }

  # https
  server {
      listen       443 ssl;
      server_name 도메인.com www.도메인.com;

      ssl_certificate      인증서/파일/경로/인증서.pem;
      ssl_certificate_key  인증서/파일/경로/키.pem;

      # www 없는 도메인을 www가 있는 도메인으로 리다이렉트
      if ($host = "도메인.com") {
        return 301 https://www.도메인.com$request_uri;
      }

      location /경로(예: api)/ {
          proxy_pass http://localhost:API서버_포트번호;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection 'upgrade';
          proxy_set_header Host $host;
          proxy_cache_bypass $http_upgrade;

          # CORS 헤더
          add_header 'Access-Control-Allow-Origin' '*' always;
          add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always;
          add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
      }

      location /api2/ {
          proxy_pass http://localhost:IIS_API서버_2_포트번호;
          proxy_http_version 1.1;

          proxy_set_header Host $proxy_host;   # 중요! proxy_pass의 호스트를 사용(IIS_API서버_2_포트번호)
          proxy_set_header X-Forwarded-For $remote_addr;
          proxy_set_header X-Forwarded-Proto https;

          # CORS 헤더
          add_header 'Access-Control-Allow-Origin' '*' always;
          add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always;
          add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
      }

      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
          root   html;
      }

      # 정적 파일 serve
      location / {
        root   ./관리자페이지_html_파일_등_경로;
        index index.html;
        try_files $uri $uri/ /index.html;
      }
  }
}

✅ nginx를 windows 서비스로 등록

  • 시스템 재부팅 시에도 별도 조치 없이 웹서버가 자동 실행되도록 NGINX를 windows 서비스로 등록.

  • NSSM(Non-Sucking Service Manager) 활용

  • 📋 설치 및 등록 방법

    • NSSM 다운로드 후 압축 해제
    • PowerShell 또는 CMD에서 nssm이 위치한 경로로 이동 후 다음 명령어 실행:
      nssm install nginx
    • GUI 창이 뜨면:
      • Application Path: nginx_설치_경로\nginx.exe
      • Startup directory: nginx_설치_경로
      • Service name: nginx
      • [Install service] 클릭 → 성공 메시지 확인
  • ✅ 서비스 등록 성공 여부 확인

    • services.msc를 실행해 목록에 nginx가 있는지 확인
    • 재부팅 후에도 자동으로 nginx가 실행됨

3. PM2로 프로세스 관리

  • 클러스터 모드를 활용하면 싱글 스레드 방식인 Node.js를 다수 CPU에서 동작하도록 할 수 있음
  • autorestart: 오류 발생 시 재시작
  • API 서버 코드 변경 후 서버 재시작이 필요할 때 무중단 배포가 가능
  • ecosystem.config.js 설정
    module.exports = {
      apps: [
        {
          name: '프로세스_이름',
          script: 'dist/main.js',
          instances: 0,
          exec_mode: 'cluster',
          autorestart: true,
          watch: false,
          env: {
            // (.env 관련 설정 등)
          },
        },
      ],
    };
    

✅ Windows 부팅 시 PM2 자동 실행 설정 (작업 스케줄러 이용)

작업 스케줄러를 사용해 PM2를 시스템 종료 이전 상태로 자동 복원 (Linux에서는 systemd 같은 init 시스템 사용)

  • ✅ 사전 준비

    • 먼저 애플리케이션을 pm2 start ecosystem.config.js 등으로 실행한 뒤, 다음 명령어로 현재 상태 저장:
      pm2 save
    • 배포 관련 스크립트에도 pm2 save 명령어를 추가
  • ✅ 스크립트 파일 만들기

    • 경로 예시: D:\pm2-resurrect.bat
    • ⚠️ 환경 변수 설정: Windows에서는 PM_HOME을 pm2가 설치된 경로로 설정해야 함(기본 경로는 \etc로, Linux용)
    • 오류 발생 시 echo 명령어 등으로 log 파일 저장해 문제의 원인을 확인
    • 스크립트 예:
      @echo off
      set PM2_HOME=C:\Users\Administrator\.pm2
      cd C:\Users\Administrator
      echo %DATE% %TIME% running pm2 resurrect >> pm2-resurrect.log
      call pm2 resurrect >> pm2-resurrect.log 2>&1
  • ✅ 작업 스케줄러에 등록

    1. 작업 스케줄러 (taskschd.msc) 실행
    2. 새 작업 만들기:
    • 이름 예: PM2 Auto Start
    • 트리거: 컴퓨터 시작 시(단, 지연 시간 30~60초 추천: Windows 환경에서는 하드웨어 성능에 따라 '즉시 실행' 설정 시 작업 스케줄러가 정상 동작하지 않을 가능성 있음.)
    • 동작:
      • 프로그램/스크립트: D:\pm2-resurrect.bat
      • 시작 위치: C:\Users\Administrator (pm2가 설치된 경로)
    • 일반 설정:
      • "사용자의 로그온 여부와 관계없이 실행"
      • "가장 높은 권한으로 실행" 체크
  • ✅ 성공 여부 확인

    • pm2 list 명령으로 서버 재부팅 후에도 프로세스가 유지되는지 확인

4. GitHub Actions Runner를 통한 자동 배포

  • GitHub Actions Runner를 통해 API 서버에 최신 코드를 자동 배포하는 시스템 구축
  • 반복적이고 비효율적인 수동 배포 작업을 없앰
  • git push, pull request 등이 트리거가 됨

✅ GitHub에서 runner 등록

  1. repository owner로서 로그인 > Settings > Actions > Runners > "New self-hosted runner"
  2. OS: Windows, Architecture: x64 선택
  3. 관리자 권한 powershell에서 가이드에 따라 아래 명령어 실행:
  • 단, 아래 스크립트는 2025.4.14. 기준. github에서 제공하는 가이드를 참고하세요(New Self-hosted runner버튼을 누르면 나타남)

    # 1. Create a folder under the drive root
    mkdir D:\actions-runner && cd D:\actions-runner
    # Download the latest runner package
    Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v2.323.0/actions-runner-win-x64-2.323.0.zip -OutFile actions-runner-win-x64-2.323.0.zip
    # Optional: Validate the hash
    if((Get-FileHash -Path actions-runner-win-x64-2.323.0.zip -Algorithm SHA256).Hash.ToUpper() -ne '해시 문자열'.ToUpper()){ throw 'Computed checksum did not match' }
    # Extract the installer
    Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD/actions-runner-win-x64-2.323.0.zip", "$PWD")
    
    # 2. 등록
    # Create the runner and start the configuration experience
    ./config.cmd --url https://github.com/your-org/your-repo --token <발급된_토큰>
    # !!!이후 등록 절차에 따라 windows 서비스로 등록할 때 반드시 Administrator 등 관리자 계정으로 등록할 것!!!
  1. 등록 여부 확인:
  • Github에서 Settings > Acrions > Runners
    • Runner 목록 확인
    • 추가한 Runner의 Status가 'Idle'이면 등록 성공

⚠️ 서비스 실행 계정 권한 주의(Windows 환경에서 매우 중요)

  • {디바이스 이름}\Administrator로 등록 시 "서비스로 로그온 허용" 권한 필요 (secpol.msc에서 설정)
    • 해당 계정이 "서비스로 로그온 허용" 정책에 포함되어 있어야 함
    • 설정 방법
      1. secpol.msc (로컬 보안 정책) 실행
      2. 로컬 정책 → 사용자 권한 할당 클릭
      3. 서비스로 로그온 항목 더블클릭
      4. {디바이스 이름}\Administrator가 목록에 없다면 추가
      5. powershell에서 net localgroup Administrators 입력해 계정이 로컬 관리자 그룹에 포함됐는지 확인
  • 또는 run.cmd 수동 실행 + 작업 스케줄러 사용 가능(비추천)

✅️ 배포 스크립트 작성 (deploy.ps1)

  • 경로 예: D:\deploy\deploy.ps1
    $projectPath = "D:\nodejs\your-api"
    
    Write-Host "✅ 자동 배포 시작"
    cd $projectPath
    
    git fetch origin
    git reset --hard origin/main
    
    npm ci
    npm run build
    
    pm2 restart ecosystem.config.js
    pm2 save
    
    Write-Host "🚀 배포 완료"

✅️ GitHub Actions Workflow 설정

  • 프로젝트_루트/.github/workflows/deploy.yml
  • 아래 workflow에는 배포 성공/실패 여부를 메일로 전송하는 작업이 포함되어 있음(-name: Send success email 이하)
    • 아래 코드를 사용하여 메일 전송 작업 추가 시 Github repository secrets 설정 필요:
      • Github Settings > Secrets and variables > Actions > Secrets 탭에서 New repository secret 버튼을 눌러 추가
        • e.g. SMTP_ADDRESSsmtp.gmail.com 할당
    name: Deploy to Windows Server
    
    on:
      push:
        branches:
          - main
    
    jobs:
      deploy:
        runs-on: self-hosted
    
        steps:
        - name: Run deploy script
          shell: powershell
          run: |
            powershell.exe -ExecutionPolicy Bypass -File "deploy_스크립트_파일_경로\deploy.ps1"
    
        - name: Send success email
          if: success()
          uses: dawidd6/action-send-mail@v3
          with:
            server_address: ${{ secrets.SMTP_ADDRESS }}
            server_port: ${{ secrets.SMTP_PORT }}
            secure: true
            username: ${{ secrets.SMTP_USER }}
            password: ${{ secrets.SMTP_PASS }}
            subject: "(서버 이름) API 서버 배포 성공"
            to: ${{ secrets.DEV_EMAILS }}
            from: GitHub Actions <${{ secrets.SMTP_USER }}>
            body: |
              ✅ 배포가 성공적으로 완료되었습니다.
              - 브랜치: ${{ github.ref_name }}
              - 커밋: ${{ github.event.head_commit.message }}
              - 작성자: ${{ github.event.head_commit.author.name }}
              - 시간: ${{ github.event.head_commit.timestamp }}
    
        - name: Send failure email
          if: failure()
          uses: dawidd6/action-send-mail@v3
          with:
            server_address: ${{ secrets.SMTP_ADDRESS }}
            server_port: ${{ secrets.SMTP_PORT }}
            secure: true
            username: ${{ secrets.SMTP_USER }}
            password: ${{ secrets.SMTP_PASS }}
            subject: "(서버 이름) API 서버 배포 실패"
            to: ${{ secrets.DEV_EMAILS }}
            from: GitHub Actions <${{ secrets.SMTP_USER }}>
            body: |
              ❌ 배포에 실패했습니다.
              - 브랜치: ${{ github.ref_name }}
              - 커밋: ${{ github.event.head_commit.message }}
              - 작성자: ${{ github.event.head_commit.author.name }}
              - 시간: ${{ github.event.head_commit.timestamp }}

✅️ 테스트

git add .
git commit -m "🚀 자동 배포 테스트"
git push origin main

✅ 확인 사항

  • GitHub Actions → Actions 탭 → ✅ succeeded
  • 서버에서 pm2 list로 Node.js 프로세스가 정상 동작하는지 확인
  • API 호출 결과 비교, 버전 번호 확인 등을 통해 새 코드가 반영됐는지 확인


이상으로 Windows Server 환경에서 Node.js 기반 API 서버 구축 및 자동 배포 시스템 구축 방법에 대한 설명을 마칩니다. 이 문서의 내용을 따라 설정하면 안정적이고 보안이 강화된 서버 환경을 구축할 수 있습니다.

⚠️ **GitHub.com Fallback** ⚠️