nginx 와 socket.io 연동

nodejs를 이용해 socket.io를 사용하는 경우 보통 포트번호가 다음과 같이 들어가기 마련이다.

somewhere.com:9000

하지만 포트 번호가 노출되는것이 영~ 깨림찍한 경우엔 앞딴에 nginx 나 apache 를 두고 뒷딴의 9000포트로 프록시를 하는 것이 보통이다. 개인적으로는 아파치도 좋치만 nginx를 더 자주쓰고 있다. nginx 를 쓴다면 아래와 같이 설정을 추가한다.

server {
    listen 80;

    root /app/node-server/dist/public;
    index index.html index.htm;

    # Make site accessible from http://localhost/
    server_name somewhere.com;

    location / {

      // A: Proxy 패스를 설정하고 싶은 경우, 
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-NginX-Proxy true;

      proxy_pass http://somewhere.com:9000/;
      proxy_redirect off;

      // B: socket.io 사용시 아래설정 필수!!
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_http_version 1.1;

    }
    ... 이후 생략 ...
}

특히 socket.io를 이용하는 경우 B 설정은 필수다. B설정이 뭘해주는지는 솔직히 귀찮아서 찾아보진 않았다. 하지만 저 설정을 하지 않으면 ws:// 프로토콜로 웹소켓과 통신할때 핸드쉐이킹이 제대로 안되서 에러가 난다.

물거품, nginx server is down!

사전 정의

  1. 물이 다른 물이나 물체에 부딪쳐서 생기는 거품.
  2. 노력이 헛되게 된 상태를 비유적으로 이르는 말. > 유의어 : 수포1, 포말3, 뜬구름

오늘 오후 지메일로부터 한통의 메일을 받았다. 당신의 사이트가 24시간 동안 크롤링이 되지 않는다. 즉, 서버가 죽었다는 말이다. 왜 죽었는지 이유는 모르겠다. 불연듯 떠오른 나의 생각은 다른거 다 제껴두고 매일 로그인해서 이벤트를 응모하도록 만들어놓은 cron 잡들이었다. 아니나 다를까! 멘붕! OTL,… 심열을 기울여 한달 스템프를 모두 받겠다고 야심차게 스크립트까지 만들어 돌렸는데,… 토요일 하루 도장이 없다! 망했다! 진짜 이번엔 성공할줄 알았는데… 제대로 한방 먹었다. ㅜㅜ 정녕 내년을 기약해야하는 것인가? ㅎㅎ

서버는 언제 죽은 것일까?

아까 낮에 허탈함에 어떻게 해야지? 어떻게 해야지? 발만 동동 굴렸는데,.. 역시 밤이 되니까 여러가지 생각을 되짚어보게 된다. 서버가 왜 죽었을까? AWS로 옮겨온 이후로 2번째다. 그리고 nginx로 넘어온 뒤로 역시 두번째다. 지난번에는 php모듈을 건들다가 발생한 문제라서 php-fpm이 문제겠꺼니 쉽게 유추해낼수있었는데.. 이번엔 도대체 뭐지?

언제 죽었는지도 알수없고, 얼마나 오랜동안 죽어있었는지 조차도 알수가 없었다. 그래! 결심했어! 찾아보자! 뚜두뚜~ 뚜두뚜~ 뚜두뚜~ 뚜뚜루루~ 뚜두뚜~ 뚜두뚜…

그래 일단 AWS에서 제공하는 모니터링 로그를 살펴보는거야!

지난 토요일에 스템프가 찍히지 않는걸로 봐서 최소 2일이상의 로그를 봐야한다. 그래서 3일짜리 네트워크 유입량부터 살펴봤다. network 아니나 다를까 12월 14일 오전 8시경 네트워크 유입량이 짧은 시간안에 엄청나게 몰렸다. UTC 기준이니까 실제 한국시간으로는 오후 5시쯤이 아닐까? 어라? 그러고보니 내가 서버를 확인한 시간이 오후 5시쯤인데 오후 5시에 죽었따고? 말이 안되는데? 쫌 이상하다! 이미 그전에 서버 응답이 없어야되고, 지메일은 분명히 지난 24시간동안 최소 1번 이상 응답이 없었다고 알림을 줬다. 그리고 이 메일을 받은 시각은 오전 10시경,.. 그렇다면 최소 어제 오전 10시 이전에 서버가 죽어 있거나 응답이 없었다는 얘기가 된다. 그래야 말이 된다. 왜냐면 내가 매일 오전 10시에 스템프를 찍도록 크론잡을 돌려놨었는데,.. 이 크론잡도 실행을 못했다는 얘기는 10시전에 서버에 뭔가 문제가 생겼다는 얘기가 된다. 다른 로그를 좀더 살펴봐야겠다.

