Tagged: 리눅스

Nginx 설정.

이 문서는 Nginx  설정에 대한 문서 입니다. 계속적으로 업데이트가 됩니다.

요청 메소드 제한

요청 메소드는 GET, HEAD, POST, PUT, DELETE 등이 있다. 문제는 대부분 웹 서비스는 GET, HEAD, POST 만 필요로한다는 것이다. Nginx 에서 이를 다음과 같이 제한 할 수 있다.

GZIP 설정

 

Nginx + PHP-FPM + MariaDB 설치 (CentOS 7)

과거에는 APM (Apache + PHP + MySQL)이 인기있는 플랫폼이 였지만 최근에는 Nginx 가 나오고 PHP-FPM 이 나오면서 NPM 으로 많이 대체되고 있는 추세에 있습니다. 이 글은 Nginx,PHP-FPM, MariaDB 설치에 관한 것입니다.

준비

이 글에서 NPM을 설치하는 환경은 다음과 같습니다.

  • CentOS 7.2.1511
  • X86_64
  • Selinux Disable
  • 작성시간: 2015. 12. 27

설치하는 방법은 CentOS 7 에서 제공하는 패키지 관리 프로그램인 YUM을 이용하는 것입니다. 다음과 같이 CentOS 7 를 최신 버전으로 만듭니다.

 

PHP 설치

다음과같이 YUM 을 이용해서 설치해 줍니다.

php-mysql 은 MariaDB 와 연동하기 위한 것임으로 함게 설치해 줍니다.

systemctl 에 등록하고 시작해 줍니다.

php-fpm 의 pool 설정을 다음과 같이 해줍니다.

세션(Session) 디렉토리의 소유권을 cacti 로 변경해 줍니다.

 

MariaDB 설치

MariaDB 의 최신 버전 설치를 위해서 다음과 같이 YUM 저장소를 추가해 줍니다. YUM 저장소 추가는 다음 내용을 파일로 저장해주면 됩니다.

현재 MariaDB 의 최신버전은 10.1 이기 때문에 baseurl 에 버전이 정확해야 합니다. 다음과 같이 설치를 해줍니다.

systemctl 에 등록을 해주고 데몬을 시작해 줍니다.

mysql_secure_installation 을 실행해서 root 패스워드와 불필요한 데이터베이스를 삭제 합니다.

 

Nginx 설치

Nginx 의 최신 버전 설치를 위해서 다음과 같이 YUM 저장소를 추가해 줍니다. YUM 저장소 추가는 다음 내용을 파일로 저장해주면 됩니다.

cacti 서비스를 예를들어 다음과 같이 cacti.conf 파일을 작성합니다.

웹 서비스를 위한 홈 디렉토리가 ‘/home/cacti’ 를 만들어주고 www 디렉토리를 생성해 줍니다.

nginx 문법체크를 하고 systemctl 에 서비스를 등록하고 서비스를 시작해 줍니다.

80(http) 방화벽 설정

80 포트, 즉 HTTP 를 위한 방화벽 설정을 다음과 같이 해줍니다.

 

 

DNS amplification DDos attacks (DNS 증폭 DDos 공격)

최근에 관리하는 서버에 트래픽이 몰리는 현상이 발생했다. 웹 서비스 트래픽도 아니기에 뭔가 싶어 봤더니 53 포트를 통한 input 트래픽이였다. 그래서 ngrep 으로 53 포트를 모니터링 하니 대략 다음과 같이 나왔다.

뭔가 자꾸 DNS 서버에 쿼리(Query)를 보내고 있었고 이로 인해서 트래픽이 발생하는게 분명했다.

DNS amplification DDos attacks (DNS 증폭 DDos 공격)

‘DNS amplification DDos Attacks’ 는 DNS 증폭 DDos 공격으로 불리운다. 왜 ‘증폭’ 일까?

DDos 는 대량의 트래픽이 필요하다. 초당 수십 Gbps 를 유발시켜야 하는데 이렇게 할려면 많은 장비가 필요하다. 그러다보니 DDos 공격을 개인이 한다는 건 무리가 있다. 그런데, DNS 서버는 이런 많은 장비 없이도 대량의 트래픽을 유발시킬 수 있는 구조적인 면을 안고 있다.

