티스토리 뷰

  • 글 시작 전

1. 본문에서 AWS EC2+Nginx 서버 설치/설정에 있어 서버 내 백엔드 기술의 사용조합은 다음과 같습니다 :

  • 배포서버 : AWS EC2 t2.micro

  • Ubuntu 16.04

  • Nginx 1.17.3

  • RVM 1.29.10

  • Database : PostgreSQL
  • ruby 2.6.3 (Rails 프로젝트와 AWS EC2와 동일)

  • rails 5.2.4.2 (Rails 프로젝트와 AWS EC2와 동일)

 참고  버전을 떠나서 AWS EC2 및 RVM 사용, Ubuntu OS 사용을 한다는 조건만 맞으면 됩니다.

 

2. 해당 본문을 읽기 전, 기본적인 Ruby on Rails 프로젝트가 준비되어 있어야 합니다.

 

3. 해당 글은 웬만하면 Nginx 개념을 익히기 위한 목적으로 활용해주세요. Nginx를 활용한 자동배포(CD) 기능을 통해 더욱 편리하게 Ruby on Rails 프로젝트를 배포할 수 있습니다.

 부록  AWS EC2+Nginx+Capistrano 지속적(자동) 배포

 

4. AWS 기초개념 및 회원가입 과정은 생략합니다.

 

 

  • 목차

  1. 글 시작 전(Intro)

  2. c10k Problem

  3. 그래서 Nginx을 왜 써야 하는가?

  4. Apache와 Nginx의 차이는?

  5. [글 시작 전] 어떻게 배포하실레요?

  6. Chapter 1 : AWS EC2 설정 / AWS EC2 서버 접근

  7. Chapter 2 : AWS EC2에서 루비/레일즈 환경, 서버환경 설치하기

  8. Chapter 3 : PostgreSQL 계정 및 데이터베이스 생성

  9. Chapter 4 : Ruby on Rails 데이터베이스 설정

  10. Chapter 5 : Secret Key 파일 확인

  11. Chapter 6 : Ruby on Rails DB 작업

  12. Chapter 7 : Nginx 설치 사전준비

  13. Chapter 8 : Nginx 설치

  14. 추가 설정 : Nginx 부가설정

  15. 참고 : Nginx 로그파일 확인

  16. 참고 : Public 폴더 내 파일들이 안불러와지는 현상

  17. 참고 : EC2에서 고정IP 사용법

  18. 자료 참고

 

 
  • 글 시작 전

사실 과거에 Rails에서 기본으로 제공하는 Puma 엔진을 기반으로 서버 배포를 하는 법에 대해 글을 쓰긴 했지만, 해당 글은 미흡하다고 여겨져서 비공개 처리를 했습니다.

 

나중에 깨닫고 보니 Rails에 기본으로 내장되어 있는 Puma 엔진 만으로는 Rails 웹페이지를 유지하기에는 한계가 있다고 느껴셔입니다.

Rails에서 기본으로 제공하는 Puma 엔진

Ruby on Rails은 기본적으로 PHP와 같이 서버엔진을 따로 깔지 않아도 된다는 장점이 있습니다.

하지만 이 장점이 미래를 바라보면 썩 좋은 장점은 아니었습니다.

 

왜 Puma 엔진이 미흡하다고 여겨졌는지 이번 글을 통해 이야기를 풀어보겠습니다.

 

 
  • c10k Problem

글을 시작하기전에 앞서, c10k 문제에 대해 언급을 하고 시작해보고자 합니다.

 

서버는 동시접속자가 많으면 많을수록 과부화가 되고, 치명적입니다.

이를테면 1월 1일 00시에 서로 새해 인사를 나눈다고 카카오톡을 사용하다보니 사용자가 급증하면서 카카오톡이 느리게 응답하거나, 죽어버리는 사례를 볼 수 있습니다.

* 카카오가 c10k 문제에 대해 대처를 안했다는건 절대 아닙니다.

 

잠시 옛날로 돌아가서, 초기에 네트워크 설계에 있어 현재보다 인터넷 문화가 발전하지 않았다보니 네트워크 소켓을 통해 최대로 커버 가능한 동시접속자의 작업 수는 1만개였습니다.

이 때 당시에는 사용자 수 = 프로세스 갯수 혹은 쓰레드 갯수 로 따져가며 서버 인프라가 설계되었다 보니 많은 CPU, 메모리 자원이 활용되던 시절이었습니다.

 

하지만 요즘은 인터넷 문화가 많이 발전했다보니, 동시접속자 수가 점점 늘어나고 있는 상황입니다.

덕분에 동시접속자가 늘어날 수록, 사용자들이 동시다발적으로 I/O 작업을 많이 하다보니 사용자들이 사용하는 서버의 자원은 점점 늘어나게 되고, 서버는 수많은 동시다발적 처리에 대한 I/O 처리를 견디다 못해 결국 죽어버리곤 하는데, 이러한 현상을 c10k Problem 이라고 합니다.

 

결국 c10k Problem 은 서버의 하드웨어적 문제, OS의 처리능력 한계, 내부 작업 프로세스 등 복합적인 원인으로 인해 탄생된 현상입니다.

 

 
  • 그래서 Nginx을 왜 써야 하는가?

효율적인 서버 자원(CPU, 메모리 등) 사용

1. Nginx 개요

다시 Nginx돌아와서, c10k Problem 문제의 해결법 중 하나로 제시된게 바로 Nginx를 활용하는 방법입니다.

과거 서버 통신방식 (bloking 방식)

과거 *멀티쓰레드를 사용하던 시절에는 위와같이 Bloking I/O 방식으로 처리가 이루어지곤 했었습니다.

Blocking I/O 방식은 뭔가 프로세스에 대한 처리를 하려고 하는데, 이미 다른 프로세스가 자리를 차지하고 있다면 이 전 프로세스가 작업이 끝날 때 까지 기다려야 함을 의미합니다.

* 멀티쓰레드 : 하나의 프로그램에 동시에 여러 작업을 돌리는 작업으로서, 프로세스 하나의 자원을 공유하다보니 처리속도가 빠르다는 장점이 있지만, 한정된 프로세스 자원을 쪼개서 사용하는 만큼, 스레드별로 자원을 효율적으로 분배해줘야 한다.

 

