4주 프로젝트-dev log #16

Joshua Song / 송성현·2020년 2월 27일
1

im_16 프로젝트

목록 보기
20/21

Introduction

서버를 EC2에 배포하고 나서 프록시 설정을 해주기로 했다. 보안 상, 그리고 DB에 연결하는 서버를 지키기 위해서 리버스 프록시를 사용하기로 하고 또 nginx를 사용해 적용하기로 했다.

Proxy

  • 먼저 프록시 서버란 클라이언트에서 인터넷 정보를 요청 했을 시 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다. 서버와 클라이언트 사이에 다리로 통신을 수행하는 부분을 프록시라고 하고 그 기능을 하는 것을 프로시 서버라고 한다. 프록시 서버의 사용 목적은 다양한데 크게 포워드 프록시, 리버스 프록시로 나누어 사용한다. 각 프록시의 장점이 다르니 알맞게 사용하면 된다.

Forward Proxy

  • 먼저 포워드 프록시는 클라이언트에서 프록시 서버를 거쳐서 인터넷에 연결되는 방식인데 프록시서버가 요청을 보내고 결과를 받으면 그 결과를 클라이언트에 전달 (forward) 해준다. 프록시 서버에서는 크게 두가지 장점이 있다.
  1. 보안: 프록시 서버에서 요청들과 넘어가는 결과에 대한 보안 정책을 적용할 수 있다.
  2. 성능: 프록스 서버는 내부에 cache를 유지하여 자주 사용하는 정보라면 요청을 보내지 않고 cache에서 가져올 수 있어 성능 향상을 가져올 수 있고 웹 사용 환경도 직접 설정이 가능해 기업에서 자주 사용한다. 외부와의 트래픽을 줄일수도 있어 네트워크 병목 현상(traffic jam?으로 인한 성능 저하 - bottleneck)을 방지하는 효과도 있다.

Reverse Proxy

  • 클라이언트가 인터넷에 요청을 보내면 리버스 프록시는 이 요청을 받아 내부 서버에서 데이터를 받은 후 이 데이터를 클라이언트에 전달한다. 내부 서버가 직접적으로 이러한 서비스를 제공한다면 보안 문제가 있기 때문에 실제 서비스 서버를 내부망에 위치시키고 프락스 서버만 내부에 있는 서비스 서버와 교신해 결과를 클라이언트에 제공한다.
  1. 보안: 외부 사용자는 내부 서버의 존재를 모르기 때문에 내부 서버의 정보를 외부로부터 숨길 수 있고 DB에 접근하는 서버로의 직접적인 접근을 막는다.
  2. 로드밸런싱: Proxy 서버가 내부 서버의 정보를 알고 있어 load balancing을 통해 요청을 조절할 수 있다.

Nginx

이번 서버에는 nginx를 사용해 리버스 프록시를 적용하기로 했다. 그렇다면 nginx가 뭔지 어느정도 알아보고 시작해야 할 것 같다.

개념

  • nginx는 트래픽이 많은 웹사이트를 위해 확장성을 목적으로 설계한 비동기 이벤트 기반구조의 오픈 소스 소프트웨어로 최상의 성능과 안정성을 제공한다고 공식 사이트에 나온다. HTTP 서버 기능과 이메일(IMAP, POP3, SMTP)을 위한 프록시 서버, 그리고 HTTP, TCP 와 UDP 서버를 위한 리버스 프록시와 로드 밸런서 역할도 한다. 러시아 프로그래머 이고르 시쇼브(Igor Sysoev)가 대규모의 동시다발적 연결(10,000개가량)을 웹 서버가 처리하는데 겪는 어려움을 지칭하는 C10K 문제를 해결하기 위해 만든 소프트 웨어로 현재 가장 빠른 웹 서버라고 홍보한다. 비동기 이벤트 기반 구조의 웹 서버 소프트 웨어이다.

Apache vs Nginx?

워낙 유명하고 전에 존재하던 Apache 서버와 nginx는 많이 비교를 당한다. 두 서버의 가장 큰 차이들을 비교하자면,