DNS 는 인터넷을 위해서는 반드시 존재해야만 하는 서버다. 인터넷 전화번호부 라고도 불리우는 서버로 인간의 주로 사용하는 도메인을 컴퓨터가 알아볼수 있는 IP 주소로 변환한다. 브라우저 주소창에 도메인을 입력하면 DNS 서버에 그 도메인의 IP 주소를 질의(Query) 한 후에 받은 IP를 가지고 실제 서버에 접속하는 구조다.

이렇게 DNS 는 질의(Query)를 받아 응답한다. 그런데, DNS 에 보낼 수 있는 질의(Query)는 다양하며 그중에서 재귀적 질의(Recursive Query) 가 문제가 된다. 재귀적 쿼리는 DNS 서버가 보유한 도메인 리스트에 질의한 내용이 없을 경우 이를 다른 DNS 서버에 질의하는 것을 말한다.

예를들어 DNS-A 이라는 DNS 서버에 naver.com 을 질의했다면 DNS-A 서버는 먼저 자신의 도메인 리스트에 naver.com 이 있는지 찾게 된다. 없다면 최상의 DNS 서버인 ROOT-DNS 서버에 DNS-A 서버가 naver.com 서버의 IP가 무엇인지 질의하게 된다. ROOT-DNS 서버는 naver.com 주소의 TLD(Top Level Domain) 인 .com DNS 서버에 물어보라고 DNS-A 서버에 알려주고 다시 DNS-A 서버는 .com TLD 서버에 질의한다. .com TLD 서버는 naver.com 네임서버에게 물어보라고 응답하고 DNS-A 서버는 드디어 naver.com 을 가진 DNS 서버에 IP를 요청하고 이를 받아서 클라이언트에게 응답하는 것으로 임무는 종료 된다.

  • OS에 설정된 DNS-A 서버에 naver.com 의 IP를 요청한다.
  • DNS-A 서버는 자신의 도메인 리스트나 도메인 캐쉬에서 naver.com IP를 찾는다. 있다면 응답하고 끝나게되고 없다면 다음으로 진행.
  • DNS-A 서버에 naver.com 이 없음을 알게된 서버는 최상의 DNS 서버은 ROOT-DNS 에 naver.com IP를 질의한다.
  • ROOT-DNS 는 naver.com 의 TLD (Top Level Domain) 인 .com DNS 에 물어보라고 DNS-A 에게 알려준다.
  • .com DNS 서버는 naver.com 도메인의 DNS 서버에게 물어보라고 DNS-A 에게 알려준다.
  • 마침내 DNS-A 서버는 naver.com 도메인의 DNS 서버에 IP가 뭐냐고 질의한다.

여기에 질의 내용을 ‘ANY’ 로 할 경우에는 응답하는 양이 많아진다. 도메인의 DNS 구성에는 MX, A, TXT, CNAME 등 다양하다. 질의할때에는 어떤 타입을 원하는지를 정할 수 있게 되는데, ANY 타입의 질의는 도메인이 가지고 있는 모든 정보를 원하게 된다.

결국 재귀적 질의와 ANY 타입의 질의를 결합해 초당 수백건의 도메인 질의를 보내게 되면 DNS 서버는 이 질의에 응하게되고 수십Gbps 의 응답 트래픽을 발생시키게 된다. 이것이 바로 ‘DNS 증폭 DDos 공격’ 이다.

이 공격은 대부분 DNS 의 잘못된 설정 탓이다. BIND 9 의 경우에는 재귀적 질의를 맞음으로써 간단하게 해결할 수 있다.

BIND 9 의 기본 설정은 ‘recursion yes’ 임으로 이를 바꿈으써 ‘DNS 증폭 DDos 공격’을 막을 수 있다. 이 공격을 막았을 경우 로그는 다음과 같이 쌓인다.

 

gitlab 패스워드 리셋하기

gitlab 패스워드 리셋하기