Apache의 요청/응답에 있어 서버 자원(Process, Thread) 활용방식 [Prefork, worker 방식; 후술에 내용 자세히 설명]

하지만 이러한 작업은 동시다발적으로 들어오는 작업에 있어서는 부적합했습니다.

또한 위 사진과 같이 요청에 따라 쓰레드/프로세스가 무한대로 생겨나다보니 요청이 많을수록 작업 처리 방식이 무겁고, 오랜 시간이 소요되는 작업에도 역시 문제가 있었습니다.

Blocking에 있어선 딱 위 그림과 같이 좋은 비유가 아닐 수가 없다. (4번 박스를 요청하는 유저로 인해 그 뒤의 손님들은 아무것도 못하고 대기해야 한다.) [출처 : Nginx 공식사이트]

위와같이 길고 무거운 작업이 만약에 서버에 요청된다면 해당 작업이 처리될 때 까지 결국 다른 요청은 아무것도 못하고 대기해야 하는 문제점이 있었습니다. 

 

그래서 나오게 된 방법론이 Non-blocking 방법론입니다.

non-blocking 방식의 작업처리 [출처 : Nginx 공식사이트]

과거의 Blocking 방식과 다르게, Non-Blocking 방식은 앞의 프로세스가 작업을 수행중이더라도, 후의 프로세스는 기다리면서 다른 작업을 해낼 수 있습니다. (아주 기초적인 예시로 이를테면 카페에서 커피를 주문하고 진동벨이 울릴 때 까지 화장실을 다녀온다던지 등..)

 

Nginx은 이런 Non-Bloking 방식을 채택했습니다.

 

 

2. Nginx가 작동되는 과정

Nginx가 돌아가는 방식 [출처 : Nginx 공식사이트]

전체적으로 Nginx가 돌아가는 과정은 위와 같습니다.

Nginx가 돌아가는 원리를 담은 위의 과정을 아래에 나름대로 해석을 해봤습니다.

 

Nginx 작업 Step 1

 

Nginx은 위 사진과 같이 보이는 것과 같이 서버가 켜지면(start) 사전에 서버개발자가 정한 쓰레드 갯수를 생성하고(Thread  Pool), 해당 스레드 풀 내에 가진 한정된 자원(쓰레드풀)만을 가지고 HTTP 요청에 대한 작업을 처리합니다.

 

단, 쓰레드를 생성함에 있어 너무 적거나 너무 많이 생성하지 않는걸 추천합니다.

  • Thread가 너무 적을 경우, 작업을 처리함에 있어 Thread가 빈번하게 부족한 현상이 발생할 것입니다.
  • Thread가 너무 많을 경우, 놀고있는(IDLE) Thread가 발생하게 되고 이는 자원의 낭비입니다.
프로세스 : 실행 프로그램
쓰레드 : 프로세스를 running 시키는 작업 단위

 

Nginx 작업 Step 2

 

Nginx와 함께 돌아가고 있는 Worker Process

그리고 요청에 대한 응답은 Nginx 내부에서 실행되고 있는 Worker Process에서 진행됩니다.

여기서, Worker Process는 개발자가 따로 설정을 하지 않았다면, CPU 특성에 맞게 자동으로 Worker Process 갯수가 생성됩니다. (저는 1개가 생성되어 있었습니다.)

 

그런데 만약 이 설정을 변경함에 앞서 한 가지 유의사항이 있다면 단순히 '많으면 좋겠지' 하는 마음으로 변경을 생각한다면 이는 비추천합니다. 하드웨어 성능을 고려하지 않고 단순히 늘릴 경우 오히려 퍼포먼스가 떨어질 수 있다는 얘기가 있습니다.

 부록  [Nginx] Worker Process

 

Nginx 작업 Step 3

Nginx는 Event Driven의 특성을 가지고 있습니다. 그리고 Event Driven은 Event Loop 기반으로 요청에 대한 작업을 처리합니다. 하지만 이 요청을 처리함에 있어 한가지 특징이 있는데, 위 사진 속 요청에 있어 A→BCD 요청 순으로 작업이 진행된다 할 때, B 작업은 A 작업이 끝날 때 까지 기다리지 않는다 라는 특징이 존재합니다. 이는 Event Loop 에서 작업이 처리됨에 있어, 비동기 방식으로 작업이 돌아가기 때문입니다.


Nginx Event Driven 내에서 어떻게 작업이 되는지 제 나름대로 해석을 해봤습니다. :

  1. Nginx는 요청에 대한 작업을 처리할 때, 스레드가 직접적으로 작업을 하진 않고 이 작업들을 '이벤트 핸들러' 라는 곳으로 보냅니다.

  2. 이벤트 핸들러에서 작업을 마치게 되면 먼저 작업이 완료된 순서되로 Queue에 쌓이게 됩니다.

  3. 매번 Event Loop은 Queue를 체크하면서 완료된 작업이 있는지 체크합니다. 이를 통해 CPU는 최대한 IDLE 상태가 아닌채로 활동합니다. 일해라 CPU

  4. Queue에 완료된 작업이 있을 경우 이를 클라이언트에게 응답(Response 합니다.)

 부록 
[Youtube] Evnet Driven은 어떠한 원리로 동작이 될까?
비동기 방식을 통해 Single Thread를 처리하는 과정 (이벤트 루프에 대한 설명)
[JavaScript] EventLoop와 비동기 동작

 

Nginx 작업 Step 4

Queue에 있는 완료된 작업을 받아내어 이를 클라이언트에게 응답(Response) 합니다.

 

Nginx 작업 Step 마무리

나름대로 최대한 이해하고 써봤는데, 미숙한 부분이 있을수도 있습니다. 혹시 내용이 부족하거나 잘못 쓴 부분이 있다 싶으면 댓글로 제보주시면 감사하겠습니다.

 

 

3. Nginx와 Puma간 메모리 퍼포먼스의 차이

 

[좌측] Nginx를 이용한 서버 오픈 / [우측] Puma 엔진을 이용한 서버 오픈

