지난 번에 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/
req.request 는 모두 req.method로 바꿔야 한다네요. varnish 4에서 바뀌었다고 합니다.
출처 : https://github.com/varnish/libvmod-vsthrottle/issues/9
return (lookup);
# return (pipe);
를
# return (lookup);
return (pipe);
로 바꿔줘야 합니다.