React 서비스 아키텍처 이해: 단일 페이지 애플리케이션(SPA)의 구조
React는 단일 페이지 애플리케이션(SPA) 개발에 널리 사용되는 프론트엔드 라이브러리이다. 사용자의 요청에 따라 전체 페이지를 새로 고치지 않고도 필요한 부분만을 갱신하는 방식으로, 빠른 반응성과 부드러운 사용자 경험을 제공한다. 그러나 React 자체는 정적 파일로 컴파일되며, 실제 사용자에게 서비스를 제공하려면 별도의 웹 서버 혹은 리버스 프록시 설정이 필요하다.
엔진엑스(NGINX)의 역할: 정적 자산 제공과 리버스 프록시
엔진엑스는 경량의 고성능 웹 서버이자 리버스 프록시로, React로 빌드된 정적 파일(index.html, JS, CSS, 이미지 등)을 효율적으로 서비스할 수 있다. 또한 백엔드 서버(예: Node.js, Spring, 톰캣 등)와 통신할 수 있도록 프록시 역할도 수행한다.
정적 자산 제공 역할
React 프로젝트는 npm run build
를 통해 정적 HTML, JS, CSS 파일로 컴파일된다. 이 결과물들은 /build
폴더에 생성되며, 이 파일들을 엔진엑스가 /var/www/html
등으로 서빙하게 된다.
리버스 프록시 구성
엔진엑스는 /api
요청 등 프론트엔드에서 백엔드로 전송되는 요청을 다른 포트의 백엔드 서버(예: 8080 포트의 톰캣)로 전달하는 역할을 수행할 수 있다.
location /api {
proxy_pass http://localhost:8080;
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;
}
톰캣(Tomcat)의 기능: 백엔드 로직 수행
톰캣은 Java 기반의 웹 애플리케이션 서버로, JSP, Servlet, Spring 등과 같은 Java EE 기술 기반의 백엔드 처리를 담당한다. React가 사용자 인터페이스를 구성한다면, 톰캣은 로그인 처리, DB 조회, 파일 업로드 등의 서버 측 비즈니스 로직을 처리한다.
Spring Boot와 톰캣 내장
최근에는 Spring Boot를 사용하여 애플리케이션을 개발하고, 내장 톰캣을 활용해 별도의 WAS 설치 없이 바로 실행할 수 있다. 이 경우, 엔진엑스는 React 정적 자산을 처리하며 API 요청은 톰캣의 8080 포트로 전달된다.
React + 엔진엑스 + 톰캣 통합 구성 시나리오
시스템 구조 요약
[사용자]
↓
[엔진엑스 (80포트)]
├── 정적 자산 제공 (React 빌드 결과)
└── API 프록시 요청 → [톰캣 (8080포트)]
예시 구성 흐름
- 사용자가
http://mydomain.com
접속 - 엔진엑스가 React의
index.html
제공 - 사용자의
GET /api/user
요청 - 엔진엑스가
/api
요청을http://localhost:8080/api/user
로 프록시 - 톰캣이 요청 처리 후 JSON 반환
실제 환경 구성 예시: Ubuntu 기준
1. React 앱 빌드
npm run build
2. 엔진엑스 설치 및 설정
sudo apt update
sudo apt install nginx
/etc/nginx/sites-available/default
파일 수정:
server {
listen 80;
root /var/www/react-app/build;
index index.html;
location / {
try_files $uri /index.html;
}
location /api/ {
proxy_pass http://localhost:8080/;
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;
}
}
3. 톰캣 서버 실행
Spring Boot로 작성한 백엔드 앱을 실행:
java -jar my-app.jar
도커(Docker)를 활용한 배포 전략
Docker를 활용하면 React, 엔진엑스, 톰캣을 하나의 컨테이너 환경에서 분리 배포할 수 있어 유지보수가 용이하다.
1. React 이미지 구성
React 빌드 후, NGINX 기반 이미지 생성:
# Dockerfile.react
FROM node:18-alpine as build
WORKDIR /app
COPY . .
RUN npm install && npm run build
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
2. 톰캣 컨테이너 준비
Spring Boot JAR 파일을 톰캣 내장으로 실행하는 베이스 이미지 사용:
# Dockerfile.tomcat
FROM openjdk:17
COPY ./target/my-app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]
3. docker-compose.yml 구성
version: '3'
services:
frontend:
build:
context: .
dockerfile: Dockerfile.react
ports:
- "80:80"
backend:
build:
context: .
dockerfile: Dockerfile.tomcat
ports:
- "8080:8080"
문제 해결 팁과 주의사항
1. CORS 에러
개발 환경에서 React가 3000포트, 백엔드는 8080포트로 분리되어 있으면 브라우저가 CORS 에러를 발생시킨다. 이를 해결하려면:
- 백엔드(Spring)에서 CORS 설정 허용
- 프록시 서버 설정 (개발환경에서는 React
proxy
설정)
2. SPA 라우팅 문제
React에서 react-router
사용 시, 새로 고침 시 404 Not Found
가 발생할 수 있다. 이 경우 엔진엑스 설정에 다음을 추가:
location / {
try_files $uri /index.html;
}
확장 가능한 구성 방안
로드밸런서 적용
고객 수가 많아지면 트래픽을 분산시키기 위한 로드밸런서를 적용해야 한다. 이 경우 NGINX는 프론트엔드뿐 아니라 백엔드 API 서버에 대한 부하 분산도 수행할 수 있다.
CI/CD 파이프라인 연동
GitHub Actions, GitLab CI, Jenkins 등을 이용해 자동 빌드, 테스트, 배포 프로세스를 설정하면 코드 변경 시마다 자동으로 React 빌드 → Docker 이미지 생성 → 배포가 이루어지는 DevOps 환경을 구성할 수 있다.
결론
React는 빠른 인터페이스를 제공하고, 엔진엑스는 정적 자산 제공과 리버스 프록시 역할을 수행하며, 톰캣은 복잡한 비즈니스 로직을 처리하는 강력한 백엔드 서버로 기능한다. 이 세 가지의 조합은 강력하면서도 유지보수가 쉬운 아키텍처를 제공하며, 도커와 CI/CD까지 결합하면 더욱 견고하고 확장 가능한 시스템을 완성할 수 있다.
답글 남기기