아주 기본적인 Rails 프로젝트 상태에서 Nginx와 Puma를 통해 서버를 켰다 했을 때, 메모리 사용량을 비교해 봐도 메모리 사용량이 2배 가량 차이가 납니다.

 


Nginx의 Thread, CPU/메모리 활용에 대해 일상생활 비유로 정리

 

비행기에는 기본적으로 승객과 승무원이 존재합니다. 여기서 승객은 비행 중, 필요한 사항(간식 요청, 면세품 구입, 담요 요청 등)이 있을 시 승무원을 호출합니다.

  • 승무원을 호출하는 승객  클라이언트에서 서버에게 보내는 요청

  • 승무원  요청을 처리하는 프로세스 혹은 쓰레드

위와같은 개념으로 나름의 Apache와 Nginx의 설명을 이어보겠습니다.

 

1) Apache

 실제 서버 내에서 작업 

하나의 요청 당 서버에서는 하나의 프로세스(혹은 쓰레드)를 다룹니다. 하지만 서버 내 CPU/메모리는 한정적임에 반해 프로세스(쓰레드)는 요청이 들어온 만큼 계속적으로 생성/작업을 하다보니 무리한 작업으로 인해 서버가 뻗어나갈 수 있습니다.

 

 일상생활 비유(항공) 

정규 비행 예약량을 기준으로 볼 때 승객 한명 당, 승무원 한명이 배치된다고 보면 됩니다. 하지만 이는 항공사에서도 비효율적인 운영방식이고, 또한 항공사 입장에서도 승무원 고용에 있어 수많은 비용이 들 것입니다.

어찌어찌해서 정규 비행 예약 기준으로 손님 1명 당 승무원 1명이 배치되었다고 치지만, 오버부킹으로 인해 손님 >= 승무원이 되어버린다면?...

 

2) Nginx

 실제 서버 내에서 작업 

서버가 실행되면 일단 사전에 쓰레드를 생성해냅니다. (몇개를 설정할 지는 서버개발자 마음)

그리고 클라이언트로 부터 요청이 들어오면 일단 서버에서는 사전에 만들어진 한정된 쓰레드 갯수를 기반으로 요청에 대해 처리합니다.

그러나 요청 >= 쓰레드일 경우, 뒤늦게 들어온 요청은 잠시 큐에 대기 및 앞의 요청에 대해 처리를 끝낸 쓰레드는 큐에 대기하고 있는 요청이 있는지 확인 후, 아직 처리되지않은 요청이 있을 경우 이를 또 처리합니다. (남은 요청이 있는지에 대해서는 Event Loop가 항상 체크합니다.)

 

 일상생활 비유(항공) 

사전에 승무원 수를 5명으로 지정해서 비행기에 탑승을 시킵니다. 그리고 승무원들이 일을 하는 스타일은 센스를 발휘해서 FIFO 순서로 일을 진행하지는 않고, 빨리 끝날 것 같은 일 부터 먼저 진행을 합니다.

 

비행기에서 승객으로부터 호출이 하나 둘 들어오고, 승무원은 이를 해결합니다.

5명의 승무원이 사전에 승객으로부터 받은 부탁을 처리를 위해 비행기 내부를 이리저리 도라다니는 도중, 다른 승객이 '저기요~' 하면서 승무원을 부르면서 추가적인 부탁을 합니다. 그런데 중간에 호출 및 추가적으로 받은 부탁이 이전에 받은 요청보다 일찍 끝날 것 같다 싶으면 빨리 끝나는 일을 능동적으로 먼저 해결합니다.

 

 

보안 취약점 대비 가능

클라이언트에서 서버에 접근함에 있어, Rails Project에 접근하기 전, 그 앞단에 존재하는 Nginx을 바라보게 됩니다.

 

이를 통해 Nginx에서 보안적으로도 다양한 대비를 할 수 있습니다.

서버에서 발생할 수 있는 다양한 취약점(XSS을 이용한 세션 하이잭킹 등)에 대한 보안 대비를 할 수 있습니다. (IP Blacklist 추가 등등)

 

 

  • Apache와 Nginx의 차이는?

웹 서버 엔진의 양대산맥이라 불리는 Apach와 Nginx에 대해 알아보겠습니다.

 

1. Apache

1995년 부터 웹서버 기반으로서 사용되고 있는 서버엔진입니다.

아파치는 Prefork와 Worker 방식으로 돌아가고 있는데 각각의 방식에 대해 설명해보도록 하겠습니다.

 

1) Prefork

Apache : Prefork

프로세스를 아예 다중적으로 복사하여 사용하는 방식입니다. 하나의 요청 당 하나의 프로세스로 처리가 이루어지며, 요청량이 많아질수록 프로세스는 증가하지만 복제시 메모리영역까지 복제되어 동작하므로 메모리를 많이 사용하게 된다는 단점이 존재합니다.

 

2) Worker

Apache : worker

과거 Prefork 방식과 다르게 Request >= Process 구조로 이루어져 있는 Worker 방식입니다. 

쓰레드 특성 상 프로세스 내의 Memory를 공유한다는 장점 덕분에 Preworker보다 메모리 자원을 덜 쓰면서도 작업이 수행된다는 장점이 존재합니다.

 

 

  Apache 정리

 

  1. 1995년에 나온 서버엔진으로서, 지금까지도 많은 인기를 누리고 있음.

  2. Process가 Blocking 시, 프로세스 작업이 끝날 때 까지 대기해야 한다.

  3. 주로 요청 하나당 프로세스(혹은 쓰레드) 하나가 쓰이는 방식이다.

  4. 자원(CPU, 메모리 등) 사용이 유동적 (요청에 따라 쓰레드, 프로세스 할당갯수가 증감됨.)

  5. 서버 내 자원(CPU, 메모리 등) 활용이 비효율적이다.

 

 

2. Nginx

2007년에 오픈소스로 공개되어 점점 많은 인기를 얻어가고있는 엔진입니다.

초반에 언급했다 싶이 Apache의 무리한 자원 활용을 완화하여 탄생하게 된 엔진입니다.

Nginx와 일반적인 서버의 구동 방식

