Nginx로 AWS ELB 대체하기

몇달 전 기존에 쓰고 있던 AWS EC2(t2.micro) 인스턴스 2개를 비용 문제로 예약 인스턴스로 바꿨다. 그런데 비용을 좀 아끼자고 결정한 일이 오히려 비용을 몇배로 키웠다. 

예약 인스턴스를 구매하고 ELB 사용하면서 비용이 더 증가했다.

처음엔 예약 인스턴스 기간이 제대로 설정이 안됐나 싶었지만 상세 내역을 보니 문제는 바로 ELB 였다. AWS에서 이녀석을 어떻게 구현했는지 모르겠지만 ELB 한대당 t2.micro 서버 한대와 맞먹는 요금이 나오는걸로 봐서는 ELB를 EC2 위에 올려서 서비스하는건가? 하는 생각도 든다.

ELB는 왜 썼나?

비용 문제를 제외하면 라우터(Route53)와 도커 컨테이너 사이에 로드발란서(ELB)를 두고 포트를 맵핑하는 방법은 정말 간편하다. 특히 SSL 인증서를 ELB에 넣는 것도 클릭 몇번이면 다 해결되지 이걸 안써야할 이유를 못찾을 정도 였는데… 이제서야 그 이유를 찾은것 같다. 쉬운 만큼 비싸다! 그럼 각설하고 ELB 대신에 nginx 를 설정해보자.

ELB를 대신할 nginx 의 위치

도커가 설치된 호스트 서버를 최전방에 위치시키면 출처를 알 수 없는 수많은 트래픽을 받아야하기 때문에 최대한 ELB 뒤에 숨기고 싶었으나 이제는 선택의 여지가 없다. 그래도 EC2 서버 자체가 털리지 않도록 AWS 보안 그룹 설정에서 80과 443 포트만 와이드 오픈으로 열어두자. 

어찌됐든 도커가 설치된 EC2 서버에 nginx를 설치해야되는데, 이 녀석을 도커 컨테이너로 띄울지 EC2 서버에 직접 서비스로 올릴지는 잠깐 고민했다. ELB를 대신할 nginx의 역할은 부하 분산의 목적보다는 한 서버위에 여러 컨테이너로 올려지는 서비스에 포트를 바인딩하기 위한 멀티 호스팅이 주 목적이기 때문에 그냥 EC2 서버에 직접 올리기로 했다.

nginx를 설치하고 멀티 호스팅 설정은 /etc/nginx/conf.d/ 폴더 하위에 호스트 별로 설정을 추가한다. 먼저 이 블로그는 도커 컨테이너의 8888번 포트와 맵핑되어 있다. 

## /etc/nginx/conf.d/miconblog.com.conf 파일
server {
	listen 80;
        server_name miconblog.com;

        location / {
                proxy_pass http://127.0.0.1:8888;
        	proxy_set_header X-Forwarded-For $remote_addr;
	        proxy_set_header Host $http_host;
        }

}

마찬가지로 운영중인 서비스도 같은 방식으로 맵핑한다.  

## /etc/nginx/conf.d/rlibro.com.conf 파일
server {
        server_name rlibro.com;

        location / {
                proxy_pass http://127.0.0.1:8080;
        	proxy_set_header X-Forwarded-For $remote_addr;
	        proxy_set_header Host $http_host;
        }
}

EC2 서버에 certbot 설치하기

이제 ELB를 선택한 또다른 이유중 하나인 SSL 인증서 문제를 해결해보자. SSL 인증서는 직접 구매해도 되지만 도메인을 가지고 있다면 Let’s Encrypt를 이용해 무료로 쓸수도 있다. 

Let’s Encrypt로 인증서를 발급받으려면 certbot 이라는 프로그램을 이용해야한다. 일단 certbot 패키지를 설치해야하는데, 내가 쓰고 있는 CentOS7 버전은 yum을 이용해 설치할수있다는데 몇몇 라이브러리의 파이썬 버전이 맞지 않아서 직접 다운로드 받아 설치했다.  설치는 아래 링크를 참고하자.

