본문 바로가기

Infrastructure/Nginx

Nginx - forward proxy 로 활용하기

업무간 대부분의 프로젝트에서 nginx 를 reverse proxy 로 사용하고 있는데, forward proxy 서버를 구축해야 할 일이 생겨

nginx 를 사용했던 부분은 짧게 남겨보려 합니다.

 

- forward proxy ?

 

일반적으로 프록시란 두 호스트가 서로 통신을 할 때 직접 하지 않고 중간에 위치해 통신을 도와주는 역할을 하는 것을 지칭합니다.

보통 forward proxy, reverse proxy 이렇게 두 종류로 나뉘는데, 프록시 서버라고 부르는 경우는 대게 forward proxy 를 가리킵니다.

 

forward proxy 란 클라이언트가 서버로 무언가의 요청을 보낼 때 프록시 서버가 요청을 대신 받아서 서버로 요청을 전달해주고, 응답 또한 서버로부터 대신 받아서 클라이언트에 전달해주는 역할을 합니다.

이렇게 구성함으로써 클라이언트가 외부 사이트에 제한없이 접근하는 것을 막을 수 있고, 반대로 서버측에는 클라이언트의 정보를 숨길 수 있습니다. 또한 어느정도 캐싱 기능의 이점을 가질 수 있습니다.

 

- nginx 설치

 

nginx 를 사용해 forward proxy 를 구축하고, 요청을 보내 의도한대로 동작을 하는지 테스트해보도록 하겠습니다.

(AWS ec2 를 한 대 띄워 ubuntu 운영체제에서 진행했습니다)

 

먼저 ubuntu 에 nginx 을 설치해야 하는데, 원래는 apt 로 설치가 쉽게 가능하지만 어차피 파일을 일부 수정해 빌드를 별도로 진행해야 하므로 소스코드를 다운받는 형태로 설치를 진행합니다. (apt 로 설치했을 때 앞으로 진행할 과정이 제대로 되지 않아 우회한 것도 이유이긴 합니다..)

 

$ wget http://nginx.org/download/nginx-1.18.0.tar.gz
$ tar -xzvf nginx-1.18.0.tar.gz

 

nginx 는 1.18.0 버전을 사용했습니다. /home/ubuntu 위치에 tar.gz 파일을 다운받고 압축을 풀어 줍니다.

 

- ngx_http_proxy_connect_module 추가

 

이번에 진행하면서 뭔가 당연히 기본으로 제공하지 않을까.. 했는데 기본 nginx 만으론 forward proxy 기능을 제공하지 않습니다.

따라서 ngx_http_proxy_connect_module 이라는 별도의 모듈을 추가해줘야 합니다.

 

$ git clone https://github.com/chobits/ngx_http_proxy_connect_module.git

 

github 에 소스 코드가 올라가있고, clone 을 떠서 쉽게 받을 수 있습니다. 안에 뭐가 들었는지 한번 봐봅니다.

 

$ cd ngx_http_proxy_connect_module/patch
$ ls
proxy_connect.patch
proxy_connect_1014.patch
proxy_connect_rewrite.patch
proxy_connect_rewrite_1014.patch
proxy_connect_rewrite_1015.patch
proxy_connect_rewrite_101504.patch
proxy_connect_rewrite_1018.patch
proxy_connect_rewrite_102101.patch

 

위의 patch 파일들을 nginx 버전에 맞게 적용해줘야 합니다. 파일명을 보면 대충 알 수 있기도 하지만, github 의 README 에서 nginx 버전에 따라 어떠한 patch 파일을 사용해야 하는지 확인 가능합니다.

저는 1.18.0 버전을 사용할 것이라, 1018.patch 파일을 사용합니다.

 

$ cd nginx-1.18.0
$ patch -p1 < /home/ubuntu/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_1018.patch
$ ./configure --add-module=/home/ubuntu/ngx_http_proxy_connect_module
$ sudo make && sudo make install

 

처음에 받았던 nginx 디렉토리로 이동해 아래와 같은 명령어를 통해 patch 및 빌드를 실행합니다.

과정간에 zlib 와 같은 패키지가 없어서 실패할 수 있는데 필요한 패키지는 각 운영체제에 맞는 패키지 관리자를 통해 설치해서 진행하시면 됩니다. 여기까지 하면 ngx_http_proxy_connect_module 모듈 설정은 끝났고, 이제 proxy 설정이 필요합니다.

 

