1. nginx 설치

sudo apt install nginx -y

nginx 실행

sudo systemctl start nginx
sudo systemctl enable nginx
  • sudo systemctl start nginx : systemctl을 사용하여 nginx서비스를 시작. systemctl은 시스템의 서비스나 데몬을 관리하는 도구.
  • sudo systemctl enable nginx : 이 명령어는 시스템 부팅 시 자동으로 Nginx가 시작되도록 설정

public ip로 접속하면 아래와같이 뜬다.


🥕 Backend 경로 /api/로 바꾸기

  • / : frontend로 라우팅
  • /api : backend로 라우팅
// 변경 전
app.use('/auth', authRouter);
app.use('/posts', postsRouter);
app.use('/users', usersRouter);

백엔드 서버의 경로를 /api로 설정

// 변경 후
app.use('/api/auth', authRouter);
app.use('/api/posts', postsRouter);
app.use('/api/users', usersRouter);

Nginx 설정을 하기 전에, 백엔드와 프론트엔드의 요청을 명확하게 구분하고 쉽게 라우팅하기 위해서는 서로 다른 경로를 설정해야 한다는 필요성을 느꼈다. 만약 동일한 경로(/)에서 프론트엔드와 백엔드를 함께 제공하면 요청을 구분하기가 어렵고 라우팅이 복잡해질 수 있기 때문이다. 따라서, 프론트엔드는 /, 백엔드는 /api와 같은 별도 경로를 지정해주기로 했다.


블루그린배포 동작방식에 대해서는 이해했는데, 이걸 구현하는건 도무지 어떻게 구현해야하는지 감이 안잡혀서 우선 포트숨기기 실습부터 해보기로 했다. (아래 링크 참고)

Nginx 리버스 프록시 설정으로 포트번호 숨기기


2. nginx 설정 파일 작성 - blue, green

/etc/nginx/sites-available/blue.conf

sudo vim blue.conf
upstream frontend {
        server 43.201.63.125:8000;
}

upstream backend {
        server 43.201.63.125:3000;
}