https://certbot.eff.org/lets-encrypt/centos6-nginx

Nginx 가 설치된 서버에서 certbot을 설치하고 아래 명령을 입력하면 certbot이 알아서 nginx 설정을 읽어와 원하는 도메인에 인증서를 설치해준다. 

$> ./certbot-auto --nginx

위 명령을 입력하면 앞에서 nginx에 2개의 멀티 호스트를 설정했기 때문에 certbot은 두 도메인 중 어떤 녀석을 HTTPS로 서비스하고 싶은지 물어봐준다. 당연히 나는 2번을 선택!

Requesting to rerun ./certbot-auto with root privileges...
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
1: miconblog.com
2: rlibro.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 2

... 중략 ... 

그럼 인증서를 /etc/letsencrpyt/live/도메인명/ 하위에 설치해준다. 그리고 이어서 http 요청이 들어오면 https로 강제 redirect 할지 말지를 묻는다. 나는 역시 강제 리다이랙션 옵션인 2번을 선택!

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2

.... 중략 ...

자 이제 인증서 설정이 끝났다. nginx를 재시작하면 miconblog.com 과 rlibro.com 두 서비스가 모두 정상 동작한다. 

그리고 SSL 인증서를 설치한 rlibro.com.conf 파일을 열어보면 certbot 직접 추가한 설정을 볼수있다. 

server {
    server_name rlibro.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
      	proxy_set_header X-Forwarded-For $remote_addr;
	proxy_set_header Host $http_host;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/rlibro.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/rlibro.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = rlibro.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name rlibro.com;
    return 404; # managed by Certbot
}

와~ 세상 정말 좋아졌다!

[TIL] 스팸메일 발송에 의한 사이트 다운 현상

몇일전부터 블로그가 자꾸 죽는 문제가 발생해서 프로세스 목록을 살펴보니 sendmail 프로세스 수십개가 떠 있었다.

혹시나 싶어서 로그를 열어보니…

tail -f /var/log/maillog

뭐지? 이쎄한 느낌은,… 172…로 보내는건 내가 보내고 있는거잖아! -_-;…

Oct 18 03:49:50 ip-172-31-5-227 sendmail[4724]: v9I3nobO004724: to=brownjerry359@yahoo.com, ctladdr=armaan.h@miconblog.com (498/498), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=32155, relay=[127.0.0.1] [127.0.0.1], dsn=4.0.0, stat=Deferred: Connection refused by [127.0.0.1]
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4725]: v9I3noaq004725: Authentication-Warning: ip-172-31-5-227.ap-northeast-1.compute.internal: nginx set sender to armaan.h@miconblog.com using -f
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4725]: v9I3noaq004725: from=armaan.h@miconblog.com, size=2125, class=0, nrcpts=1, msgid=<d8462c873023f84d2f56c38bc80cd9b2@miconblog.com>, relay=nginx@localhost
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4725]: v9I3noaq004725: to=rdsjets@gmail.com, ctladdr=armaan.h@miconblog.com (498/498), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=32125, relay=[127.0.0.1] [127.0.0.1], dsn=4.0.0, stat=Deferred: Connection refused by [127.0.0.1]
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4726]: v9I3nosf004726: Authentication-Warning: ip-172-31-5-227.ap-northeast-1.compute.internal: nginx set sender to armaan.h@miconblog.com using -f
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4726]: v9I3nosf004726: from=armaan.h@miconblog.com, size=2184, class=0, nrcpts=1, msgid=<51ad53d80a417ec81c68421db28d9432@miconblog.com>, relay=nginx@localhost
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4726]: v9I3nosf004726: to=livingvampire@hotmail.com, ctladdr=armaan.h@miconblog.com (498/498), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=32184, relay=[127.0.0.1] [127.0.0.1], dsn=4.0.0, stat=Deferred: Connection refused by [127.0.0.1]
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4727]: v9I3noQL004727: Authentication-Warning: ip-172-31-5-227.ap-northeast-1.compute.internal: nginx set sender to armaan.h@miconblog.com using -f
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4727]: v9I3noQL004727: from=armaan.h@miconblog.com, size=2127, class=0, nrcpts=1, msgid=<dd97de13b625fd97de59cf2a002743c9@miconblog.com>, relay=nginx@localhost
Oct 18 03:49:50 ip-172-31-5-227 sendmail[4727]: v9I3noQL004727: to=hanklan@hotmail.com, ctladdr=armaan.h@miconblog.com (498/498), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=32127, relay=[127.0.0.1] [127.0.0.1], dsn=4.0.0, stat=Deferred: Connection refused by [127.0.0.1]