multi-log 음,.. 뭔가 추이가 이상하다. 네트워크 아웃을 보니 토요일 새벽 0시쯤 그러니까 우리나라 시각으로는 토요일 오전 9시경부터 네트워크 유입은 있지만 뭔가 서버가 응답을 못해주고 있다. CPU credit도 갑자기 뚝 떨어졌다. 아! 여기구나! 절묘하네. 토요일 오전 9시! 도대체 이날 무슨일이 있었던거지? 젠장 한시간만 늦게 죽지..ㅜㅜ 아니지.. 매일 한번씩이 아니라 6시간마다 한번씩 크론잡을 돌렸다면 적어도 문제는 없었는데…ㅜㅜ.. 아! 쉽! 다!…

토요일 오전 9시의 미스터리. 실마리를 찾아서

그럼 토요일 오전 9시경 문제가 될만한 로그부터 뒤져봐야겠다. 일단 syslog를 봐야된다길래 /var/log/syslog가 있는지 확인부터 해봤지만,.. 어머나! 없네? syslog를 찍는건 옵션을 따로 설정해야하는건가? 아~ 몰라,.. 패스.. 그럼 지난번 원인이었던 php-fpm 로그부터 보자.

$> cd /var/log/php-fpm
$> ls -al
-rw------- 1 root   root  2054 12월 14 17:38 error.log
-rw------- 1 root   root 20440 11월 22 22:24 error.log-20141123
-rw------- 1 root   root 15612 11월 30 01:56 error.log-20141130
-rw------- 1 root   root  2504 12월  6 02:36 error.log-20141207
-rw------- 1 root   root 97429 12월 14 16:29 error.log-20141214

어랏? 로그파일의 크기가 0이 아닌걸로 봐서는 진짜 php-fpm에서 뭔가 문제가 있었네? 열어보자! 뚜둥!! 뭐지 이건?

$> cat error.log-20141214
... 중략 ... 핵심만 ...
ERROR: fork() failed: Cannot allocate memory (12)
WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 11 total

메모리를 할당할 수 없다고? 도대체 언제부터 이런거지? cat은 화면 출력 버퍼량 때문에 짤리니까 vi로 열어봐야겠다.

$> vi error.log-20141214
... 중략 ...
[12-Dec-2014 10:10:59] ERROR: fork() failed: Cannot allocate memory (12)

정확히 메모리 에러가 난 시간은 12일 오전 10시경, 참고로 리눅스 서버의 시간은 UTC 기준이었으나 크론탭을 설정할때 자꾸 헛갈려서 로컬 타임을 한국시간으로 바꿔놨다. 음,.. 그러니까 서버가 죽은 시간은 정확히 오전 10시 10분. 아! 10분만 일찍 죽었어도 12일부터 그놈의 스템프를 못찍었겠꾸나 ㅎㄷㄷ…

도대체 진짜 원인은 뭘까?

그래, php-fpm에서 처음 메모리 할당 오류가 뜬 시간이 지난 12일 오전 10시경이니까 처음 예상했던 시간보다 하루 일찍 문제가 찾아왔었군!… 그렇다면 실제 원인을 찾기 위해서 모니터링 로그를 좀더 넓혀서 살펴봐야겠다. 음.. 내가 뭔가 탐정된 느낌이군. ㅎㅎㅎ

multi-log-2weeks

아! 넓혀서 추이를 보니 이번엔 또 다른 단서가!! 네트워크 아웃을 보니 12일부터 밖으로 나가는 트래픽이 없어졌다. 덩달아 CPU 사용률이 훅~ 떨어지는걸 봐서는 확실히 12일부터 서버에 문제가 있었던것 같다. 그런데 그보다 앞서 CPU 사용률을 보니 지난 8일 오전 10시경부터 뭔가 CPU 사용률이 계단식으로 증가하고 있네!!! 뚜둥~! 마치 메모리 누수가 있을때 나타나는 현상처럼 증가하고 있다. 도대체 뭐지?

한편 이에 앞서 syslog를 대신할 만한 이벤트 메세지도 확인해봤다.

%> vi /var/log/message
... 중략 ....
Dec 12 10:11:10 ip-172-31-12-73 kernel: [604065.445632] php-fpm[9401]: segfault at 80001000321 ip 00000000005c8407 sp 00007fff305df290 error 4 in php-fpm[400000+325000]
... 중략 ....
Dec 12 18:17:24 ip-172-31-12-73 wordpress(miconblog.com)[8434]: Authentication failure for admin from 198.46.81.14
... 

여기서 잠깐!