Gitlab 을 사용하다가 갑자기 패스워드를 잊어버리는 경우가 생길 수 있습니다. 이럴때 보통 Web 에서 ‘Fogot your password’ 링크를 클릭하고 리셋될 패스워드를 가입할때 적어놓은 E-mail 로 발송을 해줍니다. 그런데, E-mail 주소가 없는 거라면 패스워드를 리셋할 수가 없어서 로그인을 못하게 됩니다.

이럴때는 Gitlab 서버에 터미널로 로그인을 해서 gitlab-rails console을 실행하고 패스워드를 바꿀 수 있습니다. 먼저 gitlab-rails console로 접속을 합니다.

여기서 만일 E-mail 주소를 정확하게 알고 있다면 다음과 같이 user 객체를 지정할 수 있습니다.

그런데 위와같이 ‘nil’ 로 나오면 없는 사용자라는 거죠. 그럼 다음은 id 로 검색을 합니다. id 는 내부 데이터베이스에 저장될때에  사용되어진 primary key 인듯 합니다. 보통 사용자가 1명이라면 이 방법이 통하지만 수십명이면 안되겠죠.. (전 집에서 개인적으로 사용하기 때문에 사용자가 1명인 경우입니다. )

뭔가 나오네요… 그런데 이마저도 모르겠다!! 그러면 사용자 로그인 아이디로 검색을 해봅니다.

뭔가 나왔군요. 그러면 user 객체가 생성되어진 겁니다.

패스워드는 다음과 같이 바꾸면 됩니다.

그리고 바로 Web 에서 변경된 패스워드로 로그인이 가능합니다.

Suspend 된 게스트 시작 않될때 해결 방법.

Suspend 는 보통 게스트를 Paused 상태로 만드는 것을 말한다. 이는 동작상태를 하드디스크에 그대로 저장하고 끝내는 것을 말하며 이를 재시작하는 것을 Resume 이라고 한다. 명령어로는 그냥 start 명령어를 쓰지만 Suspend 에서는 부팅이 아닌 저장하고 끝난 부분을 풀고 바로 시작되는 것이 다르다.

그런데, Suspend 한 이미지를 시작하려고 할 때에 다음과 같이 오류가 나왔다.

아무리 Resume 을 할려고 하더라도 위와 같은 오류로 시작도 않되었다. 이럴때는 다음과 같이 해서 부티을 시도하는 것이 좋다.

이는 앞에서도 말했듯이 Supsend 될때에 저장된 이미지를 삭제하도록 한다. 앞에서 오류는 바로 이 저장된 이미지를 풀고 Resume 을 하려고 하는 것인데, 이 이미지가 잘못되었것이다. 이럴때는 어쩔수 없이 부팅을 해야하게이 이를 삭제하고 시작하면된다.

알고리즘 – 최대공약수(Great Common Divisor)

분수 알고리즘에서 마지막으로 약분(reduce a Fraction to Lowest Terms) 을 합니다. 약분은 분자와 분모의 최대공약수(GCD, Great Common Divisor)로 나누는 것을 말합니다. 따라서 약분을 하기 위해서는 최대공약수를 구하면 됩니다.

약분, 최대공약수를 구하라.

최대공약수 구하기 1

최대공약수를 구하는 방법은 여러가지가 있는데 그 첫번째로 분자, 분모 두개를 동시에 나누었을때에 나머지가 없는 수를 구하면 됩니다. 1부터 시작해서 분자, 분모 두수중에 작은 수까지 대입해서 하나씩 나누어서 0이 되는지를 찾아보는 겁니다.

최대공약수를 구하는 무한대입법이라고 보시면 됩니다.

작은 수가 무엇인지를 구하기 위해서 min 함수를 이용했습니다. 무한대입법을 이용하기 위해서 for 문을 이용했고, maxDiv 변수에 최대공약수 값을 저장하도록 했습니다.

근데, 이렇게하면 아시겠지만 아주 큰수의 경우에 아주 오래 걸립니다. for 문 그냥 막 돌아야하니까요.

최대공약수 구하기 2 – 뺄셈이용.

