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로 접속하면 아래와같이 뜬다.
/
: 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
와 같은 별도 경로를 지정해주기로 했다.
블루그린배포 동작방식에 대해서는 이해했는데, 이걸 구현하는건 도무지 어떻게 구현해야하는지 감이 안잡혀서 우선 포트숨기기 실습부터 해보기로 했다. (아래 링크 참고)
/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… 포트 부분만 다르다.
deploy.sh
스크립트 작성deploy.sh
스크립트 작성에 앞서, 프론트엔드 서버 환경변수를 설정해주자.
/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라는 이름으로 생성한다.~/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
심볼릭링크가 설정되지 않은 상태에서 deploy.sh
를 실행했을때는 기본으로 Blue(8000, 3000 포트)로 설정된다.
한번 더 deploy.sh
를 실행하면 Green(8001, 3001 포트)으로 전환된다.