해킹 당한건가? 그럴리가 없는데,.. 80포트 밖에 열어둔게 없는데 이런게 가능한걸까?

다행인건 sendmail 설정이 유효하지 않아서 발송된 메일이 전부 거절 당했다. 덕분에 보내진 메일은 응답을 받기위해 프로세스를 들고 있다가 타임아웃이 하나둘 걸리면서 행이 걸린거 같다. 줵일~

샌드메일 발송부터 해결하자.

일단 급한대로 sendmail 데몬부터 내렸다.

$> service sendmail stop 

그리고 매번 리부팅할때마다 샌드메일 데몬이 뜨길래 아예 지워버렸다.

$> yum remove sendmail

원인이 뭐였을까?

기억을 더듬어 봤다. 아마도 예전에 워드프레스에서 댓글이 달리거나 이럴때 메일을 받았으면 해서 직접 sendmail을 설정해볼까 싶어서 설치했던 기억이 났다.
그리고 아니나다를까 워드프레스 플러그인 항목에 버젓이 Check email 플러그인이 똭~!!
아마도 이 녀석이 범인인것 같다. access 로그에도 남았겠다싶어서 확인해봤다.

[18/Oct/2017:03:52:30 +0000] 200 211.243.39.14 http://miconblog.com/wp-admin/tools.php GET /wp-admin/tools.php?page=checkemail HTTP/1.1 9689 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
[18/Oct/2017:03:52:31 +0000] 200 211.243.39.14 http://miconblog.com/wp-admin/tools.php?page=checkemail GET /wp-json/jetpack/v4/jitm?message_path=wp%3Atools_page_checkemail%3Aadmin_notices&query=page%253Dcheckemail&_wpnonce=4bad6409be HTTP/1.1 12 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
[18/Oct/2017:03:53:31 +0000] 200 211.243.39.14 http://miconblog.com/wp-admin/tools.php?page=checkemail POST /wp-admin/admin-ajax.php HTTP/1.1 58 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
[18/Oct/2017:03:53:32 +0000] 200 211.243.39.14 http://miconblog.com/wp-admin/tools.php?page=checkemail GET /wp-admin/options-general.php HTTP/1.1 21614 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36

역시나 뭔가 흔적이 남아있다. checkemail 플러그인을 바로 삭제하고 범인 수색을 더 해봐야겠다. 블로그를 독립시키던가 해야지 이 녀석 때문에 엄한 내 다른 서비스들도 같이 피해를 봤다 -_-;..
DB서버를 독립시키든지 블로그를 독립시키든지 빠른시일에 해야겠다.. 아우~ 귀찮아.

세계여행 104일째, 빈대와의 전쟁

어제 이른 아침 우유니를 떠나 마침내 수크레에 도착했다. 와보니 진짜 살만하다. 사실 우유니에 있을때 어찌나 열악하던지 거리엔 볼것하나 없고, 먹을것도 관광지라고 비싸기만하고 맛은 없고 당장에 이 거지같은 나라 볼리비아를 떠나고 싶다고 어서빨리 칠레가고 싶다고 그랬는데.. 후회할뻔했다!