위 사진과 같이 프로세스를 효율적으로 활용함으로서 서버 자원을 최대로 활용해나갔고, Event Driven을 활용한 비동기 Non-Blocking 방식을 선호함으로서 프로세스 작업이 끝날 때 까지 대기하지 않아도 된다는 장점도 있습니다.  

 

 

  Nginx 정리

 

  1. 2007년에 탄생

  2. Event Driven방식의 웹 서버 : 이 덕분에 비동기 Non-Blocking 방식 특징을 활용 가능

  3. 싱글스레드의 활용 → 적은 메모리 사용

  4. 자원(CPU, 메모리 등) 사용이 고정적 (싱글스레드)

  5. 대용량 트래픽(수많은 동시접속자) 처리에 있어 요즘 떠오르는 대안

 

 

 
  • 어떻게 배포하실레요?

배포방법은 앞으로 해당 글에서 밝힐 기본적인 Nginx+AWS EC2를 활용한 서비스 배포법과 Nginx+AWS EC2+Capistrano를 활용한 배포법 크게 두가지로 나뉘게 됩니다.

 

Capistrano는 CD(Continuous Delivery) 기법으로 사용되는 Gem으로서, 터미널에 명령어 한 줄만으로 자동으로 Remote서버(AWS EC2)에 배포부터 서버 셋팅까지 모든게 이루어집니다.

 

미래를 생각한다면 해당 본문의 방법을 따르는 것 보단 Nginx+AWS EC2+Capistrano 방법론으로 서비스를 배포하는걸 추천드립니다.

* 만약 운영서버(AWS EC2) 코드가 수정이 되었을 경우, AWS EC2 터미널에서 수동으로 Nginx 서버를 restart를 해줘야 하는 귀찮음이 있는 반면, Capistrano는 이를 자동으로 해줍니다.

 

해당 본문에 대해서는 Nginx의 중요성에 대한 액기스만 뽑아갈 것을 권유드립니다.

 

  1. Nginx+AWS EC2+Capistrano를 활용한 자동배포

  2. Nginx+AWS EC2를 활용한 배포 :  Chapter 1  로 넘어가주세요.


서론이 너무 길었네요...

이제 본론으로 돌아와서, Ruby on Rails에 Nginx을 설치해보는 과정을 알아보겠습니다.

 
  •  Chapter 1  AWS EC2 설정 / AWS EC2 서버 접근

AWS EC2 인스턴스를 설정하는법에 대해 알아보겠습니다.

 

1. AWS 상단보이는 서비스 를 클릭 후, EC2 서비스로 이동합니다.

 

2.  인스턴스 시작  버튼을 클릭합니다.

 

3. 인스턴스 셋팅을 합니다.

1) 운영체제는 Ubuntu 16.04로 합니다.

 참고  Ubuntu 18.04로 해보려 했으나, 오류가 발생해서 포기했습니다.

2) 인스턴스 유형은 여러분 서버 요구사항에 맞는걸로 선택합니다. (저는 무난하게 t2.micro로 해보겠습니다.)

 참고  AWS는 계정을 새로 만든 날로 부터 1년동안 프리티어 혜택을 받을 수 있는데, 프리티어 혜택에 있어 EC2 서비스는 750시간만 넘기지 않으면 무료입니다. [프리티어 혜택 살펴보기]

3) 그리고 하단 아래에 보이는  검토 및 시작  버튼을 클릭해주세요.

 

4)  검토 및 시작  버튼을 클릭 후, 다시 하단의  이전  버튼을 클릭해서 이전 메뉴로 이동합니다.

 

5) 보안 그룹, 즉 인바운드를 설정합니다.

저희는 여기서 기본적으로 HTTP 웹 포트인 80번 포트를 열어줘야 합니다.

 참고  https 보안을 사용할 경우, 443 포트도 열어주세요.

 

6) 우측 하단의  검토 및 시작  버튼 누르고, 이어서  시작하기  클릭

 

7) 키 페어라 해서, 내 서버 접근 때 필요한 열쇠라고 보시면 됩니다.

Pem키를 생성 및 지정 후,  키 페어 다운로드  및  인스턴스 시작  버튼을 눌러주세요.

 주의  Pem키는 분실하면 큰일나요! 꼭 잘 가지고 있으세요.

 

8) 약 1분뒤에 인스턴스가 생성이 완료된게 확인해볼 수 있습니다.

 

4. 인스턴스를 생성후, IPv4 퍼블릭 IP 를 기억해두세요.

 

5. 윈도우 사용자들은 cmd를, 맥북 사용자들은 터미널을 킵니다.

 

6. cmd/터미널에 다음 명령어를 입력해주세요.

1) AWS Key Pair 파일에 대해 권한을 400로 설정합니다.

# chmod 400 "[Pem Key 파일경로]"
chmod 400 "C:\Users\KCM\Desktop\ruby-kcm.pem"

 

2) 내 AWS 서버에 접속을 합니다.

# ssh -i "[AWS Pem Key 위치]" -o TCPKeepAlive=true ubuntu@[IPv4 주소]
ssh -i "C:\Users\KCM\Desktop\ruby-kcm.pem" -o TCPKeepAlive=true ubuntu@13.125.114.95

 

7. 아래와 같이 내 Ubuntu 서버에 접속이 되면 성공입니다.

 

 
  •  Chapter 2  AWS EC2에서 루비/레일즈 환경, PostgreSQL 설치하기

 참고  AWS EC2에서 해당 과정을 진행해주세요.

 

1. Ruby 설치를 위한 RVM 패키지 설치

\curl -sSL https://get.rvm.io | bash

 

2. RVM 설치가 끝나면 RVM 설정 초기화를 진행합니다.

 

설치가 끝나면 To start using RVM you need to run `source /etc/profile.d/rvm.sh` 와 같은

다음과 같은 글자를 볼 수 있는데, 문구에서 설명하는 그대로 터미널에 다음 내용을 입력.

source /home/ubuntu/.rvm/scripts/rvm

 

3. RVM 패키지 설치 후, Ruby를 자신의 로컬PC(로컬서버) 프로젝트 버전에 맞게 설치.

(해당 예시에서는 2.6.3 으로 설치하겠습니다.)

# rvm install [버전]
rvm install 2.6.3

 

