Search
Duplicate

Apache Proxy + AWS CF + S3

사전 지식

Apache Proxy

아파치 웹 서버를 사용하여 Client 요청을 중개하는 기능
ProxyPass [path] [url] : Client가 [path]로 요청을 한 경우에만 [url]로 요청을 보냅니다.
ProxyPassReverse [path] [url] : 백엔드[path]의 응답을 프록시 서버/[url]로 변환합니다.

AWS CloudFront

전세계에 Edge Server를 두고 Client에 가장 가까운 서버를 찾아 지연을 최소화하는 Content Delivery Server(CDN)으로 역할은 아래와 같습니다.
캐싱 및 최적화 : 자체 캐싱
보안 및 인증 : 요청 포워딩을 통해 사용자 제어
라우팅 : 요청 포워딩을 사용하여 클라이언트 요청을 원본 서버로 라우팅
요청 포워딩
클라이언트가 Cloudfront에게 요청한 원본 컨텐츠를 어떻게 전달할지 제어하는 메커니즘

S3

AWS에서 제공하는 스토리지로 데이터를 저장하고, 관리하는 클라우드 스토리지 솔루션입니다.

환경 이해하기

1.
기존 서버에 추가적인 페이지를 신규 서버로 구축
2.
URL은 ServiceURL/cms로 결정
3.
Apache Proxy, AWS Cloud Front, AWS S3 사용
아래에선 Sequence Diagram으로 설명을 합니다. 단 Return되어 오는 값의 경로는 생략해서 나타냈습니다.

Apache Proxy

기존에도 아파치의 경우 path에 따른 라우팅 처리가 있는 상태였습니다.
<VirtualHost *:80> ProxyRequests Off ProxyPreserveHost On ProxyPass /file/ http://file_service.com/file/ ttl=60 disablereuse=on ProxyPassReverse /file/ http://file_service.com/file/ ProxyPass / http://exist_service.com/ ttl=60 disablereuse=on ProxyPassReverse / http://exist_service.com/ </VirtualHost>
Plain Text
복사
apache httpd.conf
필요한 서버로 라우팅해주는 코드들이 있어 신규 서버분기 처리를 DevOps팀에서 설정해준 상태였습니다.
<VirtualHost *:80> ProxyRequests Off ProxyPreserveHost On ProxyPass /file/ http://file_service.com/file/ ttl=60 disablereuse=on ProxyPassReverse /file/ http://file_service.com/file/ ProxyPass /cms/ http://cloudfront.net ttl=60 disablereuse=on ProxyPassReverse /cms/ http://cloudfront.net ProxyPass / http://exist_service.com/ ttl=60 disablereuse=on ProxyPassReverse / http://exist_service.com/ </VirtualHost>
Plain Text
복사
apache httpd.conf

AWS Cloud Front

1.
들어온 요청들 중 특정 요청들을 S3 파일에 매핑해줍니다
sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> A: service.com/cms/
  A ->> CF: cloudfront.net
  CF ->> S3: S3/index.html
  S3 -->> C: index.html
Mermaid
복사
2.
만약 등록되지 않은 요청의 경우, S3에서 해당 동일한 경로를 탐색합니다.
sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> A: service.com/cms/assets/index.css
  A ->> CF: cloudfront.net/assets/index.css
  CF ->> S3: S3/assets/index.css
  S3 -->> C: index.css
Mermaid
복사
3.
일치하는 경로가 없는 이외의 요청(ex. SPA Router에 등록한 URL)은 Error를 띄우고, 이를 특정 파일로 요청을 보냅니다.
ServiceUrl/cms/list → S3/cms/list → 403, 404 →
sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> A: service.com/cms/list
  A ->> CF: cloudfront.net/list
  CF ->> S3: S3/list
  S3 -->> CF: [404]
	CF ->> S3: S3/index.html
	S3 -->> C: index.html
	C ->> C: /cms/list
Mermaid
복사

AWS S3

Vite의 기본 설정으론 아래와 같이 빌드됩니다.
S3
index.html
assets
index.js
index.css

경로 맞추기

Apache Proxy → … → S3 경로 맞추기

문제

index.html은 정상적으로 호출하는 하지만, .js .css파일을 제대로 못 불러오는 문제가 발생했습니다.
원인은 아무 설정 없이 빌드 시 html에서 assets로 매핑되기 때문에 엉뚱한 곳으로 proxy되기 때문이 였습니다.
<head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>title</title> <script type="module" crossorigin src="/assets/index-039d9ea0.js"></script> <script type="module" crossorigin src="/assets/index-0g459wc1.css"></script> </head>
JavaScript
복사
dist/index.html
위와 같이 호출하게 될 시 아래와 같은 경로로 호출됩니다.
sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant ES as Exist Service

  C ->> A: service.com/assets/index.js
  A ->> ES: service.com/assets/index.js
  ES -->> C: 404.html