최후의 만찬

아침부터 버스타고 오니라 밥한끼 제대로 못먹고 화장실 한번 못가고 장장 7시간 반을 달려왔기 때문에 일단 도착하자마자 밥부터 먹기로 했다. 두끼를 제꼈기 때문에 오늘저녁은 그냥 넘어갈수없다! 스테끼~~~~!! 여봉이 나 스테끼!!! 그리하여 수크레 넘버원 맛집으로 유명한 Abis Patio로 갔다. 아참 최후의 만찬엔 우유니에서 만난 일본인 나노짱도 함께했다. 나는 두말할 나위없이 스테끼를 시켰고, 속이 안좋다며 옆지기는 아이스크림과 샐러드를 시켰다. 나노짱은 샐러드와 햄버거! 여튼 주문해놓고 나노짱과 폭풍수다! ㅋㅋㅋ 나노짱 진짜 발랄하다. 그렇게 30분이 지났을까? 음식이 나온다.. 드디어!!!

두툼한 스테이크는 아!.. 이것이 진정 맛집이로구나!! 단돈 만원에 이런 퀄러티의 스테이크는 진정 듣도 보도 못했다! 어깨춤이 절로 나온다. ㅇㅎㅎㅎㅎ 가히 104일간 먹은 것중 최고다! 아 역시 수크레오길 잘했어~ +++_+

빈대와의 전쟁

암튼 그렇게 맛있는 저녁을 먹고 호스텔로 돌아왔다. 옆지기는 피곤한지 한참 숙소를 찾다가 잠이들고 나도 슬슬 정리하며 잠이 들었는데,.. 갑자기 “오빠!” 응? 머야? 왜? 뭐야? 자다가 일어났더니 옆지기가 이블 위를 기어다니던 빈대를 잡아 족쳤는지 시뻘건 피를 가르키며 안돼겠다고 이사를 가야겠다고 한다. 헐퀴! 누가 물린거지? 아직 난 물린 자국이 없는데,.. “건빵아 너는 어때?” “응! 아직 물린데는 없어.”

안그래도 푸노에 있을때 빈대를 물려서 손이 퉁퉁 부어 있다가 이제야 가라 앉기 시작했는데, 헐.. 또 빈대야..-_-;; 수크레 첫날부터 빈대라니.. 사실 가격대비 괜찮은 호스텔이라고 생각했는데 역시 맘대로 되는게 없다. 아직 물린 자국이 없으니 일단 자고 내일 아침에 일어나서 물렸으면 이사가자!

다음날 아침

아~~~ 뭐야! 물렸다. 결국…ㅎㅎㅎ 왼쪽 옆구리 한방 -_-;; 잠복기가 있기 때문에 사실 더 많이 물렸을찌도 모른다. 아.. 뭐닝? 그래도 뭐 가려워 미칠지경은 아니다. 참을만하다. 짐싸기 귀찮은데 아침부터 다시 찜싸고 숙소도 겨우겨우 예약을 했다.

빨래와의 전쟁

새로 잡은 숙소는 호스텔은 아니고 가정집이다. 다행히 빈대 호스텔에서 멀지 않았다. 초인종을 누르고 주인을 기다린다. 어랏? 너무 일찍 왔나? 반응이 없다. 한번더 눌러본다. 잠시후 문이 열렸다. “올라~” 반갑게 인사를 하고 대문을 들어서자.. 와우~! 집이 엄청크다. 왜 늦게 나왔는지 알것같다. ㅎㅎ 에어비엔비를 통해 1주일을 예약했는데, 바로 2주를 더 있기로 했다. 괜찮은 집이다. 절로 미소가 나온다. 우리가 묵을 곳은 3층에 있는 방하나. 주인 안나가 집안 곳곳을 소개시켜줬다. 옥상엔 세탁기가 있고 뷰도 너무 좋다! 자자 집구경 끝났으니 그동안 밀린 빨래를 좀 해야겠다.