4. Ruby를 설치 후, Ruby on Rails 로컬PC(로컬서버) 프로젝트에 맞는 Rails 버전 설치

# gem install rails --version=[Rails 버전]
gem install rails --version=5.2.4.2

 

5. Github에 있는 Rails 프로젝트를 끌어오세요.

# git clone [EC2에 가져올 Github 프로젝트 주소]
git clone https://github.com/kbs4674/project-BE

 

6. 현재 디렉터리 위치에서 내 프로젝트 디렉터리로 이동

# cd [프로젝트 이름]
cd project-BE

 

7. 터미널에 아래 명령어를 입력해서 Gem을 설치해주세요.

bundle install

 참고  Bundler 에러 발생시

저 같은 경우는 터미널에서 지시한 대로 bundler 버전을 업그레이드 해서 설치했습니다.

gem install bundler:2.0.2

 

8. 해당 프로젝트는 초반에 명시되었다 싶이 Database는 PostgreSQL을 사용한다는 전제로 설치가 진행됩니다.

pg(PostgreSQL) Gem이 있는 상태에서 바로 Gem을 설치하려 하면 다음과 같은 오류가 발생합니다.

위 오류를 방지하고자 PostgreSQL 패키지를 설치합니다.

sudo apt-get update
sudo apt-get -y install libpq-dev
sudo apt-get -y install postgresql postgresql-contrib

 

9. 프로젝트 내에서 Gemfile에 명시된 Gem 설치

bundle install

 

10. Rails은 일부 기능에 있어( assets/javascript  컴파일 등) Node.js 기반으로 수행되는 웹프레임워크입니다.

Node.js 없이 실행할 경우, 일부 기능 및 명령어(rake 등)에서 다음과 같은 에러가 발생합니다.

 참고  javascript runtime에 있어선 execjs(or nodejs) 활용이 좋으면서도 가볍다.

에러 방지 및 원할한 Rails를 실행시키기 위해 Node.js 모듈을 설치합니다.

sudo apt-get -y install nodejs

 

 
  •  Chapter 3  PostgreSQL 계정 및 데이터베이스 생성

 참고  AWS EC2에서 해당 과정을 진행해주세요.

 

다음은 데이터베이스 생성 및 설정에 대한 안내입니다.

 

1. 터미널에서 다음 명령어를 입력해서 PostgreSQL 커멘터에 접속합니다.

sudo -u postgres psql

 

2. DB를 제어할 유저에 대한 계정을 생성합니다.

 참고1  계정명암호는 여러분들 특성에 맞게 입력해주세요.

# create role [계정명] login password '[암호]' superuser;
create role admin login password '123456' superuser;

 참고2  계정 암호 변경

# ALTER USER [계정명] WITH PASSWORD '[암호]';
ALTER USER [계정명] WITH PASSWORD '654321';

 참고3  데이터베이스 연결 확인

## DB 연결 확인 명령어는 일반 터미널에서 입력해야 합니다.
## ubuntu@ip-×××-××-××-×××:~/project$

# psql -U [계정명] -d [DB 이름] -W -h localhost
psql -U admin -d kcm_dev -W -h localhost
  • -U : username
  • -d : database name
  • -W : password 사용
  • -h: 연결할 호스트. 제외할 경우 "peer authentication failed" 에러 발생 가능

 참고4  데이터베이스 삭제

# DROP DATABASE [데이터베이스 이름];
DROP DATABASE kcm_dev;

 

3. 계정 및 데이터베이스 생성이 끝났다면,  Ctrl + D  를 눌러서 PostgreSQL 콘솔에서 나가주세요.

 

 
  •  Chapter 4  Ruby on Rails 데이터베이스 설정

 참고  해당 작업은 로컬PC(로컬서버) 프로젝트에서 진행해주세요.

 

1. 환경변수를 설치하고자  Gemfile  로 이동 후, 다음 내용을 입력해주세요.

gem 'figaro'

그리고 터미널에 다음 명령어를 입력해서 Gem을 설치합니다.

bundle install

 참고  Gem dependency 에러가 날 경우

해당 에러는 Figaro 때문에 발생하는 에러입니다.

에러의 해결방법은 Gem을 Update 시켜주면 되나, 전체적으로 다 Update를 하지말고 최소한의 Gem에 대해서만 업데이트를 해주는 것이 좋습니다.

최소 Dependency 끼리간의 Update를 진행하는 명령어는 아래와 같습니다.

bundle update --conservative

 

2.  config/database.yml  파일을 열람 후, 다음과같이 수정해주세요.

 참고  Database은 Environment에 따라 분리 시켜주는게 가장 좋습니다. 

## config/database.yml
## Database은 Environment에 따라 분리 시켜서 해주는게 가장 좋습니다.

#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: postgresql
  host: localhost
  encoding: utf8
  username: <%= ENV["DB_USER_NAME"] %>
  password: <%= ENV["DB_USER_PASSWD"] %>
  pool: 5

development:
  <<: *default
  database: <%= ENV["DB_NAME"] %>_<%= Rails.env %>

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: <%= ENV["DB_NAME"] %>_<%= Rails.env %>

production:
  <<: *default
  database: <%= ENV["DB_NAME"] %>_<%= Rails.env %>

 

3. config 폴더 속에  application.yml  파일을 새로 만들어 낸 후, 다음 내용을 입력해주세요.

 참고  아래 내용의 dev, admin, 123456은 제 기준으로 작성한겁니다. 여러분들 기준에 맞게 작성해주세요.

## [로컬 프로젝트] config/application.yml

DB_NAME: "kcm"
DB_USER_NAME: "admin"
DB_USER_PASSWD: "123456"

 

4. app, config 등 폴더가 위치한 Rails 프로젝트의 루트폴더 위치에서  .gitignore  파일을 생성 후, application.yml 파일이 Push가 안되도록 방지해줍니다.

## .gitignore

/config/application.yml

 

5.  .gitignore  이 제대로 적용되지 않을 것을 대비해, Git Cache를 제거해줍니다.

git rm -r --cached .

 

6. 지금까지의 작업을 Github로 push 합니다.

git add .
git commit -m "database.yml 설정 변경"
git push origin master

 

7. AWS EC2로 돌아와서, Github에 최신버전으로 되어있는 커밋을 불러옵니다.