server {
    listen 80;

    location / {
        proxy_pass http://frontend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api/ {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

/etc/nginx/sites-available/green.conf

sudo vim green.conf
upstream frontend {
        server 43.201.63.125:8001;
}

upstream backend {
        server 43.201.63.125:3001;
}

server {
    listen 80;

    location / {
        proxy_pass http://frontend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api/ {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

8001, 3001… 포트 부분만 다르다.

3. deploy.sh 스크립트 작성

deploy.sh 스크립트 작성에 앞서, 프론트엔드 서버 환경변수를 설정해주자.

🥕 프론트엔드 서버 환경변수 설정하기

  • 기존 방법 : 프론트엔드(브라우저)에서는 .env 환경변수 사용이 불가능하기 때문에, /public/js/config.js 에 HOST, PORT, API_BASE_URL등 변수를 선언해놓고 export하여 사용하였음.
  • .env를 사용하면 포트를 바꿔서 실행해야하는 경우, PORT=3001 node app.js 이런식으로 실행하면 되지만, js파일을 사용하는 기존방법으로는 불가능했음. 그래서 .env의 환경변수를 바탕으로 js객체를 만들어 config.js에 저장하는 방식으로 진행하기로함.

/generate-config.js

import { promises as fs } from "fs";
import path from "path";
import { fileURLToPath } from "url";
import dotenv from "dotenv";

// 현재 파일의 디렉토리 경로 설정
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// .env 파일을 명시적으로 로드
dotenv.config({ path: path.join(__dirname, ".env") });

// 환경 변수를 객체로 저장
const resolvedConfig = {
    HOST: process.env.HOST,
    PORT: process.env.PORT,
    BE_PORT: process.env.BE_PORT,
    API_BASE_URL: `http://${process.env.HOST}:${process.env.BE_PORT}/api`,
    API_IMAGE_URL: `http://${process.env.HOST}:${process.env.BE_PORT}/uploads`,
    DefaultProfileImageUrl: process.env.DEFAULT_PROFILE_IMAGE_URL
};

// 저장할 경로 설정
const configPath = path.join(__dirname, "public/js/config.js");

// JavaScript 파일 내용 생성
const configJsContent = `export const config = ${JSON.stringify(resolvedConfig, null, 2)};`;

// 파일 생성 (덮어쓰기)
try {
  await fs.writeFile(configPath, configJsContent, "utf8");
  console.log(`✅ config.js 파일이 생성되었습니다: ${configPath}`);
} catch (error) {
  console.error("❌ config.js 생성 중 오류 발생:", error);
}

/.env

# 서버 호스트 설정
HOST=43.201.63.125

# 포트 설정
PORT=8000
BE_PORT=3000

# API URL 설정
API_BASE_URL=http://${HOST}:${BE_PORT}/api
API_IMAGE_URL=http://${HOST}:${BE_PORT}/uploads

# 기본 프로필 이미지 URL
DEFAULT_PROFILE_IMAGE_URL=/images/default-profile-image.png

package.json

  "scripts": {
    "prestart": "node generate-config.js",
    "start": "node app.js",

npm start 하면 node generate-config.js가 실행되고 아래와같이 config.js가 생성된다.

/public/js/config.js

export const config = {
  "HOST": "localhost",
  "PORT": "8000",
  "BE_PORT": "3000",
  "API_BASE_URL": "http://localhost:3000/api",
  "API_IMAGE_URL": "http://localhost:3000/uploads",
  "DefaultProfileImageUrl": "/images/default-profile-image.png"
};

deploy.sh 내용

  • sites-available/에는 nginx 설정파일이 저장되어있다. (blue.conf, green.conf)
  • sites-enabled/default : blue.conf 또는 green.conf의 심볼릭 링크를 sites-enabled/에 default라는 이름으로 생성한다.
  1. default파일을 통해 현재 활성화된 설정을 확인한다. (blue인지 green인지)
  2. 현재 활성화된 설정이 아무것도 없다면(default파일이 존재하지 않는경우), 기본값으로 blue를 설정한다. (blue.conf를 기본으로 심볼릭 링크를 설정)
  3. 만약 현재 설정이 blue 라면, 포트번호를 blue(8000,3000)로 프론트와 백엔드를 실행한다.
  4. 만약 현재 설정이 green 이라면, 포트번호를 blue(8001,3001)로 프론트와 백엔드를 실행한다.
  5. 새 버전에 맞게 심볼릭링크를 생성한다. (그린버전으로 전환할거라면, green.conf를 심볼릭링크로 생성)
  6. 기존 버전 프로세스를 종료한다. (이전버전이 블루였다면, 8000번과 3000번 포트를 죽임)

~/deploy.sh

#!/bin/bash

# 경로 설정
SITES_AVAILABLE="/etc/nginx/sites-available"
SITES_ENABLED="/etc/nginx/sites-enabled"

CURRENT_LINK="$SITES_ENABLED/default"

BLUE_CONFIG="$SITES_AVAILABLE/blue.conf"
GREEN_CONFIG="$SITES_AVAILABLE/green.conf"

BLUE_FRONTEND_PORT=8000
GREEN_FRONTEND_PORT=8001

BLUE_BACKEND_PORT=3000
GREEN_BACKEND_PORT=3001

echo "🔍 현재 활성화된 설정 확인..."
if [ -L "$CURRENT_LINK" ]; then
		# 심볼릭 링크가 이미 생성된 경우라면, 해당 심볼릭 링크가 blue인지, green인지 확인한다.
    CURRENT_TARGET=$(readlink -f "$CURRENT_LINK")
else
		# 심볼릭 링크가 생성되지 않았다면, blue.conf를 기본으로 심볼릭 링크를 생성한다.
    echo "❌ 심볼릭 링크가 설정되지 않았습니다. 기본값으로 Blue 설정을 사용합니다."
    sudo ln -s "$BLUE_CONFIG" "$CURRENT_LINK"
    sudo systemctl reload nginx
    exit 1
fi # bash의 if문을 닫는다.

if [ "$CURRENT_TARGET" == "$BLUE_CONFIG" ]; then
    echo "🔵 현재 Blue 버전이 실행 중입니다. Green으로 전환합니다..."
    NEW_TARGET=$GREEN_CONFIG
    NEW_FRONTEND_PORT=$GREEN_FRONTEND_PORT
    NEW_BACKEND_PORT=$GREEN_BACKEND_PORT
    OLD_FRONTEND_PORT=$BLUE_FRONTEND_PORT
    OLD_BACKEND_PORT=$BLUE_BACKEND_PORT
else
    echo "🟢 현재 Green 버전이 실행 중입니다. Blue로 전환합니다..."
    NEW_TARGET=$BLUE_CONFIG
    NEW_FRONTEND_PORT=$BLUE_FRONTEND_PORT
    NEW_BACKEND_PORT=$BLUE_BACKEND_PORT
    OLD_FRONTEND_PORT=$GREEN_FRONTEND_PORT
    OLD_BACKEND_PORT=$GREEN_BACKEND_PORT
fi

# 환경변수 로드
echo "BE 환경변수 로드 중..."
export $(grep -v '^#' ~/2-jenny-kang-community-be/.env | xargs)

# 백엔드 실행
echo "🚀 백엔드 서버(${NEW_BACKEND_PORT}) 시작..."
PORT=${NEW_BACKEND_PORT} nohup node ~/2-jenny-kang-community-be/app.js > ~/logs/backend_${NEW_BACKEND_PORT}.log 2>&1 &

# config.js 생성 후 프론트엔드 실행
echo "🚀 프론트엔드 서버(${NEW_FRONTEND_PORT}) 시작..."
PORT=${NEW_FRONTEND_PORT} BE_PORT=${NEW_BACKEND_PORT} node ~/2-jenny-kang-community-fe/generate-config.js 2>&1 && \
nohup node ~/2-jenny-kang-community-fe/app.js > ~/logs/frontend_${NEW_FRONTEND_PORT}.log 2>&1 &

# 심볼릭 링크 변경 (config.js 생성 이후)
echo "📝 Nginx 설정을 새 버전으로 전환 중..."
sudo ln -sf $NEW_TARGET $CURRENT_LINK
sudo systemctl reload nginx

# 기존 Blue 또는 Green 종료
echo "🛑 기존 버전 (프론트: ${OLD_FRONTEND_PORT}, 백엔드: ${OLD_BACKEND_PORT}) 종료..."
kill $(lsof -t -i:${OLD_FRONTEND_PORT}) 2>/dev/null
kill $(lsof -t -i:${OLD_BACKEND_PORT}) 2>/dev/null

echo "✅ 배포 완료! 현재 운영 환경: $(readlink -f $CURRENT_LINK)"

실행 권한 추가

chmod +x deploy.sh

4. 실행 결과

심볼릭링크가 설정되지 않은 상태에서 deploy.sh를 실행했을때는 기본으로 Blue(8000, 3000 포트)로 설정된다.

한번 더 deploy.sh를 실행하면 Green(8001, 3001 포트)으로 전환된다.

profile
일단 할 수 있는걸 하자.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN