내부 사용자들이 간단하게 인증할 수 있는 방법


mod_auth_basic.so
mod_authn_file.so

없다면 설치하고 httpd.conf에서 loadmodule할것

 


설정된 디렉토리 내용 안에 아래 추가.

 httpd.conf 설정은 아래와 같이 한다.

        AllowOverride All
        Order allow,deny
        Allow from all
AuthType Basic
AuthName "test admin"
AuthUserFile "/경로는알아서/apache/conf/.htpasswd"
require valid-user

보안상 .htpasswd 파일은 아파치 conf밑에 두도록 한다.
htpasswd -c .htpasswd 아이디
 


n사 다닐때 글로벌 모바일 게임 웹 서버를 구축하는 프로젝트를 했었는데, 처음엔 싱가포르 지역에만 구축을 했었고 

추후 기획의 요구사항이 국가코드.도메인.com/게임명  url로 해당 국가에 설치된 서버로 접속하도록 하는 것이었다.  

예를 들면, 북미에서 접속할때는 us.domain.com/game1, 중국에서 접속할때는 cn.domain.com/game1 이런 식이었다. 


지금은 잘 기억나지 않지만, 인프라에서 global dns 서비스를 구축하면 가능했던 걸로 확인을 했었으나 비용 등의 문제로 

이 방법은 사용하지 못했고 대신 애플리케이션 레벨에서 처리를 하기로 마음 먹고 진행한 것이 geoIP를 이용해 해당 국가 코드를

알아내고 그 국가의 서버로 redirect 시키는 것이었다. 이를 바탕으로 간단히 정리해본다.

(실제로는 서비스는 종료되어 이 방법을 리얼 환경에 적용해보지도 못했음.)


 http://perl.apache.org/    


     - mod_perl 아파치 모듈을 이용해 perl 스크립트로 아파치 단 요청과 응답 사이에 로직을 추가하여 실행할 수 있다.
       일반적으로 perl 스크립트는 실행시마다 컴파일이 되지만 mod_perl 을 이용할 경우 아파치 서버가 시작될 때 perl 모듈과
       스크립트들이 한번만 컴파일이 되면 그 이후부터는 컴파일된 모듈이 아파치 내부에서 동작하게 된다.

     - 읽어보면 도움이 될만한 사이트


     - 2.2.x 와 호환 가능한 버전을 다운로드 받으면 된다. http://perl.apache.org/dist/mod_perl-2.0-current.tar.gz

          
2. 설치방법
     1) tar zxvf mod_perl-2.0.-cyrrent.tar.gz 한 후 해당 폴더로 이동
     2) perl Makefile.PL MP_APXS=/usr/local/apache/bin/apxs
     3) make
     4) make test
     5) sudo make install
-----------------------

3. httpd.conf 추가 
    LoadModule perl_module modules/mod_perl.so 
    를 추가한 뒤 아파치 재시작이 성공하면 OK


4. 펄 모듈 생성
     1) cd /home/www/perl;  mkdir MyApache2; cd MyApache2;
     2) vi startup.pl 한 뒤 아래 내용 입력 후 저장
use lib qw(/home/www/perl); // perl 설치 경로
1;
 
     3) vi RedirectUrl.pm 한뒤 아래 내용 입력후 저장
package MyApache2::RedirectUrl;

use warnings;
use XML::Simple;
use APR::Table;
use Apache2::Connection ();
use Apache2::RequestRec ();
use Apache2::RequestIO ();
use Apache2::Const -compile => qw(REDIRECT);
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Headers;
use Encode;

sub handler {
     my $r = shift;
     $r->content_type('text/plain');
     $r->content_encoding('utf-8');

     my $c = $r->connection;
     my $clientIp = $c->remote_ip;
     my $address = "geoIP를 이용하여 국가코드를 리턴하는 api(사내주소여서 공개할 수 없음)";
     my $objUserAgent = LWP::UserAgent->new(timeout => 2);
     $objUserAgent->agent("TEST/TEST");
     my $objHeader = HTTP::Headers->new;
     $objHeader->push_header("Content-Type" => "text/plain");
     my $objRequest = HTTP::Request->new(GET=>"$address", $objHeader);
     my $objResponse = $objUserAgent->request($objRequest);
     my $content = $objResponse->content;

     # Test XML
     #my $content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>...주소데이터...";
     my $xml = new XML::Simple;
     my $data = $xml->XMLin($content);

     if (defined($data->{error})) {
          my $errCode = $data->{error};
          my $errMsg = "warning : ";


          if($errCode eq "1001") {
               $errMsg .= "ERROR_IP_NOTFOUND";
          }

          if($errCode eq "1002") {
               $errMsg .= "ERROR_DB_SEARCH";
          }

          if($errCode eq "2001") {
               $errMsg .= "ERROR_NETWORK";
          }

          if($errCode eq "2002") {
               $errMsg .= "ERROR_NETWORK_TIMEOUT";
          }

          if($errCode eq "2003") {
               $errMsg .= "ERROR_NETWORK_UNKNOWN";
          }

          if($errCode eq "3001") {
               $errMsg .= "ERROR_IP_INVALID";
          }

          if($errCode eq "4001") {
               $errMsg .= "ERROR_MAXMIND";
          }

          print $errMsg;
     } else {
          my $countryCode = $data->{country};

          if($countryCode eq "CN") {
               print "access denied....!(Country Code : CN) \n";
          } elsif($countryCode eq "SG") {
               print "access denied....!(Country Code : KR) \n";
          } elsif($countryCode eq "KR") {
               # 특정주소로 Redirect
               my $URL = "redirect할 주소";
               $r->headers_out->set('Location' => $URL);
               return Apache2::Const::REDIRECT;
          } else {
               print "# welcome! \n";
          }
     }

     return Apache2::Const::OK;
}
1;
 