git pull origin master

 

8. Git Pull 후, AWS EC2에 존재하는 Rails 프로젝트에 Gem을 최신화 해주세요.

bundle install

 

9. 하지만  .gitignore  로 인해 pull을 하면서  config/application.yml  파일을 오지 않았습니다.

AWS EC2에서 config 폴더에  application.yml  파일을 생성 후, 3번과정과 동일하게 내용을 입력해주세요.

## [AWS EC2] config/application.yml

DB_NAME: "kcm"
USER_NAME: "admin"
USER_PASSWD: "123456"

 

 
  •  Chapter 5  Secret Key 파일 확인

 참고1  AWS EC2에서 해당 과정을 진행해주세요.

 참고2  해당 내용은 Rails 5.2 버전 이상부터 해당되는 이야기입니다.

 

AWS EC2 서버에서 config 폴더에 보면 github로 부터 받지 못한 파일이 하나 있습니다.

Rails 파일이 생성이 되면 자동으로  .gitignore  파일이 생성됨과 동시에  .gitignore  파일에는 /config/master.key 파일이 Github에 Push되지 않도록 설정되어 있습니다.

 

레일즈 프로젝트는 암호화 인증 방식으로서 config/credentials.yml.enc 파일과, 이를 해독하는 config/master.key 파일 두가지로 짝지어져 있는 형태입니다.

 

key 파일은 보통  rails new  명령어를 통해 프로젝트를 생성하면 자동으로 생성되며, 레일즈 프로젝트에 있어 하나의 암호화 인증서 같은 개념입니다.

사실 이러한 인증 기법은 5.1 버전에서 부터 시작되어 왔으나, 5.2버전에는 인증방식 조금 변화가 생겼습니다.
 부록 
Ruby on Rails : Credentials

알 수 없는 난수로 이루어져 있는 credentials.yml.enc 파일

아래 명령어를 입력하면, 위와같이 난수로 이루어져있는  config/credentials.yml.enc  파일을 복호화 해서 내용을 살펴볼 수 있습니다.

EDITOR=vi rails credentials:edit

좌 : 복호화 된 credentials.yml.enc / 우 : credentials.yml.enc에 등록된 환경변수 조회하기

더 나아가, 이 기능을 이용해서 Figaro Gem을 대체하여 환경변수로서도 쓰일 수 있습니다.

 

하지만 배포 전 작업에 있어 위 2개의 인증파일(credentials.yml.enc, master.key)이 존재하지 않을 경우, 배포가 안되는 문제가 발생합니다.

 

1. AWS EC2로 프로젝트 배포 전,  config/credentials.yml.enc  파일에 변수 설정을 했을 경우, 로컬 프로젝트에 있는  config/master.key  파일을 AWS EC2 프로젝트로 Copy & Paste를 해주세요.

그리고  Chapter 6  로 넘어가면 됩니다.

 

2. 만약 AWS EC2로 프로젝트 배포 전,  config/credentials.yml.enc  파일에 어떠한 설정도 진행하지 않았을 경우 다음과같이 진행해주면 될 것 같습니다.

 

1) 혹시 2개 중 하나의 key 파일이 존재할 것을 대비해, 일단 깨끗이 삭제를 합니다.

rm config/credentials.yml.enc
rm config/master.key

 

2) 새로운 Key 파일을 생성합니다.

EDITOR="mate --wait" rails credentials:edit

그럼 새로운 key 파일이 생성된게 확인될 겁니다.

3)  Chapter 6  로 넘어가서 다음 과정을 진행해주세요.

 

 
  •  Chapter 6  Ruby on Rails DB 작업

 참고  AWS EC2에서 해당 과정을 진행해주세요.

사전 셋팅이 끝났으니, 본격적으로 서버를 열기위한 과정을 따져보겠습니다.

 

1. production 환경을 특정지어 database.yml에 등록한 dataabase 이름을 기반으로 DB를 생성합니다.

RAILS_ENV=production rake db:create

 

2. production 환경을 특정지어 DB를 Migrate 해줍니다.

RAILS_ENV=production rake db:migrate

 참고  기존에는 단순히  rake db:migrate  라고 했었던 반면, 이번에는 RAILS_ENV 라는 옵션이 붙게 됩니다.

이제 DB 또한 환경에 따라 작업이 이루어지므로 이 부분을 잘 따져야 합니다.

 

3. 혹시  db/seeds.rb  파일에 더미데이터를 등록해놓은게 있다면, 더미데이터도 등록해주세요.

RAILS_ENV=production rake db:seed

 

 
  •  Chapter 7  Nginx 설치 사전준비

 참고  AWS EC2에서 해당 과정을 진행해주세요.

 

드디어 오늘 글의 핵심 주인공인 Nginx 설치입니다.

본격적인 Nginx 설치 전, 여러분들의 귀찮음을 덜어주고자 몇 가지 사전 작업을 진행하고자 합니다.

 

1. 터미널에 다음 명령어를 입력해서 apt 패키지에 대한 인증키를 등록합니다.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7

 

2. https 통신을 지원하는 모듈을 설치합니다.

sudo apt-get install -y apt-transport-https ca-certificates

 참고  

apt-transport-https  패키지 관리자가 https를 통해 데이터 및 패키지에 접근할 수 있도록 한다.

ca-certificates  certificate authority에서 발행되는 디지털 서명.

 

3.  /etc/apt/sources.list.d/passenger.list  파일에 향후 다운로드를 할 패키지(passenger)에 대한 등록을 합니다.

sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger xenial main > /etc/apt/sources.list.d/passenger.list'

 

4. 이전 패키지와의 버전확인 및  /etc/apt/sources.list.d/passenger.list  에 기록했던 패키지의 최신버전에 대해 다운로드가 진행됩니다.

sudo apt-get update

 

 
  •  Chapter 8  Nginx 설치

 참고  AWS EC2에서 해당 과정을 진행해주세요.

 

1. 터미널에 다음 명령어를 입력해서 Nginx 및 Passenger을 설치를 시작합니다.

아래 명령어를 입력해주세요.

sudo apt-get install -y nginx-extras passenger