로그를 보니 재밌는 현상을 발견했다. php-fpm에서 메모리 할당 오류가 나면 segfault 메시지를 발생시킨다는 사실과 더불어 인도에서 내 워드프레스 계정을 털려고 시도한 흔적이 보인다는 사실이다! 아~ 인도!! IT 강자로 급부상 중이라고 하더니… 흠..좀..무.. 다시 워드프레스 계정 보안 플러그인을 설치해야겠다는 생각이든다. php-fpm 문제 해결을 위해 검색을 좀 해봤더니 설정값을 좀 늘려보라는데,.. 그게 문제겠냐? 저렇게 무차별 DDos 공격에 당하면 서버가 죽어버리는데..ㅜㅜ..

여전히 알수없는 미스터리..

다시 돌아와서 지난 8일에 내가 도대체 무슨일을 했는지.. 기억을 더듬어봤다. 일단 캘린더에 등록된 저녁 일정엔 와인동호회 모임이 있었음을 알려준다. 하지만 월요일 오전엔 무얼했지? 페북에도 쓴 글이 없고, 지메일에도 주고 받은 내역이 없다. 그리고 몇일전에 서버에 노드앱을 추가한게 떠올랐다. 혹시나 싶어 로그를 살펴봤으나.. 젠장 로그에 시간을 안찍어놨네.. 망할… 내일 회사가면 회사 메일을 한번 뒤져봐야겠다. 아~~ 여기까지 추적해왔는데.. 이녀석이 꼬리를 짜르고 도망간 느낌이다. 내 기필코 니놈을 잡고 말테다.

현재, 수사선상의 용의자.

  1. php-fpm: 그냥 너는 서버를 죽인 실체
  2. 인도 해커들의 무차별 로그인 공격: 일종의 DDos 공격,… 내가 너무 방어를 안했나? php-fpm에 많은 부하줌.
  3. 내가 만든 노드 앱들에서 발생하는 메모리 누수(?),.. 모르겠다.
  4. 그냥 서버 자원이 쪼들려서 그런건가?,..

아무리 생각해도 난 저 계단식 사용률에 문제가 있지 싶다. 그동안 아무런 문제가 없다. 8일부터 특이한 계단식 로그가 찍히는걸봐서는 강력하게 의심이 되는데,.. 그것도 일정하게 증가하는걸로 봐서는… 아! 인도해커들이 일정한 주기로 공격을 하는건가? 아놔 모르겠다.. 일단 자자.

apache에서 nginx로 갈아타기

요즘 AWS 덕분에 리눅스라는 녀석을 조금 더 딥하게 보고 있는데 리눅스 이녀석 자체만으로 공부할게 너무 많다. 각설하고 오늘은 그동안 공부한 것들 복습도 할겸 미뤄뒀던 동구밭 블로그를 nginx로 갈아탔다. 갈아타는 과정을 좀 정리해보면 다음과 같다.

  1. 리눅스 계정 및 웹서버 루트 폴더 이동
  2. CentOS 5.x 버전에서 yum으로 설치가능한 패키지 버전 문제 확인
  3. CentOS 5.x 버전의 공식 릴리즈 사이트에는 php 버전이 매우 낮음을 확인
  4. CentOS를 6.x 버전으로 업그레이드 가능한지 확인. yum으로는 불가. 백업해서 재설치해야 함을 확인
  5. OS 업그레이드를 포기하고 yum으로 php5.4 버전 설치 (많은 삽질)
  6. yum으로 nginx 설치했는데.. 이것도 버전이 낮아서 yum 레파지토리 변경후 1.6으로 업그레이드

과정이 참 긴데,.. 오늘 느낀점은 yum 명령과 레파지토리에 관련된 내용을 좀더 공부해야겠다는 생각을 했다.

웹서버 루트 폴더 정리

여튼 그간의 과정을 되짚어보자. 일단 웹서버 루트가 어디에 있는지 확인했더니 /home/www 였다. 아~~ 홈폴더 하위에 웹폴더를 뒀었꾸나… 얼마나 개념이 없었는지 실감하면서,.. /var/www/nginx_root로 이동 감행! 이제 나에게 리눅스 계정과 권한문제는 껌이지ㅋㅋㅋ 폴더를 생성하고 소유자를 nginx로 변경, 그리고 wordpress 폴더도 통째로 이동후 소유자(nginx)와 권한을 변경! wp-content 폴더는 간편설치를 위해 655 권한으로 변경. 소유자를 nginx로 했기 때문에 사실 600으로 해도 된다.

nginx와 php 설치

다음으로 아파치 서버와 mysql를 내리고 기존에 설치되어 있는 php 버전을 확인해봤다.

$> php --version

옴마~ 5.1 버전??? 왜이렇게 버전이 낮지? 이거 작년에 설치했을텐데,.. 이유를 알아보기 전에 일단 지우자.

$> yum remove php*

