컴퓨터 / Computer

varnish 쓸때 실제 접속자 ip 사용하기

공유지기 3 7,686 2016.08.24 22:42

0_fivEmSUN_cafc0046fceae53820e6e11ed19a3a0d3034ec3c.jpg 


지난 번에 varnish 설치하고 phpmyadmin 접속 안되는 현상이 나타났는데, 알고보니 http 접속 로그라든지 REMOTE_ADDR을 통해 접속자 ip 가져오는 것에 문제가 생겼다. 그리하여 이를 해결하고자 이 글을 추가해서 쓴다. 

 

varnish 동작 원리에 대해서는 글이 많으니 간단히 설명한다.

 

웹서버(httpd) -  varnish - 외부 접속자들

 

위 구조에서 외부 접속자들의 ip가 varnish를 지나서 웹 서버로 가면 모두 127.0.0.1로 표시가 된다. 아파치 로그 뿐만 아니라 그누보드나 자체 서비스의 로그에도 접속자 ip가 127.0.0.1로 기록된다. 이 문제가 phpmyadmin 문제와 결부가 되어 3가지 방법으로 해결을 시도하였다. 

 

1안 : 변수 변경

아파치에서 외부 ip를 확인하는 변수는 "REMOTE_ADDR"인데 이 변수를 다른 변수로 대체하여 사용하는 방법을 찾았다. 대체 가능한 변수는 "HTTP_X_FORWARDED_FOR"인데 웹 서버 설정에서 바꾸어야 할 부분이 있다. 

* httpd.conf

1. 추가 :  LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" varnishcombined

2. 수정

     ErrorLog logs/seven2015-error_log varnishcombined

     Customlog logs/seven2015-access_log varnishcombined

 

그리고 이렇게 하기 위해서 varnish 설정 파일을 수정해야 한다. 

* default.vcl : 주석 해제 

 sub vcl_pipe {

      set bereq.http.connection = "close";

     return (pipe);

 }

다른 부분은 그대로 두고 저 항목만 주석을 푼다. 

 

이제 저렇게 하고 운영 중인 체크박스와 그누보드를 아래와 같이 수정 작업하였다. 

* Checkbox 

 대체 :  REMOTE_ADDR -> HTTP_X_FORWARDED_FOR 

* GNUBoard

 - bbs/visit_insert_inc.php

 대체 :  REMOTE_ADDR -> HTTP_X_FORWARDED_FOR   

 - /common.php 

 대체 :  REMOTE_ADDR -> HTTP_X_FORWARDED_FOR   

 그런데 저렇게 수정하다보니 REMOTE_ADDR 변수가 들어가 있는 부분이 무척 많았다. 그리고 대다수 프로그램들이 REMOTE_ADDR을 쓰다보니 저렇게 수정하다보면 설치하는 프로그램 모두를 저렇게 바꾸어야 하는 수고가 든다. 


2안 : mod-rpaf 설치  (잘 안됨)

그래서 다른 방법을 찾아보니 누군가가 mod-rpaf를 쓰면 된다고 하였다. 그래서 아래 순서대로 진행을 해 보았다. 

* 다운 받기 (이게 원 사이트에 가면 잘 다운받을 수가 없어서 아래 구글에서 받았다.)

 - 파일 : https://code.google.com/p/nginxda/downloads/detail?name=mod_rpaf-0.6.tar.gz&can=2&q=

 - 위치 : /usr/local/src 

 

* 압축 풀기

 - tar xzvf mod_rpaf-0.6.tar.gz

 - cd mod_rpaf-0.6

* 설치 

 apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c

 

* httpd.conf 수정

 - 아래 추가 

LoadModule rpaf_module modules/mod_rpaf-2.0.so

# mod_rpaf Configuration

RPAFenable On

RPAFsethostname On

RPAFproxy_ips 127.0.0.1 10.0.0.1

RPAFheader X-Forwarded-For

 -> 127.0.0.1 -> 서버 ip로 변경  (10.0.0.1은 삭제)

 

저렇게 하고 httpd를 다시 실행시켰는데, 잘 동작하지 않았다. 첫번째 방법은 프로그램 설치할때만 작업을 해야 하는데, 이번 방법은 뭔가 적용이 잘 안되었다. 

 

3안 : 프로그램 추가 없이 변수 전달로 처리

이 방법을 쓰니 "HTTP_X_FORWARDED_FOR" 변수를 "REMOTE_ADDR" 변수로 연결하는데, 설치하는 프로그램에 관계없이 프로그램을 설치할때 httpd.conf만 잘 수정하면 된다.

 