해당 명령어를 입력하면 nginx 및 passenger가 다운로드가 되고, 1분도 안되어서 모든 다운로드가 완료됩니다.

 참고1  Nginx 관련 파일(패키지)은  /etc/nginx  에 있습니다.

 참고2  Passenger은 Rails 기반에서 Nginx를 돌릴 시 함께 설치해야 하는 패키지로서, 서버에서 메모리가 원할히 사용될 수 있도록 도움을 줍니다.

 

2. Nginx 설치 후, 간단하게 서버를 오픈해보겠습니다. 터미널에 아래 명령어를 입력해주세요.

sudo service nginx start

아래 사진과 같이 기본 Nginx 메인 홈페이지가 잘 나오면 성공입니다.

 

하지만 저희는 Rails 프로젝트의 홈페이지를 띄어야 합니다.

이를 위한 몇 가지 수정을 진행해보겠습니다.

 

3. 터미널에 아래 명령어를 입력해주세요.

 참고  해당 파일은 nginx 전체 설정을 관리하는 파일입니다.

sudo vi /etc/nginx/nginx.conf

 

4.  /etc/nginx/nginx.conf  파일에서 52번 째 줄의 코드에 대해 주석을 해제해주세요.

 참고  에디터에서 입력모드 전환 방법은 키보드에서   키를 한번 눌러주면 됩니다.

위와같이 입력을 다 해냈다면 키보드에서  ESC  를 누르고  Shift + :  를 누른 후  wq  를 입력하고 엔터를 눌러서 에디터에서 나가주세요

 

5. 터미널에 아래 명령어를 입력해서 Ruby 언어(인터프리터)가 어디서 비롯되는건지 경로를 확인합니다.

passenger-config about ruby-command

위 명령어를 입력하면 보이는 아래 사진의 passenger_ruby 옆에 보이는 경로를 메모장 같은 프로그램을 켜서 미리 내용을 옮겨적어두세요.

 참고  만약 다음과 같은 오류가 나올경우

Passenger Gem을 따로 설치해 준 후, 다시 위의 명령어를 터미널에 입력해보세요.

gem install passenger

 

6. passenger.conf 파일을 열람 후, 다음과같이 코드를 수정해주세요.

sudo vi /etc/nginx/passenger.conf
## /etc/nginx/passenger.conf

passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby [passenger_ruby 경로];

필자 기준으로 작성해본 passenger.conf 설정

 

7. Nginx 내부에 돌려볼 Rails 프로젝트에 대한 설정을 진행해보겠습니다.

터미널에 아래의 명령어를 입력해주세요.

sudo vi /etc/nginx/sites-enabled/default

 

8.  /etc/nginx/sites-enabled/default  에서 내용을 수정해주세요.

1) 아래에 사진과 같이 일부 코드에 대해 주석처리를 해주세요.

 

2) server 블록 안에 다음과같이 내용을 등록해주세요.

 참고 1  해당 코드는 Rails로 치면 라우터의 역할을 합니다.

server {
      listen 80 default_server;
      root [Rails 프로젝트 경로]/public;
      server_name [IP주소];
      passenger_enabled on;
      rails_env [Environment];
  
      location / {
        index  index.html index.htm;
      }

      error_page   500 502 503 504  /50x.html;
        location = /50x.html {
      }
  
      ... (내용 생략) ...
}

 참고 2  대괄호로 감싸진 부분만 여러분들 환경에 맞게 입력해주면 됩니다.

필자 기준으로 작성해본 Server 설정 코드

 

9. 서버가 시작되기 전, nginx.conf에 내용이 잘 입력이 되었는지 한번 확인해보세요.

sudo nginx -t

 

10. Nginx 서버조작 명령어는 아래와 같습니다.

## 서버 시작
sudo service nginx start

## 서버 재시작
sudo service nginx restart

## 서버 Stop
sudo service nginx stop

 

아까 저희는 2번과정에서 서버를 한번 열었었고, 그 상태에서 Nginx 설정을 바꿔줬으니 서버를 restart 해보겠습니다.

터미널에 아래 명령어를 입력해주세요.

sudo service nginx restart

 

11. 오.. 이제 거의 다왔습니다.

서버가 열렸긴 했는데 에러가 발생했네요!

 

저희는  Chapter 6  과정에서 DB에 대해서는 이미 Production 환경을 기준으로 create 및 migrate가 완료된 상태입니다.

하지만 저희는 assets 파일에 대해 precompile을 해주지 않았습니다.

아래 명령어를 입력해서 Assets 파일들을 Precompile 해주세요.

rake assets:precompile

 

12. Nginx를 다시 시작을 해주세요.

sudo service nginx restart

 

13. 다시 홈페이지에 접근을 시도하면 접속이 잘 됩니다!

 

 
  •  추가 설정  Nginx 부가설정

 참고1  AWS EC2에서 해당 과정을 진행해주세요.

 참고2  해당 사항은 필수적인 사항은 아니고, 선택적인 사항입니다.

 부록  내 웹사이트의 보안점수는?

 

1. 서버 정보 및 버전 노출

현재 지금 서버가 열린 상태로 크롬 개발자도그를 통해 서버의 응답값을 보면 홈페이지에 어떤 서버를 쓰는지 훤히 다 보입니다. 위와같이 노출을 방지하고 싶으면 다음 과정을 따라주세요. 

 

1) Nginx 설정파일을 엽니다.

sudo vi /etc/nginx/nginx.conf

 

2) http 블록 안에 다음과같이 입력해주세요.

## 다음 내용을 nginx.conif 에 입력

include /etc/nginx/security.conf;
## /etc/nginx/nginx.conf

http {
  + include /etc/nginx/security.conf;
  
  ... (내용 생략) ...
}

 

3)  /etc/nginx  디렉터리로 이동합니다.

그리고 해당 위치에  security.conf  파일을 생성해주세요.

cd /etc/nginx
vi security.conf

 

4)  /etc/nginx/security.conf  파일에 다음 내용을 작성합니다.

## /etc/nginx/security.conf

server_tokens off;

위와같이 입력을 다 해냈다면 키보드에서  ESC  를 누르고  Shift + :  를 누른 후  wq  를 입력하고 엔터를 눌러서 에디터에서 나가주세요

 