Apache:

  • 쓰레드 / 프로세스 기반 구조로 요청 하나당 쓰레드 하나가 처리하는 구조
  • 사용자가 많을수록 더 많은 쓰레드를 생성해 메모리 및 CPU 낭비
  • 하나의 쓰레드:하나의 클라이언트 (마치 자바스크립트..?)

nginx

  • 비동기 이벤트 기반 구조
  • 다수의 연결 처리 가능
  • 대부분의 코어 모듈이 Apache보다 적은 리소스로 더 빠르게 동작 가능
  • 더 작은 쓰레드로 클라이언트의 요청 처리 가능

쓰레드 기반은 하나의 커넥션 당 하나의 쓰레드를 소모하지만 이벤트 기반은 비동기 식으로 처리해 먼저 처리되는 것부터 로직이 진행되게끔 한다.

Apache

클라이언트에서 요청을 받으면 MPM(Multi Processing Module: 다중처리모듈)으로 처리하는데 대표적으로 Prefork 와 Worker방식이 있다.

Prefork MPM

실행중인 프로세스를 복제해 처리를 한다. 각 프로세스는 한번에 한 연결만 처리하고 요청량이 늘수록 프로세스가 증가하지만 복제시 메모리 영역까지 복제되어 동작해 메모리 공유가 필요 없어 안정적이다.

Worker MPM

프리포크가 하나당 하나의 스레드로 처리했다면 워커는 한개의 프로세스가 여러 쓰레드를 사용해 쓰레드가 메모리를 공유한다. 그래서 메모리를 덜 사용한다.

위에 언급했듯이 C10K 문제에 있어 Apache는 접속마다 처리를 위해 프로세스 그리고 쓰레드를 생성한다. 그렇다면 10,000개의 요청일 때 그만큼 프로세스 혹은 쓰레드가 생성되는 것이고 그만큼 대용량 처리를 할 때 웹서버의 한계점을 보여준다.

Nginx


Event Driven 형식으로 소프트웨어가 돌아가기 때문에 요청이 들어오면 모두 비동기 식으로 돌리기 때문에 Event Listner 로 미뤄버린다. 흐름이 끊기지 않고 응답이 빠르게 진행돼 1개의 프로세스로 더 빠르게 작업하고 또 메모리적으로도 시스템 리소스를 적게 처리한다.

싱글 쓰레드여서 서버의 자원 활용도가 유리하고...또 아파치에 비해... 자원활용을 더 잘한다 ㅋㅋㅋㅋ 그런 점이 장점인 것 같다. 떠오르는 추세이고 또 성능이 좋다 하니 사용하고도 싶고 또 nginx도 비동기, node.js도 비동기라면...? 시너지가 있다고 한다.

선택은...?

"You just may be hacked when some yet-unknown buffer overflow is discovered. Not that that couldn't happen behind nginx, but somehow having a proxy in front makes me happy".

Node.js 의 창시자인 Ryan Dahl는 발견 되지 않은 버퍼 오버플로우에 의한 해킹을 완벽히 막을 수는 없지만, Nginx를 프록시 서버를 앞에 두는 것이 좋다고 말한다.

버퍼 오버플로우는 시스템 해킹의 대표적인 공격 방법 중 하나이다. 버퍼는 데이터가 저장되는 메모리 공간인데 메인 메모리뿐만이 아닌 다른 하드웨어에서 사용하는 임시 저장 공간도 역시 버퍼라고 한다. 데이터가 지정된 공간보다 커서 해당 메모리 공간을 벗어 나는 경우, 즉 결론적으로 버퍼 공간 보다 큰 데이터를 저장하게 해서 일어나는 오버플로우를 이용한 공격이다. 공격이 성공할 경우 시스템의 권한을 상승시키거나 악성 행위를 하도록 할 수 있다.

nginx를 프록시 서버로 앞에 놓고 node.js를 뒤쪽에 놓으면 버퍼 오버플로우를 이용한 공격을 어느 정도 방지할 수 있다고 한다. 직접적인 웹 서버를 향한 접근을 막고 한 단계 더 거치게 하며 보안을 강화한다.

적용

