V-logue

[Nginx] Nginx 무한 404 Error가 발생하는 문제 본문

Error

[Nginx] Nginx 무한 404 Error가 발생하는 문제

보그 2022. 7. 20. 21:29

AWS ELB와 Nginx로 HTTPS 서버 구축하는 도중 서버를 테스트 하는 과정에서

문제가 발생했다.

node app.js로 서버를 시작하고나서 별다른 동작이 없는데도 불구하고, 계속해서 GET / 404요청이 들어오는 것이다.

이 문제를 해결하기 위해서  server section의 server_name과,

location section의 proxy_pass값에 문제가 있다고 인식하고 값을 수정하기로 했다. 

(참고로 http Ip 주소는 실제 ip 주소말고 임의의 ip 주소를 넣었다.)

server {
    listen       80;
    server_name rendev.link;
    
// 단순히 nginx가 어떻게 http요청을 처리하는 지 알려주는 section

location / {
        proxy_pass http://123.31.65.435:3000;
    }
    ...
}

// 단순한 http request에서 수신대기중인 123.31.65.435:3000; 서버로 nginx가 
// 요청을 전달하도록 지시하는 section
// Case 1 (수정전 기본값)

server {
        listen 80;
        server_name  rendev.link;
        if ($http_x_forwarded_proto = 'http'){
        return 301 https://$host$request_uri;
        }
        location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://123.31.65.435:3000; // 임시로 붙여놓은 ip주소
        proxy_redirect off;
  }
}
}

server_name은 renDev. link

proxy_pass는 http://123.31.65.435:3000; // 임시로 붙여놓은 ip주소

실패

 // Case 2   
    
    server {
        listen 80;
        server_name  rendev.link;
        location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:3000;
        proxy_redirect off;
  }
}
}

server_name : renDev.link

proxy_pass http://127.0.0.1:3000

실패

// Case3

server {
        listen 80;
        server_name  rendev.link;
        location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://123.31.65.435:3000; // 임시로 붙여놓은 ip주소
        proxy_redirect off;
  }
}
}

server_name: rendev.link;

proxy_pass http://123.31.65.435:3000; // 임시로 붙여놓은 ip주소

실패

 // Case4 
 
 server {
        listen 80;
        server_name  ~.;
        location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:3000;
        proxy_redirect off;
  }
}

server_name ~.;

proxy_pass http://127.0.0.1:3000;

실패

// Case5

   server {
      listen       80;
      server_name  rendev.link;
      # redirect https setting
      if ($http_x_forwarded_proto != 'https') {
        return 301 https://$host$request_uri;
      }
      location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # port setting , 서버의 port와 동일한 port로 pass 시켜야 합니다.
        proxy_pass http://127.0.0.1:3000;
        proxy_redirect off;
  }
}

server_name : rendev.link;

proxy_pass http:127.0.0.1:3000;

redirect https setting추가

성공

 

 

// Basic setting

if ($http_x_forwarded_proto = 'http'){
        return 301 https://$host$request_uri;
        }
server_name : renDev. link
proxy_pass : http://123.31.65.435:3000; // 임시로 붙여놓은 ip주소

// Successful setting

if ($http_x_forwarded_proto != 'https') {
        return 301 https://$host$request_uri;
      }
server_name : rendev.link;
proxy_pass http:127.0.0.1:3000;

 

위 코드와 아래 코드가 달라진 것은, http일때와 https가 아닐때로 조건이 나뉘는데 사용한다면

!= https가 더 맞는 설정이라고 생각이 들었다.

 

 

reverse proxy는 외부에서 서버가 제공하는 서비스에 접근할 경우 proxy server를 통해서 접근하는 방식이다.

만약에 proxy server를 사용하게 된다면, 모든 통신이 proxy server를 통과하게 되는데

브라우저가 웹사이트와 연결된다면 다음과 같은 경로를 타게 된다.

			browser <-> proxy <-> internet <-> website

브라우저에서 proxy server로의 첫 번째 hop은 로컬에서 수행되기 때문에 proxy는 컴퓨터 내부에 연결을 수신하게 되고, 그곳에서 대기하게 된다. 컴퓨터 내부 연결인 로컬 연결에서는 예약된 IP주소인 127.0.0.1인 localhost를 사용하게 된다.

이런 방식으로 통신하는 것이 direct하게 메모리와 상호작용하는 것이기 때문에 매우 빠른 속도를 보장한다.

그렇기 때문에, nginx.conf파일의 proxy_pass 값이 127.0.0.1:3000(app.js의 서버 port번호)로 사용해야 하는게

맞는 방법이다.

홉(hop)은 컴퓨터 네트워크에서 출발지와 목적지 사이에 위치한 경로의 한 부분이다. 데이터 패킷은 브리지, 라우터, 게이트웨이를 거치면서 출발지에서 목적지로 경유한다. 패킷이 다음 네트워크 장비로 이동할 때마다 홉이 하나 발생한다.

 

proxy_pass가 127.0.0.1:3000과 server_name이 rendev.link가 맞는 상태라면 Case2번은 왜 계속해서

404에러가 발생했을까?

 

그것은 https로 redirect하는 코드가 없었기 때문이다.

일단 기본적으로 요청이 어떻게 들어오는 것은 별개로하고, 404에러가 발생한 것은

					location /

nginx의 location / 은 /로 들어오는 모든 코드를 proxy로 보낸다는 것을 의미하고 / 경로 하위 경로를

모두 포함하게 된다.

rendev.link로 들어오는 http:80 통신은 elb 로드밸런스 상으로 https:443으로 redirect하게 되있는데,

redirect하는 코드가 빠져있기 때문에 계속해서 404에러가 발생하지 않았을까 하는 추측이 든다.

 

+++

 

if ($http_x_forwarded_proto != 'https') {
        return 301 https://$host$request_uri;
      }

 

대부분의 서비스의 경우 API를 운용하는 백엔드 서버 앞에다 Proxy 서버를 두고 SSL에 관한 작업을 위임하게 되는데,

이를 SSL offloading이라고 한다.

Nginx로 proxy서버를 구성하는게 이런 SSL offloading의 작업이라고 할 수 있게 되는데,

https로 들어온 통신이 proxy서버를 거쳐 http통신으로 바뀌고 이를 통해 더 빠르게 통신할 수 있게 된다.

아마존 elb는 http 통신을 https로 리디렉션 시켜주는데,

Nginx가 SSL offloading을 수행하면서, http통신을 https로 리디렉션 시켜주지 않았기 때문에

발생한 오류였다. elb는 redirect 시켜주는데, nginx는 http로 내보내니 404에러가 발생했던 것

 

 

 

 

 

잘못된 내용이 있다면 지적해주시면 감사하겠습니다.

Comments