이 방법을 유클리드(Euclidean) 방법인지는 모르겠습니다. 유클리드 방법은 나눗셈을 이용하는 방법인데, 이것을 뺄셈으로 변환한 것으로 보이거든요.

두 숫자가 있다고 합시다. 두 숫자를 관호에 넣고 왼쪽엔 큰 숫자, 오른쪽엔 작은 숫자를 넣습니다. 그리고 이 둘을 뺀 값을 제수로 넣습니다. 그리고 다시 큰 수를 왼쪽에 넣고 다시 빼고 나온 값을 다시 제수로 넣고 이를 반복하다 보면 나머지가 0일때에 피제수값이 나오는데 이게 바로 최대공약수 입니다.

(3654, 1365)

이 둘을 빼면 2289 값이 나옵니다. 그러면 3654(제수)를 버리고 다음과 같이 적습니다.

(2289, 1365)

다시 둘을 빼면 다음과 같이 나옵니다.

(924, 1365)

왼쪽에는 항상 큰 숫자여야 해서 이 둘을 교환합니다.

(1365, 924)

이것을 한눈에 알아보도록 표기를 하면 다음과 같습니다.

위와 같은 방법이 되고 마지막에 (0, 21) 이니까 두수의 최대공약수는 21 이 되는 것입니다.

이 방법이 유클리드 호제법과 같다는 이유는 뺄셈하는 방법이지만 제수를 항상 나머지로 다시 넣기 때문입니다. 유클리드 호제법은 나눗셈을 이용해서 나온 나머지를 다시 제수로 넣는 방법인데 둘은 같습니다.

(3654, 1365) = (2289, 1365)

이를 공식으로 쓰면,,,

3654 = 1365*1 + 2289

이는 3654/1365 를 나눈 나머지 2289 랑 같습니다.

여기서 규칙은 한가지, 두수를 비교해서 큰수를 왼쪽에 넣어준다 입니다.

최대공약수 구하기 2 – 나눗셈이용.

이를 유클리드 호제법이라고 합니다. 앞에 뺄셈을 나눗셈으로 바꿔서 하는 방법입니다. 이게 뺄셈보다 좋은 점은 반복적인 뺄셈을 없애줍니다. 규측인 뺄셈과 같습니다.

위와같이 while 문을 이용해서 할수도 있지만 재귀호출(Recusive) 로도 다음과 같이 구현할 수 있습니다.

최대공약수(GCD)를 구했는데, 1이 값으로 나온다면 이는 최대공약수가 없다는 것을 의미합니다. 1은 모든수의 공약수이기 때문입니다.

알고리즘 – 분수(Fraction) 문제

알고리즘 – 분수(Fraction) 문제는 컴퓨터 알고리즘을 시작하는데 좋은 예제입니다. 분수는 어릴적 산수시간에 배운 그게 맞습니다. 1/2, 1/3, 1/4 식 입니다.

분수에는도 사칙연산을 할 수 있습니다. 더하기(add), 빼기(subtract), 곱셈(multiply), 나눗셈(divide) 가 그것입니다. 이를 컴퓨터 프로그램 언어를 이용해서 만들어보는 겁니다.

참고: http://interactivepython.org/runestone/static/pythonds/Introduction/ObjectOrientedProgramminginPythonDefiningClasses.html#a-fraction-class

분수의 정의와 제약사항

분수는 다음과 같이 정의됩니다.

수학에서 분수(分數, fraction)는 a/b 이나  \frac {a} {b} 꼴로 표시한다. 이것은 a를 b로 나눈 값, 즉 a와 b의 를 뜻하며, 여기서 a는 분자b는 분모라고 한다. 이 때 분모 b에 0이 들어가는  \frac {a} {0}(a는 상수)라는 수는 정의될 수 없으므로 b0 이어야 한다.

From 위키페디아

중요한 것이 분모는 0 이여서는 안됩니다. 또 한가지 이 글에서 제약조건을 걸어야 하는데, 분자와 분모 모두 양수로만 이루어진 분수를 다룹니다. 또, 모두 정수여야 합니다. 이를 정리하면 다음과 같습니다.

  • 분모는 0 이여서는 안됩니다.
  • 분자, 분모는 모두 양의 정수(양수이며 정수)