nginx 적용 방법은 이미 많은 선배 개발자들이 친절하게 설명을 하고 있어 그 스텝들을 꼼꼼하게 따라가니 적용을 할 수 있었다. 일단 80포트로 요청을 받아도 리버스 프록시로 로컬에 실행시켜놓은 다른 포트의 파일에 접근을 가능하게 만들었다. inbound 설정으로 nginx가 아니면 서버에 접근하지 못하게 설정할 수도 있다.

그래도 간략히 설명하자면 -
먼저 sudo apt-get update와 sudo apt-get install nginx 명령어를 통해 nginx를 설치한다.

nginx 프록시만을 설정할 instance에 접속해 nginx를 설치해주었고 /etc/nginx 디렉토리로 가서 /etc/nginx/sites-available안의 파일을 하나 만든 후,

위와 같은 형식으로 수정해 프록시 설정 및 요청 처리에 대한 설정을 해주었다. 이 코드는, 저 서버로 요청이 들어온다면, 같은 로컬에 있는 3000 포트에 열린 파일로 보내준다 이말이다.

이 후 sudo ln -s /etc/nginx/sites-available/node-server /etc/nginx/sites-enabled/
명령어로 새로 작성한 설정을 적용시켜 주었고 nginx서버를 재시작해 연결됨을 확인할 수 있었다.

그리고 node-server파일을 수정할 때 nginx보안을 위해 일단 헤더 정보 노출 방지와 에러 메시지 관리만 적용해 주었다. 필요한 보안 설정이 더 있다면 추가할 예정이다.

개인적으로, nginx 의 핵심은 직접적인 접근을 막고 보안을 강화하는 것인데, 한 인스턴스, 즉 한 ip로 들어가 그 뒤의 포트번호만 붙히면 또 접근이 가능한걸 보면서, 한단계 더 복잡하게 만들고 싶었다.

하나의 인스턴스를 더 만들어서, 처음에 만든 인스턴스는 순수하게 리버스 프록시 서버로 사용하기로 결정했다. 그래서 리버스 프록시 서버로 요청이 가면 그 요청을 내부 서버가 있는 인스턴스로 보내준다. 이런 식이라면, 내부 서버 url은 알 방법이 없고, 설사 알더라고 inbound 설정을 해주었기에 리버스 프록시 서버를 거치지 않고서는 내부 서버 코드가 있는 instance로 접근이 불가능하다.

마무으리

nginx 리버스 프록시를 적용한 서버 배포를 마치고 레포까지 퍼블릭으로 파니 현재 처음 목표로 한 minimum requirement가 완성되었다. 서버와 클라이언트를 연결해 엑스포로 빌드한 어플이 잘 작동하는 것을 확인했고 아직 안드로이드 스토어에 배포하기 까지는 자잘한 버그들을 수정해야 한다.

일단 이렇게 프록시 설정을 해주면 더 좋고 효과적이라는 것을 선배 개발자분이 소개해주셔서 알 수 있었다. 비전공자로 너무 기본지식이 없다보니 이런 부분들을 소개 받으면 공부 할 수 있어서 좋다. 직접 이론을 공부하고, 웹 서버 소프트웨어를 설치해 적용해보니 신기했고 또 프록시가 잘 작동하는 것을 보니 신기했다. 현재는 http로 리버스 프록시를 적용했는데 나중에 기회가 있다면 ssl을 적용한 https에서도 구성하면 좋을 것 같다. 잠깐 봤는데 좀 방법이 달라 그때도 집중해서 배워야 한다. 이제 코드 작성은 완성이여서 프로젝트를 회고하는 포스트가 남았다. 끝이라니..신기

참고

nginx:
https://velog.io/@jeff0720/2018-11-18-2111-%EC%9E%91%EC%84%B1%EB%90%A8-iojomvsf0n
https://m.blog.naver.com/jhc9639/220967352282
https://medium.com/daidalos-hoho/nginx-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EB%B3%B4%EC%95%88-%EC%84%A4%EC%A0%95-c239c3315ef8
https://taetaetae.github.io/2018/06/27/apache-vs-nginx/
https://cosyp.tistory.com/206

Proxy:
https://www.lesstif.com/pages/viewpage.action?pageId=21430345

profile
Grow Joshua, Grow!

0개의 댓글