5) Nginx 설정코드 검사 및 서버를 재시작 후, 다시 크롬 개발자도구에서 네트워크 상태를 확인해보세요.

sudo nginx -t
sudo service nginx restart

서버에 대한 정보가 이제 노출이 안된다!

이제 서버에 대한 정보가 안보입니다.

 

 

2. 새로운 헤더 추가

add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

홈페이지에 위 3개의 헤더에대한 정보를 넣어보고자 합니다.

1. add_header X-Frame-Options SAMEORIGIN

  · SAMEORIGIN : 같은 홈페이지상의 iframe 호출은 가능하나, 타 사이트의 iframe 호출은 불가능

  · DENY : 모든 iframe 금지

  · ALLOW-FROM Url :  주소를 설정하고 해당 주소는 iframe 허용

 

2. X-Content-Type-Options nosniff : 잘못된 MIME 타입이 포함된 응답을 거부

* MIME 타입 : 컨텐츠 형식(mp3, zip, pdf 등)을 정의하기 위한 인터넷 표준 [참고]

 

3. X-XSS-Protection "1; mode=block" : XSS를 통한 세션 하이잭킹 방지

* XSS 세션 하이잭킹 : 타인의 세션(서버에 인증된 유저정보)을 탈취해서 내가 남인 것 처럼 행동하는 것 [클릭]


1) Nginx 설정파일을 엽니다.

sudo vi /etc/nginx/nginx.conf

 

2) http 블록 안에 다음과같이 입력해주세요.

## 다음 내용을 nginx.conif 에 입력

include /etc/nginx/security.conf;
## /etc/nginx/nginx.conf

http {
  + include /etc/nginx/security.conf;
  
  ... (내용 생략) ...
}

 

3)  /etc/nginx  디렉터리로 이동합니다.

그리고 해당 위치에  security.conf  파일을 생성해주세요.

cd /etc/nginx
vi security.conf

 

4)  /etc/nginx/security.conf  파일에 다음 내용을 작성합니다.

add_header X-Frame-OptionsSAMEORIGIN;
add_header X-Content-Type-Optionsnosniff;
add_header X-XSS-Protection"1; mode=block";

위와같이 입력을 다 해냈다면 키보드에서  ESC  를 누르고  Shift + :  를 누른 후  wq  를 입력하고 엔터를 눌러서 에디터에서 나가주세요

 

5) Nginx 설정코드 검사 및 서버를 재시작 후을 하면 새로운 헤더가 적용됩니다.

sudo nginx -t
sudo service nginx restart

 

 
  •  참고  Nginx 로그파일 확인

 참고  AWS EC2에서 확인해보세요!

Nginx 기반으로 서버를 열더라도, 서버의 로그기록은 총 3개가 기록됩니다

 

1. Ruby on Rails 서버 로그기록

평소에 알던바와 같이 홈페이지에 접속 시 일어나는 상황에 대한 모든 기록이 담깁니다.


다음으로 Nginx 로그를 소개하기 전에 잠깐  etc/nginx/nginx.conf  파일을 보겠습니다.

 

nginx.conf

Nginx 코드 중, access와 error 로그기록에 대해 저장하는 코드가 존재합니다.

이 두개의 로그는 Nginx에서 별도로 수집하는 로그기록 입니다.


2. Nginx : Access

Access 로그는 어떤 유저가 어떤 페이지에 접속했고, 어떤 브라우저로 접속했는지에 대한 정보가 담겨져 있습니다. 

/var/log/nginx/access.log

 

3. Nginx Error

서버 접속에 실패할 경우, Nginx 내부에서 어떤 에러로 인해 실패했는지 기록이 됩니다.
/var/log/nginx/error.log

 

 
  •  참고  Public 폴더 내 파일들이 안불러와지는 현상

간혹 public 폴더 내용이 반영이 안되는 현상을 겪을 수 있습니다.

이런 현상 발생 시

 

 

 config/environments  위치에 있는  production.rb  파일을 열람 후,

config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

위 내용을

config.public_file_server.enabled = (ENV['RAILS_SERVE_STATIC_FILES'].present? || true)

위와같이 전환시켜 주면 됩니다.

위 코드는 RAILS_SERVE_STATIC_FILES 환경변수가 없을 경우(NULL), true 로 대체시켜 주는것을 뜻합니다.

 

 
  •  참고  EC2에서 고정IP 사용법

EC2 서버는 껏다킬 때 마다 IP가 유동적으로 바뀝니다.

이는 AWS가 유저수에 비해 IP 보유량이 부족해서 그런건데, IP를 돌려쓰다보니 이러한 현상이 발생합니다.

 부록  DHCP 개념

 

하지만 다행히 AWS에서는 고정IP를 지원합니다.

해당 방법에 대해서는 다음 글을 참고해주세요 : https://kbs4674.tistory.com/26

 

 

 

이것으로 AWS EC2에서 Nginx 엔진을 활용한 서버를 여는 법에 대해 알아봤습니다.

이제 우리 Puma 엔진은 놓아주자구요...!

 

긴 글 봐주셔서 감사합니다.

 

 
  • 자료 참고

1. 위키백과 : C10k problem

2. [오픈위키] C10k Problem

3. Apache냐 Nginx냐, 그것이 알고싶다.

4. Apache httpd – Prefork MPM 과 Worker MPM 의 비교

5. Nginx 공식페이지 : Thread Pools in NGINX Boost Performance 9x!

6. 아파치 2.4와 Nginx 특징 및 비교

7. Nginx Architecture

8. [씨엔텍시스템즈] 웹서버 소프트웨어 Apache 와 NginX 비교

9. AWS Ubuntu 16.04 에 Rails Project를 nginx로 Deploy 하기

10. Deploying a Ruby application

11. apt-get 설치 : apt-transport-https, ca-certificates 패키지 개념

12. apt-key 개념

13. apt-get update에서 hit 및 get 개념

14. 보안등급 A+를 받을 수 있는 Nginx SSL 설정

 

 

 

댓글
댓글쓰기 폼
공지사항
Total
53,991
Today
19
Yesterday
104
링크
«   2020/11   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          
글 보관함