분수의 덧셈

분수의 덧셈은 먼저 분모를 ‘통분’해야 합니다. 무슨말이냐 하면 덧셈을 하기 위한 두개의 분수들의 분모 크기를 같은 값으로 만드는 것(=분모를 통일하는것)입니다. 예를들어

1/2 + 1/3 이 있다면 분모를 통분하는데 서로서로 분모값을 분자,분모에 곱해주면 됩니다. (1*3)/(2*3) + (1*2)/(3*2) = 3/6 + 2/6 = 5/6

분모가 같아지니까 분자만 그대로 더해주면 됩니다.

분수의 뺄셈

분수의 뺄셈은 분수의 덧셈과 마찬가지로 분모를 통분해주고 분자까리 빼주면 됩니다.

분수의 곳셈

분자는 분자까리, 분모는 분모끼리 곳해주면 끝~

분수의 나눗셈

나누는 분수을 역으로 바꾸고 둘을 곱셈하면 된다.

2/5 나누기 1/3 = 2/5 * 3/1 = 6/5

여기까지가 분수에 관한 수학적 알고리즘입니다.

컴퓨터 알고리즘

컴퓨터 알고리즘은 컴퓨터를 이용해서 문제를 해결하는 방법입니다. 그럴려면 아무래도 프로그래밍을 해야하고 프로그래밍을 위해서는 프로그램 언어를 이용해야 합니다. Python, Java, PHP 등이 여기에 속합니다.

한가지 컴퓨터 알고리즘을 할때에는 선택한 언어의 특성을 이용하는 경우가 있습니다. 예를들어 Python 을 이용할 경우에 내장 메소드를 이용할 수 있는데, 이번 분수 알고리즘에서 이를 사용할 것입니다. 다른 언어로 구현할 경우에는 이러한 Python 의 내장 메소드 기능을 제공하지 않기 때문에 다르게 구현을 해야합니다.

이 말은 결국 컴퓨터 알고리즘을 구현하는데 사용하는 언어에 영향을 어느정도 받는다는 것입니다.

Python 의 특징(python3.4 기준)

Python 은 내장 메소드를 지원합니다. 이는 모든 데이터를 객체로 인식하고 레퍼런스하기 때문에 가능한 것입니다. 단순한 숫자조차도 다양한 메소드를 지원합니다.

위에 보시면 숫자에 대한 내장 메소드를 볼수 있습니다. 이 내장 메소드들은 특정한 연산을할때에 자동으로 작동합니다. 예를들어, ‘__add__’ 의 경우는 숫자를 더할때에 자동적으로 호출되어 작동합니다.

Python 에서 사칙연산에 관한 내장 메소드는 다음과 같습니다.

구현하기

Fraction 이라는 클래스를 만들고 내장 함수들을 조작함으로써 완성함으로써 완성됩니다.

먼저 두개의 숫자를 입력받는걸로 분수를 만듭니다.

그리고 덧셈 테스트를 해봅니다.

같은 클래스의 객체를 만들어서 덧셈을 해보면 저렇게 내장 메소드가 없다라고 나옵니다. 그러면 저 내장 메소드를 만들어주면 됩니다.

위와같이 덧셈 내장 메소드를 정의해주고 다음과 같이 테스트를 합니다.

잘 되네요. 뺄셈, 곱셈, 나눗셈은 앞에서 말한 방법대로 내장 메소드를 이용해서 구현하면 됩니다.

제약조건인 음수와 0에 대한 것을 예외로 처리하였습니다. 다음과 같이 실행 합니다.

마이너스(-) 표시가 마음에 안들긴하지만 일단 구현까지만하는 걸로..

ELK 구축하기 1 – Logstash

ELK 는 ElasticSearch, Logstash, Kibana 를 말하며 보통 이 시스템은 실시간 로그분석 시스템으로 불리웁니다. Logstash 는 로그를 실시간으로 전송하고 ElasticSearch 는 전송된 로그를 검색 인덱스를 만들어 보관하며 Kibana 는 ElasticSearch 의 분석한 자료를 시각화해줍니다.