- nginx proxy 설정

 

저와 동일하게 과정을 진행했다면 /usr/local 경로에 nginx 가 설치되어 있을 것입니다.

해당 위치의 conf 안에 있는 nginx.conf 를 수정해줍니다.

 

server {
  listen  포트;
  server_name  서버 도메인 혹은 포트;
  
  resolver  8.8.8.8;
  
  proxy_connect;
  proxy_connect_allow  443 563;
  proxy_connect_connect_timeout  120s;
  proxy_connect_read_timeout     120s;
  proxy_connect_send_timeout     120s;
  
  
  location / {
    proxy_pass $scheme://$http_host$uri$is_args$args;
  }
  
  ...
}

 

server 부분에 위와 같은 세팅을 추가해주시면 됩니다. 저 같은 경우는 포트는 80을 넣고, server_name 에는 현재 세팅중인
nginx 가 떠있는 ec2 의 ip 를 넣어주었습니다.

 

$ cd /usr/local/nginx/sbin
$ sudo ./nginx

 

위 명령어로 지금까지 세팅한 nginx 를 실행합니다.

 

- 테스트

 

여기까지하면 nginx forward proxy 세팅은 끝났습니다. 이제 실제로 요청을 보내 의도한대로 동작하는지 테스트를 해봐야 합니다.

실시간으로 확인하기 위해 nginx 의 access log 를 열어둡니다.

 

$ tail -f /usr/local/nginx/logs/access.log

 

세팅하면서 access log 의 위치를 따로 건드리지 않았기 때문에, 기본으로 설정된 위의 경로에서 access log 에 접근할 수 있습니다.

 

테스트하기 위해 간단한 node.js 코드를 하나 작성해줍니다.

curl 로도 가능하지만, axios 모듈에서 proxy 를 확인해보고자 하는 의도도 있었습니다.

 

import axios from 'axios';

(async () => {
  try {
    const { data } = await axios({
      url: 'https://jsonplaceholder.typicode.com/photos',
      proxy: {
        protocol: 'http',
        host: 'ec2 host',
        port: 80,
      },
    });
    console.info(data);
  } catch (e) {
    console.error(e);
  }
})();

 

스크립트는 간단합니다. axios 에서도 proxy 는 간단하게 추가할 수 있도록 되어 있네요. proxy 의 host 부분에 아까 nginx 를 세팅했던 ip 혹은 도메인을 넣어주시면 되겠습니다. 위에 사용한 url 은 json data 를 떨궈주는 주소인데 실제로 저걸 사용할 건 아니지만, 테스트용으로 확인하기엔 충분합니다. 위 스크립트를 실행해보겠습니다.

 

// data
[
  ...
  ,
  {
    albumId: 2,
    id: 83,
    title: 'quia quasi enim voluptatem repellat sit sint',
    url: 'https://via.placeholder.com/600/a19891',
    thumbnailUrl: 'https://via.placeholder.com/150/a19891'
  },
  {
    albumId: 2,
    id: 84,
    title: 'aliquam dolorem ut modi ratione et assumenda impedit',
    url: 'https://via.placeholder.com/600/b5205d',
    thumbnailUrl: 'https://via.placeholder.com/150/b5205d'
  },
  ...
]

// nginx access log
172.31.15.7 - - [28/Jul/2022:17:17:49 +0000] "GET https://jsonplaceholder.typicode.com/photos HTTP/1.1" 200 1072894 "-" "axios/0.19.2"

 

스크립트 실행시 nginx access log 를 확인해보면 axios 를 사용해 호출했던 리퀘스트가 남는 것을 확인할 수 있고, 클라이언트에서 origin url 로부터 받아야되는 응답도 이상없음을 확인할 수 있습니다.

curl 을 사용한다면 curl  https://jsonplaceholder.typicode.com/photos -v -x [ec2 ip] 로 확인할 수 있습니다.

 

실제로 업무에선 위 과정 중 nginx 에 외부 모듈을 매번 빌드해주는건 꽤나 귀찮은 작업이기 때문에, 이미지를 하나 만들어서 쓰거나

이미 이런 모듈도 설치된 nginx 이미지가 있을 것 같아 이를 사용해 forward proxy 를 구성할 예정입니다.