옥상에서 빨래를 시작한 시간은 11시 40분쯤 빨래가 끝난 시간은 오후 4시 40분 ㅎㅎㅎ 빨래하고 밥먹자 했는데 저녁이 되어 버렸다. -_-;; 한국에서 잘 먹지도 않는 라면이 거의 한달에 서너번은 해먹는듯 싶다. 이거시 고향의 맛인가? 아님 귀차니즘의 맛인가? 난 잘 모르겠다. 맵다. “건빵! 제발 스프는 반만 넣자! 응?”

세계 여행 100일째, 볼리비아 우유니

새벽에 볼리비아 우유니에 도착했다. 계획대로라면 수도인 수크레로 가야했지만 역시나 장기 여행은 변수가 많다.
볼리비아 선거가 코앞이라 수크레로 가는 버스가 모두 매진됐다. 사실 매진된건지 아예 운행을 안하는건지 모르겠다. 암튼 다음주 월요일이 되야 버스가 있단다. 결국 수크레를 포기하고 우유니로 왔다. 물론 라파즈에 몇일 보낼수도 있었지만 나나 와이프나 모두 원치 않았다.
우유니에 도착한 시간은 새벽 5시쯤 아직 해도 안떴다. 다행인건 여행객들이 많아서 아침식사와 샤워를 제공한다는 까페 삐끼(?)라고 하긴 뭐하고
암튼 아줌마가 터미널까지와서 우리를 이끌었다. 인터넷이 된다는 이곳 카페도 인터넷은 그다지 좋지 않다. 연결이 됐다 안됐다 반복된다. 쿠바도 아닌것이 인터넷은 포기! 일기나 쓰자.

역할 분담

여행 50일이 넘어서면서 나와 와이프의 역할이 어느정도 갈렸다. 스페인어가 나보다 유창한 와이프는 새로운 곳에 도착하면 나에게 짐을 맡기고
여기저기 숙박을 알아보러 다닌다. 때론 여자 혼자 보내는게 안쓰럽지만 그 반대도 마찬가지다. 대신 나의 역할은 짐꾼이다. 와이프가 없는동안엔 짐을 보며 보통 멍때린다. 아무래도 노트와 펜을 하나 사야겠다. 오늘처럼 카페에 앉아 있을수만 있다면 노트북을 꺼내 글이라도 쓰겠지만 대부분은 그냥 길바닥 위에서 짐을 내려놓고 멍때리기 일쑤다. 왠지 뭔가를 끄적이지 않고 멍때리고 있으면 시간이 아깝다.

우유니

밤버스에 여독이 풀리지 않은 상태에서 우유니로 출발했다. 그동안 수없이 들었던 그 갑질(?) 우유니! 그런데 우유니 투어는 마츄피츄에 비하면 정말 양반이었다. 중간에 밥도 주고 가격대비 꾀 괜찮은 투어라는 생각이든다. 소금사막에 물이 좀더 찻으면 어땠을까? 조금 아쉬움이 들기도하지만 하루종일 사진 찍느라 우리 웨딩촬영보다 힘들었다. 그래서 또 가고 싶은 생각이 싹 사라졌다. 우유니도 그랬고 마츄픽츄도 그랬지만 이런 유명 관광지를 다녀왔을때 그 무엇이 나에게 주는 특별함 보다는 언젠가 옆지기와 맞아! 그래 그랬지! 하며 추억꺼리가 하나 더 생긴거 같아 좋다.

여행 100일

여행 100일엔 파티를 하고 싶었는데 어쩌다 보니 우유니에서 100일을 보냈다. 나도 뭔가 여행 백일에 대한 소회를 써보고 싶지만 100일이라는 시간이 소회를 남기기엔 그렇게 긴 시간은 아닌것 같다. 200일에 다시 써봐야겠다.