지우고 나서 yum 으로 설치 가능한 패키지를 알아보니 CentOS 5.x 버전에 있는 공식 릴리즈 모듈에는 5.1까지 밖에 없는게 아닌가? “아~ 난감한데… 어떻하지?.. 그냥 최신 버전을 홈페이지에서 직접 받아서 컴파일 할까?” 하다가 예전에 php 버전에 따른 의존성 모듈들 때문에 고생한 한 기억이 떠올라서(파이썬을 직접 업그레이드하다가 꼬여서 파이썬에 의존성이 매우 심한 yum 명령어를 날려버렸던 씁슬한 기억) 이번에는 온전히 yum 으로만 해결하려고 맘먹었다.

이 문제를 어떻게 해결할까? 한참 찾다 결국엔 yum 레파지토리를 업데이트해야한다는 사실까지 알아냈다. ㅎㅎㅎ 아무튼 현재 내가 쓰고 있는 CentOS 버전은 5.11(final) -_-;; yum을 이용해 상위 버전으로 업그레이드는 못한단다. 그리고 5.11의 공식 라이브러리 레파지토리에는 php 버전도 5.1 이고 심지어 nignx도 0.6 버전이었다. 자세한 설치는 검색하면 나온다.

nginx는 php 모듈을 지원하지 않기 때문에 php-fpm 이라는 FastCGI 모듈을 이용해야한다. 여튼 php와 관련된 모든 연동 모듈은 remi 라는 레파지토리를 이용했다. 배가 너무 고픈 관계로 일단 여기까지 정리하고 다음에 이어서 정리하자.

오늘 새롭게 알게된 내용

  1. ningx는 php 대신에 php-fpm 모듈을 이용한다.
  2. 워드프레스에서 이미지 크롭하려면 그래픽 처리와 관련된 php-gd 라이브러리가 설치되어 있어야한다.
  3. CentOS 5는 후졌다. 하지만 어쩔수 없다.
  4. yum 레파지토리를 변경하거나 업데이트 할 수 있다.
  5. 확실히 하드웨어가 저사양일 경우 아파치보다 nginx가 훨씬 좋터라!

리눅스 파일 권한과 워드프레스 설치시 유의점

AWS 서버로 이전하기 위해 필요한 지식들 2탄

지난글에 이어서 2탄으로 정리해본다. 지난글을 되짚어보려니 또 기억이 가물가물… 역시 글은 생각날 때 바로 써야… 흐흑… 각설하고,.. 지난 글을 되짚어보자.

지난글에서 아마존 EC2 인스턴스를 하나 만들고 사용자 계정과 파일 및 폴더 소유자에 대한 이야기를 잠깐 언급했었다. 특히 엔진엑스에서 서버의 실행권한이 nginx 라는 것이 매우 중요하다고 이야기했었다. 이 이야기를 하기 앞서 먼저 리눅스 파일 권한 부터 알아보자.

리눅스 파일 권한에 대한 기본 개념

리눅스를 설치하고 가장 최상위 루트(/)에서 ls -al명령어를 실행해보자.

$> cd /
$> ls
$> ls -al
합계 100
dr-xr-xr-x 23 root root  4096 11월 21 15:10 .           <--- 현재 폴더
dr-xr-xr-x 23 root root  4096 11월 21 15:10 ..          <--- 상위 폴더
-rw-r--r--  1 root root     0 11월 21 15:10 .autofsck
dr-xr-xr-x  2 root root  4096 11월 21 12:12 bin
dr-xr-xr-x  4 root root  4096 11월 21 13:29 boot
... 중략 ...
dr-xr-xr-x 89 root root     0 11월 21 15:10 proc
dr-xr-x---  4 root root  4096 11월  5 06:09 root
dr-xr-xr-x  2 root root  4096 11월 21 12:54 sbin
dr-xr-xr-x 13 root root     0 11월 24 09:54 sys
drwxrwxrwt  3 root root  4096 11월 24 09:54 tmp
... 중략 ..

조회를 해보면 대충 위와 같은 결과를 얻을수있다. 여기서 첫번째 열(drwxrwxrwt)은 계정의 권한을 의미한다. 폴더일 경우 d로 시작되고 심볼릭 링크인 경우엔 l, 그리고 파일은 미지정(-)상태가 된다. 그리고 그 다음 각각 3자리는 아래와 같다.

[1자리:파일타입][3자리:소유자권한][3자리:그룹의권한][3자리:others권한]

위에서 소유자와 그룹은 두번째와 세번째 열에 각각 그 소유자와 그룹 이름을 표시한다. 여기까지는 상식이니까 넘어가고 자세한 내용은 검색하면 많으니까 검색해보자.

루트 폴더(/)의 대부분은 소유자인 루트(root)에게 대부분의 읽기(r),쓰기(w),실행(x)권한이 열려있다. 하지만 몇몇 폴더들은 쓰기 권한이 빠져있는 것을 확인할 수 있다. 대표적으로 리눅스 시스템 폴더(/sys)와 부팅에 필요한 폴더(/boot) 그리고 실행중이 프로세스 정보가 담겨있는 /proc 폴더들은 루트 마저도 쓰기권한이 없는 경우가 많다. 생각해보면 너무나 당연한 권한이다. 이런 권한 때문에 루트(/)폴더에서 일반 유저가 mkdir 명령으로 폴더를 생성하면 퍼미션이 없다며 생성이 되지 않는다.

