본문 바로가기
Today I Learned 2024. 8. 5.

(24.08.05)[17주차] Nginx 404 Not Found 오류 고찰과 해결

도메인을 입력 시 보여지는 랜딩 페이지

 

정상적으로 Java SpringBoot 기반의 BE 프로젝트와 React를 활용한 FE 가 CI/CD를 통해서 컨테이너 형식으로 웹 서버 인스턴스에서 최신화되면서 배포 파이프 라인이 일단은 완료가 되었었다.

 

publicclassdev.com 도메인을 구입하여, 영역을 지정해 해당 웹서버 인스턴스로 접근할 수 있도록 설정을 했다.

 

 

 

  하지만, 브라우저에서 도메인으로 진입 후, 새로고침을 하거나, 특정 주소에 직접적으로 접속을 하는 경우(ex. 브라우저 주소창에 publicclassdev.com/board/2 처럼 Path를 전부 지정해서 한번에 요청) 에 위와같은 nginx단에서 404 Not Found 에러가 발생했다.

 

이에 대해 고찰해보고 해결까지를 정리하면서 주의할 점을 다시 한번 상기 하도록 한다.


오류발생 : 기존 CD 배포 파이프라인 상황

초기 파이프라인 설계

 

 이러한 파이프 라인상에서 Nginx 컨테이너에 직접적으로 네트워크 설정인 nginx.conf 파일의 내용을 수정을 하고자 하면서 404 에러를 고치고자 했다.

 

인스턴스 내 모든 컨테이너는 같은 브릿지 네트워크로 연결된 상태임에도 작동이 안되고 있었다.

 

conf 설정 : FAIL

events {}

http {
    server {
        listen 80;
        server_name publicclassdev.com www.publicclassdev.com;
...     
     location / {
            try_files $uri $uri/ /index.html;
        }
...

 

  관련한 FE 및 배포에 관련해서 지식이 없었기 때문에 거의 3일이상을 찾아보면서 nginx.conf 파일의 설정에 대해서 학습하면서 알아보면서 점검

 

  • try_files 문으로 React에 파일이 없을 경우 이미지가 빌드가 될 때 생성된 index.html 을 참고하라는 conf 문을 입력
    • 그럼에도 404 오류가 발생했기 때문에, 이는 참고해야할 index.html이 없거나 문제가 있다고 판단
  • 기타 관련 설정들을 추가해도 똑같은 문제 발생

 

React container 의 /usr/share/nginx/html 와 일치 시키는 작업 : FAIL

# React 컨테이너에서 해당 경로를(내부 파일까지) 복사해서 /tmp 지정
docker cp publicclassdev-front:/usr/share/nginx/html /tmp/html

# 임시 경로 /tmp 복사한 내용을 nginx container 경로에 붙여넣기
docker cp /tmp/html nginx-container:/usr/share/nginx/

# 임시 경로의 파일 삭제
rm -rf /tmp/html
  •   인스턴스 SSH 로 직접 React Container에서 참고해야하는 index.html과 static 요소들(파일들) 을 전부 복사해서 nginx container 안의 경로에 붙여넣어 참고할 수 있게 시도
    • 404 오류는 발생하고 있지는 않지만, 오히려 index.html 에 지정되어있는 CSS 및 JS 요소들을 React 쪽으로 참조를 하고 있지 못한 상태

이 상황에서 2~3일 밤을 새가면서 찾아보면서 했지만, 모든 해결 방법들이 적용이 되지 않은 상태였다가, 깃헙액션의 처음부터 점검을 해보자라는 마인드로 전체 점검을 한 후, Dockerfile에서 그 문제의 원인을 알아 낼 수 있었다.

 

React Image를 위한 Dockerfile 점검 : SUCCESS

# Stage 1: Build
FROM node:18 AS build

# 작업 디렉토리 설정
WORKDIR /app

# 종속성 파일 복사
COPY package.json package-lock.json ./

# 종속성 설치
RUN npm install

# 애플리케이션 소스 복사
COPY . .

# 애플리케이션 빌드
RUN npm run build

# Stage 2: Production Image
FROM nginx:latest

# Nginx 설정 파일을 Docker 이미지에 포함
COPY nginx.conf /etc/nginx/nginx.conf

# 빌드 단계에서 생성된 파일을 Nginx로 복사
COPY --from=build /app/build /usr/share/nginx/html

# Nginx 포트 공개
EXPOSE 80

# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]

 

 위는 React 단의 Image를 만들어 낼 수 있는 Dockerfile

  • Stage 2 부분에서 nginx.conf 를 통해서 Nginx를 빌드하는 단계를 발견
    • 즉, 이미 React Container안에서는 서로를 참조할 수 있는 Nginx가 이미 존재를 하고 있었던 것

중복된 nginx 가 존재하는 초기 파이프라인의 작동 구성

위처럼 80 포트로 외부에서 요청이 들어오게 될 때, nginx가 두개를 거쳐서 react로 들어가기 때문에 nginx 2개와 React의 빌드 파일이 조금이라도 통일되지 않거나, conf가 문법이 꼬일 경우,

  • React의 어떠한 파일로도 참조할 수 없음
  • 서로 다른 conf 로 참조해야할 파일이 있어도 다른 index.html에서 참조

등 서로가 서로를 참조를 하지 못하는 상황이 발생했던 것

 

파이프라인 재구성으로 해결

새로 작성된 파이프라인

  • 새로 만든 Nginx Container를 삭제
  • React Container의 외부 노출 포트를 80 포트 = 인스턴스로 요청이 들어오는 포트로 설정
    • 어차피 React Container안의 Nginx도 80:80 으로 받고 있기 때문에 정상적으로 작동이 됨
# 적용된 nginx.conf
user  nginx;
worker_processes  auto;

...

http {
...

    server {
        listen 80;
        server_name publicclassdev.com www.publicclassdev.com;

        root /usr/share/nginx/html;
        index index.html;

        # React 애플리케이션 요청 처리
        location / {
            try_files $uri $uri/ /index.html;
        }

        # Spring Boot API 요청 프록시
        location /api/ {
            proxy_pass http://publicclassdev:8080;  # Spring Boot 컨테이너 이름을 확인하여 수정
            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;
            proxy_redirect off;
..
  • 이미 존재하는 React Container안의 위의 정상적으로 index.html을 참조할 수 있도록 nginx.conf 에 적용

# React Dockerfile에서 Nginx 설정 파일을 Docker 이미지에 포함하는 스텝
COPY nginx.conf /etc/nginx/nginx.conf

 

  • 해당파일은 Dockerfile이 참조할 수 있도록 같은 경로에 저장을 해서 nginx.conf를 React 빌드할 때 포함시킬 수 있도했음

결국 일주일 내내 nginx와 React 컨테이너를 분리한다는 독립된 환경을 구축하려는 욕심으로 인해서, Dockerfile도 확인을 안하는 실수를 했던 것.

 

어차피 Nginx는 React와 서로를 참조해야지만 작동되는 웹어플리케이션이기 때문에 FE BE 를 분리한다는 명목하에 굳이 나눌 필요도 없는 nginx를 React와 분리시킨다는 이상한 Ideation에서 구상을 진행한 것이라고 생각한다.

 

앞으로 이러한 FE BE 분리 한 환경을 인스턴스 내에 Docker Container로 구축을 하고자 할 때 위에 같은 패턴을 가지고 구성을 하는 것도 참조해야할 필요가 있다고 생각한다.