React + Spring을 Apache Reverse Proxy로 한 도메인에서 서비스하기

2025. 12. 15. 14:27카테고리 없음

프론트엔드(React)와 백엔드(Spring)를
하나의 도메인으로 자연스럽게 묶는 실무 구성 정리


왜 이 구조를 쓰는가?

실무에서 가장 많이 쓰는 구조는 아래와 같다.

  • 화면: React (정적 파일)
  • API: Spring Boot (WAS)
  • 앞단: Apache (웹서버)

이렇게 나누는 이유는 명확하다.

  • 화면은 빠르게 정적 서빙
  • API는 WAS에 위임
  • 외부 노출은 Apache 한 곳에서만 관리

전체 아키텍처 한 눈에 보기

[ Browser ]
     ↓ https://www.example.com
[ Apache : 443 ]
     ├─ /            → React build (DocumentRoot)
     └─ /api/**      → Spring Boot (Reverse Proxy)

중요
브라우저는 Apache만 바라보고,
Spring WAS의 포트는 외부에 노출되지 않는다.


Apache 기본 설정 예시

<VirtualHost *:443>
    ServerName www.example.com

    DocumentRoot /var/www/react/build

    <Directory /var/www/react/build>
        Require all granted
        Options -Indexes
        AllowOverride None
    </Directory>

    <Location /api>
        ProxyPass http://localhost:8080/api
        ProxyPassReverse http://localhost:8080/api
    </Location>
</VirtualHost>

이 설정 하나로 역할이 완전히 분리된다.


React 화면은 어떻게 제공되는가

1️⃣ React는 이미 빌드된 상태

npm run build
  • index.html
  • static/js/*.js
  • static/css/*.css

이 파일들이 DocumentRoot 아래에 존재한다.


2️⃣ 사용자가 /로 접근하면

https://www.example.com/

Apache는 이렇게 처리한다.

/var/www/react/build/index.html 반환

→ React 앱 실행


/api 요청은 어떻게 처리되는가

React 코드에서 보통 이렇게 요청한다.

fetch('/api/users');

요청 흐름

Browser
 → https://www.example.com/api/users
 → Apache
 → Location /api 매칭
 → localhost:8080/api/users
 → Spring Controller

React는 포트도, 서버 주소도 모른다.


왜 React에서 포트를 안 적어도 되나?

fetch('/api/users');

이 코드의 의미는 단순하다.

현재 페이지의 도메인 + 프로토콜을 그대로 사용

  • 페이지가 HTTPS → 443
  • 페이지가 HTTP → 80

포트는 브라우저가 자동 결정한다.


CORS 문제가 발생하지 않는 이유

이 구조의 가장 큰 장점 중 하나다.

브라우저 기준

화면 요청: https://www.example.com
API 요청 : https://www.example.com/api
  • 도메인 동일
  • 프로토콜 동일
  • 포트 동일

👉 Same-Origin → CORS 발생 안 함


운영 환경에서 이 구조가 좋은 이유

✅ 보안

  • WAS 포트(8080) 외부 차단
  • SSL 인증서 Apache에서만 관리

✅ 배포

  • React: 파일 교체만으로 배포
  • Spring: 독립 재기동 가능

✅ 확장

  • API 서버 증설 시 Apache에서 로드밸런싱 가능

자주 하는 실수

❌ React에서 API 주소를 이렇게 쓰는 경우

fetch('http://localhost:8080/api/users');
  • 운영 환경에서 즉시 문제 발생
  • CORS, 보안, 환경 분리 모두 깨짐

✅ 올바른 방식

fetch('/api/users');

한 줄 요약

Apache는 화면과 API의 관문이고,
React는 정적 파일,
Spring은 /api 요청만 처리한다.


다음 편 예고

  • 왜 굳이 Apache 앞단이 필요한가?
  • Nginx vs Apache 선택 기준
  • 실무에서 자주 쓰는 Reverse Proxy 패턴