[ec2-user@/]$> cd /
[ec2-user@/]$> mkdir test
mkdir: `test' 디렉토리를 만들 수 없습니다: 허가 거부

하지만 권한이 있는 폴더에서는 당연히 폴더든 파일이든 생성할수 있다. 그럼 폴더를 하나 생성해보자.

[ec2-user@/]$> cd ~
[ec2-user@~]$ mkdir test
[ec2-user@~]$ ls -al | grep test
drwxrwxr-x   2 ec2-user ec2-user  4096 11월 24 10:41 test

ec2-user 계정으로 폴더를 생성하면 당연히 첫번째 비트는 폴더이므로 [d]가 된다. 그리고 본인이 생성했으므로 당연히 소유자권한은 rwx가 되고, 그룹의 권한은 ec2-user가 속해있는 그룹에게는 모든 권한이 열려있다. 하지만 그외 유저들에게는 쓰기 권한이 없다. 그럼 루트로 폴더를 생성하면 어떤 권한이 생성될까?

[ec2-user@~]$ sudo mkdir test2
[ec2-user@~]$ ls -al | grep test
drwxrwxr-x   2 ec2-user ec2-user  4096 11월 24 10:41 test
drwxr-xr-x   2 root     root      4096 11월 24 10:41 test2

루트 권한으로 폴더를 만들면 일반 유저와는 다르게 그룹 권한도 쓰기권한이 없다. 그만큼 root계정은 보안에 신경쓰고 있음을 보여준다.

아파치나 nginx에서 403 forbidden 에러가 나는 이유

자 이제 이 얘기가 왜 중요한지 알아보자. 보통 웹서버를 설치하고 브라우저로 설정한 파일을 URL로 통해 접근하려고 할때 403 forbidden 에러를 종종 보게 되는데, 바로 이 에러가 파일 권한 문제와 관련이 있다. 이전에도 이와 관련된 글을 쓴적이 있다.

apache나 nginx와 같은 웹서버는 URL을 통해 서버에 있는 특정 파일에 접근(access)하게 되는데 이때 접근 계정은 해당 서버를 실행시킨 계정이 된다. 즉, nginx의 경우 nginx라는 계정으로 해당 파일에 접근하게 되는 것이다. 물론 아파치서버의 경우 apache 계정으로 접근하게 된다. 따라서 웹서버의 최상위경로(doc_root)는 접근하려는 계정에게 최소한 읽기 권한이 있어야 한다.

따라서 nginx의 루트 폴더(document_root)를 누구 소유로 지정하느냐에 따라 최소 권한이 바뀐다.

  • 가령, 루트폴더를 nginx 계정이 소유하고 있다면 최소 400(r–,—,—) 권한이 있어야하고
  • nginx가 아닌 다른 계정(ec2-user)이라면 최소 004(—,—,r–) 권한이 있어야한다.

그런데 nginx 웹서버의 도규먼트 루트 폴더를 계정의 홈폴더(/home/ec2-user) 하위로 지정하고 싶은 경우가 있다.

/home/ec2-user/www

예를 들면, 위와 같은 위치에 www 폴더를 만들고 싶은 경우를 말하는데, 안타깝게도 이렇게 하려면 현재 ec2-user 폴더의 권한도 수정해줘야한다. 왜냐면 ec2-user 폴더는 홈폴더 특성상 700권한으로 지정되어 있기 때문에 소유자 본인 말고는 다른 계정이 접근조차 할수없다.

[ec2-user@/]$> cd /home
[ec2-user@home]$> ls -al
합계 16
dr-xr-xr-x  4 root     root     4096 11월  3 09:27 .
dr-xr-xr-x 23 root     root     4096 11월 24 10:39 ..
drwx------ 15 ec2-user ec2-user 4096 11월 24 11:11 ec2-user

그래서 자신의 홈폴더 하위에 웹폴더를 만들고 싶다면, 웹서버 계정이 접근 가능하도록 /home/ec2-user 폴더에 최소한 읽기 권한은 있어야한다.

drwx—r–

하지만 나는 리눅스가 지정해둔 홈폴더 고유의 권한을 바꾸고 싶진 않기 때문에 www 라는 이름이 /var/www/nginx-root 폴더를 가르키도록 심폴릭 링크를 만들어 사용한다. ln 명령은 일반 유저에겐 권한이 없으므로 sudo를 붙인다.

$> sudo ln -s /home/ec2-user/www/nginx-root www
lrwxrwxrwx   1 root     root        20 11월  4 08:53 www -> /var/www/nginx-root/

워드프레스와 nginx의 소유자 권한

이제 nginx 서버에 워드프레스를 설치해보자. nginx 서버는 지난 1탄에서 살펴봤듯이 master 프로세스는 root가 실행시키고 실제 동작을 담당하는 worker 프로세스는 nginx 라는 계정으로 실행된다. 따라서 워드프레스 설치경로의 소유자를 같은 nginx로 바꿔준다. 만약 다른 계정으로 지정한다면 반드시 nginx 계정이 접근가능하도록 other에 읽기 권한이상을 열어줘야한다.

설치형 워드프레스의 장점, 웹에서 설치하기

워드프레스는 간편하게 클릭만으로 플러그인이나 테마를 설치할 수 있는데 이때 설치되는 과정을 살짝 들여다보자. 1. 먼저, 웹 관리 메뉴에서 테마나 플러그인을 다운로드 받으면,
2. 워드프레스를 실행시키는 프로세스(nginx)가 필요한 파일을 웹에서 다운로드 받는다. 3. 그리고 이것을 wp-contents 폴더에 복사한다. 4. 이때 다운받은 파일의 소유자와 권한은 당연히 nignx가 된다. 5. 하지만 그룹과 other에게 쓰기 권한은 주어지지 않는다.

정리하면 아래와 같이 764(rwx,r-x,–x) 권한으로 지정된다.

drwxr-x–x 11 nginx nginx 4096 11월 24 12:59 penny

여기서의 핵심은 워드프레스를 실행시킨 프로세스가 누구냐는 것이다. 즉, nignx 계정으로 파일을 다운받아 워드프레스가 인식하는 특정폴더(wp-contents)에 파일을 복사하기 때문에 워드프레스 폴더의 소유자가 nignx가 아니라면 other 계정의 쓰기 권한도 지정해야함을 의미한다. 따라서 소유자와 other에 권한이 제대로 매치되지 않으면 그 쉽다는 원클릭 설치도 제대로 안될것이다.

정리하면,

이번 글도 양은 얼마되지 않으나 글로 정리하려니 시간을 엄청 썼다. 이번글은 거의 리눅스 계정과 워드프레스 얘기만 했는데, 다음 편에는 AWS에서 라우터 설정과 nginx에서 멀티 호스팅을 어떻게 전략적으로 응용할수있는지 알아보겠다.

덧,

이 글이 도움이 되셨다면 아시죠? 광고한번 클릭해주세용~ 🙂

AWS 서버로 이전하기 위해 필요한 지식들 1탄

Cafe24에서 약 2년간 가상 서버 호스팅을 이용하다 이번에 AWS로 넘어왔다. 막상 이사오려니 귀찮은 작업들이 많아서 미루고 미뤄뒀는데, 결국 호스팅 계약 만료일에 이르러서야 실행에 옮겼다. 혹시 잊어먹을까 해서 그동안 했던 작업들을 정리해본다.

1. AWS 계정 만들기

맨 처음 해야할 일은 아마존 웹서비스라고 불리는 AWS 계정을 만드는 일이다. 1년간 무료에 혹해서 일단 만들었는데 신용 카드 정보를 입력해야한다. 이말은 즉, “테스트 서버를 1년간 돌리다 니가 그 서버를 직접 내리지 않으면 난 과금하겠다!” 라는 얘기. 하지만 뭐 이미 난 1년 내내 돌릴 개인 서버가 필요하므로 비용은 일단 무시하고 실행에 옮겼다! 다만 AWS는 초보자가 접근하기엔 무리가 좀 있지 싶다. 필요하다면 AWS Essential 무료 강의를 찾아서 듣길 권한다.

2. EC2 인스턴스 만들기

AWS에서 EC2라고 부르는 녀석은 Cafe24에서 가상 서버 호스팅이라고 부르는 가상 서버와 동일한 녀석이다. 일반적으로 서비스가 커지면 Application 서버와 DB 저장소 뿐만아니라 라우터와 로드 발란서도 두고 캐시 서버도 막 두고 그러던데,.. 솔직히 나도 그러고 싶었다. 개인적으로 블로그 외에 연습용 서비스를 몇개 만들어서 돌리고 있기 때문에 EC2 인스턴스를 여러개 만들어두고 올렸다 내렸다 하고 싶은데, 나중에 과금이 얼마나 될지 가늠이 안되서… 불안하다. 특히 DB를 분리할까말까 엄청 고민을 했다. 하지만 역시나 내 결론은 과금문제..ㅜㅜ.. 그래서 결론은 “EC2 서버 인스턴스 한대를 열씨미 쪼개서 써야겠다.” 라는 결론에 이르렀고 나중에 이사는 그만 다니고 싶어서 평생 AWS에서 살겠다는 각오로 EC2 인스턴스를 어떻게 활용할까 전략을 짰다.

3. EC2 인스턴스 활용 전략

일단 내가 EC2 인스턴스 하나에 개인 블로그를 포함해 몇개의 서비스를 돌릴지 추려봤다.

  1. 워드프레스 블로그 (Nginx + PHP + MySQL)
  2. 개인 위키 페이지 (Nginx + PHP + MySQL)
  3. NodeJS Application N 개 (nodejs + MongoDB)
  4. NodeJS Application M 개 (nodejs + MySQL)
  5. 기타 잡다 저장소

대충 요렇게 정리하고 보니 몇가지 걸림돌이있었다. 이전 서버에선 APM(Apache + PHP + MySQL) 조합을 이용했는데 이번에 Nginx로 갈아타려고 맘먹고 보니 Nginx 설정도 허들중에 하나였다. 물론 그보다 앞서 서버 접근 권한과 계정을 어떻게 정리하고 관리할지도 문제였다.

4. 서버 접근 권한 및 계정 정리

서버 접근 권한은 나에겐 좀 신세계였다. 나는 프로그래밍은 좋아하지만 리눅스라는 서버와는 그렇게 친숙하지 않기 때문에 찾아보고 옆 짝지한테 물어보고 참… 성가시게 굴었네. 학교 다닐때 나도 남들처럼 PC에 리눅스 좀 설치하고 “나 컴터 존나 잘해 리눅스 깔았꺼든.. 나 쫌 짱이지~?” 하며 뻐기고 다닐껄 그랬다. 특히나 리눅스라는걸 딱히 배우거나 공부한적도 없기 때문에 일반적으로 리눅스 유저들이 계정관리를 어떻게하는지 그게 진짜 궁금했다. 근데 나와 같은 궁금증을 가진 사람이 없는건지 다들 대충 쓰는건지 계정을 추가하거나 삭제하는 글들은 쉽게 검색해서 찾을수있는데, 어떤 룰을 가지고 계정관리를 하고 있는지 아무리 찾아도 안나오드라. ㅎㅎ 나만 못찾는건가? (꿍시렁.. 꿍시렁…)

나의 궁금증을 한번더 자극하는 것은 바로 EC2 서버에 접속하기 위한 Key Pair란 녀석이었다. 이전엔 서버 접속을 위해 계정과 비밀번호가 필요했는데 AWS는 비밀번호 자체가 필요없다는 것이다! 오호라~! 맨날 비번 입력하는거 귀찮았는데 이거 정말 좋은데? 라는 생각도 잠시,… ssh 도움말을 좀 읽어보니… ‘아~ 원래 있는거구나…ㅎㅎㅎ’ 암튼 EC2 서버는 공개키를 이용한 접속을 기본으로 제공한다. 이왕 하는 김에 접속 주소와 공개키를 alias로 엮어 놓으면 엄청 편했다. 공개키 생성관련 내용은 아마존 가이드 문서를 참고하시길….

$> vi ~/.bash_profile
alias "aws"="ssh -i [your-key-pair-name].pem ec2-user@xxx.xxx.xxx.xxx"
대충 요렇게 적고,...

$> source ~/.bash_profile
$> aws 

   __|  __|_  )
   _|  (     /   Amazon Linux AMI
  ___|\___|___|

Wow~~ 벌써 연결됐네... 엄청 간단한걸??? 

여튼 EC2 인스턴스를 만들면 ec2-user 라는 계정이 기본으로 생성되는데, 이 녀석은 sudo 권한이 있는 사실상의 루트라고 보면된다. 다만 루트(root)계정과 다른점은 sudo를 쳐야한다는 귀차니즘 정도? 어쨌든 루트 계정은 아니니까 보안 면에서는 일단 안심! 기존에 Cafe24 가상 서버를 사용할땐 어짜피 나 혼자 쓰는 서버고 또 다른 계정을 만드는 것도 귀찮아서 그냥 root로 접속해왔는데, 그때 무차별 패스워드 대입 공격(BruteForce)에 한번 털린 적이 있어서 Fail2ban도 걸어보고 별짓을 다 해봤던거 같다. 애초에 패스워드 접속을 막고 공개키로만 접속했다면 털리는 일은 없었을텐데… 하는 아쉬움을 뒤로하고 어찌됐든 AWS는 ec2-user라는 계정을 기본으로 생성해준다. 그래서 일단 요걸로 당분간 쓰고 필요할때 루트로 작업하는 걸로… 정리

리눅스를 설치하면 기본적으로 root와 더불어 wheel이 라는든가 demon, staff, bin, sshd, ftp 등등 그리고 apache라는 계정은 자동으로 만들어 주는지 어쨌는지는 모르겠지만 암튼 여러 계정을 자동으로 생성해준다. 어떤 계정들이 있는지 확인을 위해서는 /etc/passwd 파일을 확인해보면 된다.

$> cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
....
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
ec2-user:x:500:500:EC2 Default User:/home/ec2-user:/bin/bash
nginx:x:498:498:Nginx web server:/var/lib/nginx:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
....

보통 계정이 생성된 순서대로 기록되기 때문에 ec2-user 까지가 아마도 EC2 인스턴스를 만들면 자동으로 생성해주는게 아닐까 생각된다. 처음에 인스턴스 생성하고 확인해보지 않아서 정확히는 모르겠지만 그럴 가능성이 99.9% 일듯… 참고로 adduser 라는 명령으로 특별한 옵션없이 계정을 생성하면 생성된 계정의 ID는 500번 이후의 번호를 할당받는데, ec2-user가 500인걸로 봐서는 기본 셋팅후 가장먼저 생성한 계정이 아닐까 싶다. 그리고 ec2-user 이후로는 내가 설치한 프로그램의 돌아갈때 필요한 권한을 얻기 위해 자동으로 생성된 녀석이다.

그나저나 난 apache를 깐 기억이 없는데,.. 저 계정은 언제 생성된거징? 리눅스 설치하면 자동으로 생성되는건가? 아시는 분?? 댓글좀… 굽씬굽씬~

5. 계정과 프로세스 그리고 파일 및 폴더 소유자

그동안 리눅스 서버를 만지작 거리면서 계정은 서버에 접근하기 위한 일종의 로그인 유저, 그 이상 그 이하도 아니라서 크게 신경쓰지 않았다! 하지만 이 계정이 참 중요하다는 사실을 nginx에 워드프레스를 깔면서 새삼 실감했다. 어쩜 “개발자라면서 그건 기본인데 그것도 몰랐냐?” 할수도 있지만… 그래요 전 몰랐어요 흑흑… 지금이라도 알아서 참 다행이야!! 아는게 중요한게 아니라 제대로 이해했다는게 중요!!

일단 리눅스에서 프로그램을 실행시키면 누가 그 프로그램을 실행시켰는지 ps 명령어를 통해 알수있다.

$> ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 Oct13 ?        00:00:01 /sbin/init
root         2     0  0 Oct13 ?        00:00:00 [kthreadd]
root         3     2  0 Oct13 ?        00:00:01 [ksoftirqd/0]
... 
mysql      447 32720  0 Nov03 ?        00:01:04 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysq
root       473     2  0 Oct13 ?        00:00:00 [md]
root       598     2  0 Oct13 ?        00:00:00 [khungtaskd]
... 

ps -ef 라는 명령을 치면 엄청 많이 나오기 때문에 필요한 것들만 필터해서 찾을수있는데 이때 grep를 사용하면 된다. grep는 정규식을 의미한다는건 참고로 알아두자!

$> ps -ef | grep nginx
nginx    17077 17075  0 Nov04 ?        00:00:05 php-fpm: pool www
nginx    17078 17075  0 Nov04 ?        00:00:05 php-fpm: pool www
...
root     26088     1  0 06:18 ?        00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    26090 26088  0 06:18 ?        00:00:00 nginx: worker process
nginx    26400 17075  0 07:04 ?        00:00:00 php-fpm: pool www
ec2-user 26785 26605  0 09:06 pts/0    00:00:00 grep nginx

여기서 보면 nginx의 마스터 프로세스는 root가 실행시켰다. 그리고 실제로 동작하는 워크 프로세스는 nginx 라는 계정으로 실행됐다. 서버가 실행중에 항상 떠있는 데몬을 띄우기 위해서는 service 라는 명령을 이용해 프로그램을 실행시키는 경우가 있는데 service 명령은 ec2-user 계정으로는 권한이 없어서 실행이 안된다. 따라서 sudo를 사용하거나 root로 로그인 해야한다.

ec2-user $> sudo service nginx start
ec2-user $> sudo su
root $> service nginx start

암튼 이렇게 데몬으로 서비스되는 녀석들은 루트가 실행하고 실제 프로그램이 동작할때는 루트 권한을 주면 안되기 때문에 워커 프로세스에는 다른 권한으로 동작시키는 것 같다. 그래서 nginx 라는 계정이 nginx를 설치할때 자동으로 생성되고 이 계정으로 실제 nginx가 실행된다.

여기서 엔진엑스 서버가 nginx 계정으로 실행되는게 매우 중요한데 그 이유는 바로 워드프레스 때문이다. 워드프레스는 테마나 플러그인을 자동으로 다운받고 설치하는데 이때 다운받고 설치하는 일을 엔진엑스 프로세스가 하기 때문에 프로세스의 권한으로 파일을 생성하고 소유하게 된다.

아직 쓸 얘기가 많은데.. 오늘은 너무 많이 써서… 일단 내일 다시 To be continues….