이를 이용하면 시스템 자체 뿐만 아니라 각종 애플리케이션의 로그들을 분석하고 시각화된 통계자료를 자동으로 얻을 수 있습니다.

첫번째로 Logstash 를 설치해보도록 하겠습니다.

설치

Logstash 는 Java 7 이상이 필요합니다. Java 7 을 설치해야 합니다. 이것이 없으면 동작이 안됩니다.

Logstash 홈페이지에서 다운로드 받아 설치할 수 있습니다. tar.gz 도 있고 우분투, 레드햇 패키지도 있어 자신에게 필요한 것을 받아 설치하면 됩니다.

 

기본개념

Logstash 의 기본 개념을 잠깐 살펴보겠습니다.

마치 쉘(Shell)의 파이프라인(pipeline)처럼 동작합니다. 입력을 받아서 출력을 해주는 구조 입니다. 그리고 입력 받은 내용을 필터링을 하고 출력할 수도 있습니다.

Logstash 에서 Input, Filter, Output 이 핵심이며 다양한 Input, Filter, Output 에 대응하기 위해서 각각 플러그인을 가지고 있습니다. 예를들어 다양한 입력을 받아야 하는 경우에 운영자가 Input 자체를 구성할 수 있지만 누군가 만들어놓은 플러그인 설치하면 끝나게 됩니다.

basic_logstash_pipeline

결국 Logstash 를 운영은 수집하고자 하는 로그에 대해서 Input, Filter, Output 어떻게 만들고 구성할것인가가 핵심이 됩니다. 그래서 설정파일의 형식은 다음과 같습니다.

 

사용법

명령행으로 사용할 수 있습니다.

‘-e’ 옵션은 명령행에서 설정파일을 작성할 수 있도록 해줍니다. 설정 내용을 보면 input 부분에 ‘stdin{}’ 으로 표준입력을 받겠다는 것이고 output 에 ‘stdout{}’ 으로 표준출력으로 결과를 내보내겠다는 뜻입니다.

이제 아파치 로그 파일을 Logstash 설정파일을 만들어 분석해보도록 하겠습니다. 먼저 input 부분을 정의해 줘야 합니다. 예를들면 다음과 같습니다.

‘input{}’ 에는 어떤 형태의 입력을 받을 것인가를 정의하는데 이것을 플러그인(Plugin)이라고 합니다. 그래서 ‘input 플러그인이 무엇이냐?’하는 질문이 가능합니다. 여기서는 ‘file’ 이되며 보다 자세한 사항은 ‘Input plugins‘ 페이지를 참고하시면 됩니다. 그에 따른 세부사항을 설정하도록 되어 있습니다. 위 예제에서는 file 로부터 받을 것이기에 형태를 file 로 했고 세부사항으로 파일의 경로와 ‘start_position’ 을 정의했습니다. file 형태로 입력을 받을 경우에 기본값은 Unix 시스템의 ‘tail -f’ 와 같이 실시간으로 파일에 새롭게 써지는 로그들을 읽도록 되어 있는데 이를 바꾸고자 한다면 ‘start_position’을 이용하면 되고 위 예제에서는 파일의 처음부터 읽도록 바꾸었습니다.

다음으로 filter 을 정의해야 합니다. 아파치 로그를 파싱하기 위한 작업입니다. 역시나 filter plugin 들이 아주 많은데, 여기서는 기본으로 가지고 있는 grok 을 사용해서 다음과 같이 로그 파싱을 정의해줍니다.

아파치로그를 커스터마이징했다면 위의 예제와는 다르게 정의해야 합니다. 위 예제는 아파치로그가 “COMBINED” 로그로 설정되어 있어서 이 형태를 파싱하겠다 것입니다.

Output plugin 은 화면으로 출력을 하기위해 다음과 같이 stdout 을 사용합니다.

이것을 하나의 파일에 저장한 후에 다음과 같이 실행해 줍니다.

위와같이 원하는 결과가 화면에 나옵니다.