* default.vcl 수정

 - 아래 항목을 추가

# Below is a commented-out copy of the default VCL logic.  If you

# redefine any of these subroutines, the built-in logic will be

# appended to your code.

 sub vcl_recv {

     if (req.restarts == 0) {

        if (req.http.x-forwarded-for) {

            set req.http.X-Forwarded-For =

                req.http.X-Forwarded-For + ", " + client.ip;

        } else {

            set req.http.X-Forwarded-For = client.ip;

        }

    }

  

 if (req.request != "GET" &&

       req.request != "HEAD" &&

       req.request != "PUT" &&

       req.request != "POST" &&

       req.request != "TRACE" &&

       req.request != "OPTIONS" &&

       req.request != "DELETE") {

#         /* Non-RFC2616 or CONNECT which is weird. */

         return (pipe);

     }

     if (req.request != "GET" && req.request != "HEAD") {

#         /* We only deal with GET and HEAD by default */

         return (pass);

     }

     if (req.http.Authorization || req.http.Cookie) {

#         /* Not cacheable by default */

         return (pass);

     }

   return (lookup);

  #   return (pipe);

 }

#

 sub vcl_pipe {

#     # Note that only the first request to the backend will have

#     # X-Forwarded-For set.  If you use X-Forwarded-For and want to

#     # have it set for all requests, make sure to have:

      set bereq.http.connection = "close";

#     # here.  It is not set by default as it might break some broken web

#     # applications, like IIS with NTLM authentication.

     return (pipe);

 }

 

 

* varnish 재실행

 - service varnish restart 

 

 

* varnish_client_ip.php 생성

/etc/httpd/conf.d/ 에 varnish_client_ip.php 를 생성한다. 내용은 아래와 같다.

<?php

if( isset( $_SERVER[ 'HTTP_X_FORWARDED_FOR' ] ) ) {

  $_SERVER[ 'REMOTE_ADDR' ] = $_SERVER[ 'HTTP_X_FORWARDED_FOR' ];

}

 

* httpd.conf

1. 추가 :  LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" varnish

 

2. 수정 (varnish도 varnishcombined도 

     ErrorLog logs/seven2015-error_log varnish

     Customlog logs/seven2015-access_log varnish

 

3. VirtualHost 수정

아래 코드를 넣는다. 

<Directory "/var/www/www.example.com">

    php_value auto_prepend_file "/etc/httpd/conf.d/varnish_client_ip.php"

</Directory>

 

4. 예제 

이제, 아래와 같은 샘플을 넣으면 된다. 

<VirtualHost 127.0.0.1:8080>

    ServerAdmin webmaster@dummy-host.example.com

    DocumentRoot /var/www/www.example.com

    ServerName www.example.com

    ErrorLog /var/log/httpd/example.com-error_log

    LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" varnish

    CustomLog /var/log/httpd/example.com_log varnish

    <Directory "/var/www/www.example.com">

       php_value auto_prepend_file "/etc/httpd/conf.d/varnish_client_ip.php"

    </Directory>

</VirtualHost>  

5. 아파치 재실행

/usr/sbin/apachectl restart

 

이 방법을 쓰면 127.0.0.1이 아니고 제대로 접속자 ip를 볼 수 있다. 그리고 설치하는 프로그램이나 코드도 변수 수정없이 할 수 있다. 

 

 

* 참조 

 - http://stackoverflow.com/questions/10024877/varnish-client-ip-not-logging-in-apache-logs

 - http://stackoverflow.com/questions/19311164/serverremote-addr-returns-127-0-0-1

 - http://old.drupion.com/resources/downloads/mod-rpaf

 - https://code.google.com/p/nginxda/downloads/detail?name=mod_rpaf-0.6.tar.gz&can=2&q=

 - http://www.techinfobest.com/getting-real-client-ip-through-varnish/

Comments

공유지기 2019.03.09 15:13
3안의 default.vcl 수정에서,

req.request 는 모두 req.method로 바꿔야 한다네요. varnish 4에서 바뀌었다고 합니다.


출처 : https://github.com/varnish/libvmod-vsthrottle/issues/9
공유지기 2019.03.09 15:17
그리고  sub vcl_recv 절 끝부분에 있는

  return (lookup);
  #  return (pipe);



  #  return (lookup);
    return (pipe);

로 바꿔줘야 합니다.
공유지기 2019.03.09 19:15
그리고 * varnish_client_ip.php 생성 이거도 안해도 됩니다.