5. httpd.conf에 모듈을 사용하도록 설정 추가
<IfModule mod_perl.c>
    PerlRequire /home/www/perl/MyApache2/startup.pl

    <Location ~ "/*">
        SetHandler perl-script
        PerlResponseHandler MyApache2::RedirectUrl // 사용자 정의 모듈
    </Location>
</IfModule>
 

6. 필요시 XML 파싱을 위한 XML::Simple, XML::Parser 설치
     yum install expat-devel;
     cpan install XML::Simple;
     cpan isntall XML::Parser;
     cpan isntall APR::Table;





 

'Apache & Nginx' 카테고리의 다른 글

[Apache] 로그인 계정 세팅  (0) 2015.09.03
[Apache] 프로세스 생성 방식에 따른 비교  (0) 2015.09.03

Prefork 방식

  • 1개의 자식 프로세스당 1개의 쓰레드를 가짐(최대 1024개의 프로세스 생성 가능)
    • 1개의 자식 프로세스는 1개의 요청을 처리
  • 프로세스당 독립적인 메모리 사용
    • 메모리 공간이 독립적이기 때문에 안정적이나 메모리를 많이 소모
  • 설정 내용 (샘플)

     <IfModule prefork.c>

        StartServers        20      // 아파치 시작시 생성되는 자식 프로세스 개수

        MinSpareServers      5      // 부하가 적을 경우에 이 수치만큼 유지하려고 함

        MaxSpareServers     10      // 부하가 많을 경우에 이 수치 이하로 줄이려고 함

        MaxClients         256      // 클라이언트의 최대 요청 수 제한

        MaxRequestsPerChild  10000  // 생성된 자식 프로세스가 이 수치만큼 요청을 받을 경우 처리후에 자동으로 종료됨 

                                  //(0은 무한대로 유지 -> 이렇게 값을 주게 되면 특정 모듈의 메모리 누수와 같은 버그로 서비스 불가 상황이 발생할 수 있다!)

    </IfModule>

Worker 방식

  • 1개의 자식 프로세스가 다중 쓰레드를 가지며, 각 쓰레드는 1개의 요청을 처리
  • 쓰레드간 메모리 공유로 Prefork보다 적은 메모리 사용
    • 리소스의 race condition 발생이 생길 가능성이 크므로 조심해야 함. 특히 php는 더 조심해서 사용.
  • 설정 내용 (샘플)

     <IfModule worker.c>

        StartServers         2       // 아파치 시작시 생성되는 자식 프로세스 개수

        ServerLimit          6       // 구성 가능한 자식 프로세스 제한 개수 (MaxClients와 ThreadsPerChild에서 요구한 프로세스 개수보다 높게 설정하면 안됨)

        MaxClients         150       // default는 ServerLimit * ThreadPerChild, 클라이언트의 최대 동시 요청 처리 수

        MinSpareThreads     25       // 서버에 idle 쓰레드가 불충분하다면 자식 프로세스는 idle 쓰레드 > MinSpareThreads 가 될때까지 생성됨

        MaxSpareThreads     75       // 서버에 너무 많은 idle 쓰레드가 존재하면 자식 프로세스는 idle 쓰레드 < MaxSpareThreads 가 될때까지 죽게됨

        ThreadsPerChild     25       // 자식 프로세스당 생성될 수 있는 쓰레드 개수

        MaxRequestsPerChild  0       // 생성된 자식 프로세스가 이 수치만큼 요청을 받을 경우 처리후에 자동으로 종료됨

                                  //(0은 무한대로 유지 -> 이렇게 값을 주게 되면 특정 모듈의 메모리 누수와 같은 버그로 서비스 불가 상황이 발생할 수 있다!)

    </IfModule>

요약

  • 일반적으로는 prefork 방식이 사용되고 요청량이 많은 서버의 경우 worker 방식을 사용하기도 하나, worker방식은 쓰레드간 메모리 공유로 인해
    리소스에 대한 경합이 발생할 가능성이 많기 때문에 애플리케이션 레벨에서 코딩을 thread-safe하게 구현해야 한다. 
    보다 안정적인 서비스를 위해서 prefork + 서버 scale-out으로 많이 사용한다.
  • MaxClient의 튜닝 (prefork 방식 사용시에~)
    • 서버의 메모리 사용량 대비 처리가능한 개수로 역산하여 정하는 것이 좋다.
      • 계산 방법 예제
        • 사용가능한 여유 메모리 산정 : 2G(Total Memory) - OS(500M) - Java(600M) - Swap(Total Memory * 0.8 = 160M) = 약 700M
          • 2G를 TotalMemory로 봤을때 OS 입장에서 80% 이상 사용하게 되면 swap 발생 가능성이 커짐. 따라서 1.6G 만이 가용 가능한 메모리라고 봐야 함.
          • 1.6G에서 예를들어 Tomcat의 Xmx가 600M이고 top 기준으로 RES 700M정도 된다고 하면,  최종 900M 정도가 가용  메모리라고 봐야 한다.
          • 900M에서 OS와 기타 주요 프로세스들이 사용하는 메모리를 200M 정도로 산정하여 추가로 빼주면 700M 정도가 apache가 사용할 수 있는 가용메모리가 됨.
        • 자식 프로세스 하나의 메모리 크기 측정 : 약 10M 라고 가정
        • MaxClients 는 700 / 10 = 70개로 서비스 가능하다.


'Apache & Nginx' 카테고리의 다른 글

[Apache] 로그인 계정 세팅  (0) 2015.09.03
[Apache] mod_perl을 이용한 redirect 서버 만들기  (0) 2015.09.03

+ Recent posts