[백엔드] 앞단에 Nginx 적용하기 공부/BE, DB

Date 2021. 8. 30. 18:13

이번에 프로젝트를 진행하면서 웹서버로 Nginx를 사용하였다. 총 두가지 목적으로 사용했는데

1. 정적 파일 응답 ( nginx에서 요청 처리)

2. 리버스 프록시 ( 뒷단의 nestjs 서버로 전달)

로 사용하였다.

 

여기서 리버스 프록시로 Nginx를 사용할 때 고려할 점을 알아보도록 하겠다.

기본 설정

Nestjs에서는 HTTP 요청을 기본적으로 Express 를 사용해서 처리하기 때문에 간단하게 Express 를 이용했다.

또한 앱을 띄우기 위해서 간단하게 docker-compose 를 이용했다.

 

다음은 간단한 Nginx configuration이다.

80포트로 들어오는 요청들을 모두 http://backend:3000 으로 전달한다.

 

upstream server {
    server backend:3000;
  }

  server {
    listen 80;

    location / {
        proxy_pass http://server;
        proxy_redirect off;
    }
  }

 

다음으로는 Express 서버 코드다.

 

const express = require('express');
const app = express();
const port = process.env.PORT;

app.get('/', (req, res) => {
  var json = {
      host: req.hostname,
      ip: req.ips,
      header: req.rawHeaders,
      body: req.body,
      cookies: req.cookies,
  };
  res.send(json);
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

 

간단하게 요청이 들어오면 Request 를 적절히 파싱하여 응답한다.

서버와 Nginx를 docker-compose 를 이용해 배포한다.

 

services:
  backend:
    container_name: backend
    image: expressdghg:1.0
    environment: 
      - PORT=3000
  nginx:
    container_name: nginx 
    image: nginx
    ports:
      - 80:80
    volumes:
      - ./nginxconf:/etc/nginx/conf.d

 

이제 localhost:80로 HTTP 요청을 보낼 시 Nginx > Express 순으로 전달되고 응답하게 될 것이다.

응답

요청을 보내면 다음과 같이 응답한다.

 

{
host: "server",
ip: [ ],
header: [
"Host",
"server",
....

 

보다시피 hostip 가 제대로 설정되어있지 않다. 이는 요청을 Nginx 에서 보냈기 떄문이다.

이것을 해결하기 위해서는 두가지 설정이 필요하다.

해결방법

1. Express

 

우선 Express의 설정을 변경해야 한다. 문서에서는 다음과 같이 설명하고 있다.


When running an Express app behind a reverse proxy, some of the Express APIs may return different values than expected. In order to adjust for this, the trust proxy application setting may be used to expose information provided by the reverse proxy in the Express APIs. The most common issue is express APIs that expose the client’s IP address may instead show an internal IP address of the reverse proxy.

 

trust proxy가 설정되어야 한다. 이는 다음과 같이 설정할 수 있다.

 

app.set('trust proxy', true);

 

이렇게 설정하면 Express는 내부적으로 다음과 같이 동작한다. ( 4.17.1 기준 )

  1. app.set('trust proxy fn') 으로 변경한다. 왜인지는 모르겠다.
  2. Request 객체에 접근할 때 proxy 와 관련된 값들을 반환할 때 이 app의 trust proxy fn 값을 참고해 반환한다.

 

 

2. Nginx

 

Express에서 trust proxy 설정을 해두었다면 Express는 헤더 참고 시 기존 헤더가 아닌(RFC에 정의된 general 헤더) 특별한 헤더들을 참고한다.

  • 사실상 표준(de-facto) 헤더들로 X-Forwarded-* 헤더들이다.

nginx config을 다음과 같이 변경한다.

 

  server {
    listen 80;
    location / {
        proxy_pass http://server;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_redirect off;
    }
  }

이 설정들로 앱을 다시 구동하면 정상적으로 값들이 출력된다.

 

 

결론

 

사실 이 글을 쓰게 된 계기는 Nestjs에서 Secure 설정으로 쿠키를 이용하고 있었는데, Nginx에서 SSL 종료 후 넘기기 때문에 정상적으로 적용이 안되었었다..! 해서 찾아보니 X-Forwared-Proto 를 이용해 프로토콜을 설정해줘야 한다고 해서 찾아보았다.

 

즉 Express등 앱을 직접 노출하지 않고 Nginx등 리버스 프록시를 사용하는 경우 앱에서 Host나 Client IP에 접근하기 위해서는 적절한 처리가 필요하다.

Recent Posts

Popular posts

Recent Comments

Tag List

JavaScript 도커 ORM GCP JWT 인증 클라우드 TypeScript 네임스페이스 파이썬 운영체제 백준 k8s API DNS 테라폼 DB 알고리즘 IAC 네트워크 AWS 인가 컨테이너 리눅스
Total : Today : Yesterday :
Blog powered by Tistory, Designed by hanarotg