Mermaid
복사

해결

vite.config.js에서 base옵션을 통해 /cms/가 접두에 붙도록 설정했습니다.
export default defineConfig({ plugins: [react()], ... }, base: '/cms/' });
JavaScript
복사
vite.config.js
설정을 이렇게 변경해주니 ServiceURL에서 정상적으로 호출이 되었습니다.
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>title</title> <script type="module" crossorigin src="/cms/assets/index-039d9ea0.js"></script> <script type="module" crossorigin src="/cms/assets/index-0g459wc1.css"></script> </head>
JavaScript
복사
index.html
위와 같이 호출하게 될 시 아래와 같은 경로로 호출되어 문제가 해결됩니다.
sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> A: service.com/cms/assets/index.js
  A ->> CF: cloudfront.net/assets/index.js
  CF ->> S3: S3/assets/index.js
	S3 -->> C: index.js
Mermaid
복사

AWS Cloud Front → … → S3 경로 맞추기

문제

하지만 cloudfront의 DNS를 통해서 접속했을 때 index.html에서 파일을 호출할 때 문제가 발생했습니다.
index.html의 경우 cloudfront.net/cms로 호출해도 에러 처리를 통해서 index.html로 redirect되었지만, assets/index.js 호출 또한 에러 처리로 index.html이 리턴되어 의도치 않은 결과가 나왔습니다.
sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

	C ->> CF: cloudfront.net/cms/assets/index.js
	CF ->> S3: cloudfront.net/cms/assets/index.js
	S3 -->> CF: [404]
  CF ->> S3: S3/index.html
	S3 -->> C: index.html
Mermaid
복사

해결

1.
service.com/cms의 경로를 cloudfront.net/cms로 변환되도록 https.conf를 변경해주었습니다.
ProxyPass /cms/ http://cloudfront.net ttl=60 disablereuse=on > ProxyPass /cms/ http://cloudfront.net/cms ttl=60 disablereuse=on ProxyPassReverse /cms/ http://cloudfront.net > ProxyPassReverse /cms/ http://cloudfront.net/cms
Plain Text
복사
apache httpd.conf
2.
vite.config.js의 base: /cms/를 제거 후 build 파일의 이름을 assets에서 cms로 변경해주었습니다.
export default defineConfig({ ... base: '/cms/' > build: { assetsDir: 'cms', }, });
JavaScript
복사
vite.config.js
해당 옵션을 통해 아래와 같이 빌드파일 이름이 바뀌게 됩니다.
S3
index.html
cms
index.js
index.css

작업 결과 플로우

S3 구조

S3
index.html
cms
index.js
index.css

dist/index.html

<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>title</title> <script type="module" crossorigin src="/cms/index-039d9ea0.js"></script> <script type="module" crossorigin src="/cms/index-0g459wc1.css"></script> </head>
JavaScript
복사
index.html

service.com/cms/list 페이지 진입

sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> A: service.com/cms/list
  A ->> CF: cloudfront.net/cms/list
  CF ->> S3: S3/cms/list
  S3 -->> CF: [404]
  CF ->> S3: S3/index.html
	S3 -->> C: index.html
	C ->> C: /cms/list
Mermaid
복사

service.com/cms/index.js 호출

sequenceDiagram
  participant C as Client
  participant A as Apache Proxy
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> A: service.com/cms/index.js
  A ->> CF: cloudfront.net/cms/index.js
  CF ->> S3: S3/cms/index.js
	S3 -->> C: index.js
Mermaid
복사

cloudfront.net 페이지 진입

sequenceDiagram
  participant C as Client
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> CF: cloudfront.net
  CF ->> S3: S3
	S3 -->> C: index.html
Mermaid
복사

cloudfront.net/cms/list 페이지 진입

sequenceDiagram
  participant C as Client
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> CF: cloudfront.net/cms/list
  CF ->> S3: S3/cms/list
  S3 -->> CF: [404]
  CF ->> S3: S3/index.html
	S3 -->> C: index.html
	C ->> C: /cms/list
Mermaid
복사

cloudfront.net/cms/index.js 호출

sequenceDiagram
  participant C as Client
  participant CF as AWS CloudFront
  participant S3 as AWS S3

  C ->> CF: cloudfront.net/cms/index.js
  CF ->> S3: S3/cms/index.js
	S3 -->> C: index.js
Mermaid
복사