2013.05.24 22:56
* 아파치 Access Log 에서의 IP Logging
일반적인 아파치 로그 설정
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
%v : 가상호스트명
%h : 리모트 IP
로드밸런서를 거치게 되면 %h 의 리포트 IP가 로드밸런서 IP로 찍히게 됩니다.
LogFormat "%v %{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
여기서 %h 를 %{X-Forwarded-For}i 로 변경해 주서야 합니다.
HTTP Header 값인 X-Forwarded-For 를 바로 사용하는 것입니다.
- access log 포멧
포맷 | 의미 |
%a | 원격지 IP 주소 |
%A | 로컬 IP 주소 |
%B | HTTP 헤더를 제외하고 전송된 바이트 |
%b | HTTP 헤더를 제외하고 전송된 바이트. CLF 포맷에서는 , 전송된 것이 없을 경우 0 으로 표시하기 보다는 ‘-‘ 로 표시한다. |
%{FOOBAR}e | 서버에 의해 지정된 환경변수 |
%f | 파일 이름 |
%h | 원격지 호스트 |
%H | 요청한 프로토콜 |
%{Foobar}i | Foobar 의 내용: 클라이언트에서 서버로 요청된 헤더라인으로 예를 들자면, Referer 헤더일 경우 %{Referer}i 로 사용되어 진다. |
%l | 원격지 사용자이름 (이것이 사용되어 지기 위해서는 IdentityCheck 가 반드시 enable 되어져 있어야 한다) |
%m | 요청방식 |
%{Foobar}o | 서버에서 응답되어 지는 HTTP 헤더. 예를들면 : %{Content-Type}o, %{Last-Modified}o |
%p | 요청을 처리하는 서버의 참조적인 포트 |
%P | 현 요청을 처리하고 있는 아파치 자식 프로세서의 프로세스 ID |
%q | 쿼리 문자열 (쿼리가 있을 경우 “?” 뒤로 쿼리문이 포함되며 그렇지 않을 경우 공백으로 처리된다) |
%r | HTTP 메소드를 포함한 요청의 첫 라인 |
%s | HTTP 상태코드. 만약 클라이언트의 요청이 내부적인 리다이렉트를 발생시켰을 경우 %s 는 초기 요청의 상태코드를 %>s 는 최종상태 코드를 포함하게 된다. 일반적으로, %s 의 사용 보다는 %>s 가 유용하다. |
%t | 요청한 시간과 날짜 (standard english format) |
%{format}t | strftime() function 을 이용한 포맷형식에 따른 시간 [Day/Month/Year:Hours:Minutes:Seconds Time Zone] |
%T | 요청을 처리하는데 걸린 시간 (초) |
%u | 인증이 요청된 원격 사용자 이름 |
%U | 요청된 URL |
%v | 요청을 처리하는 서버의 참조적인 서버 이름 |
%V | UseCanonicalName 설정에 따른 서버 이름 |
* reverse proxy add forward module로 해결하기
가상서버에서 방문자 IP가 잡히지 않는 문제는 아파치로그 뿐만이 아닌 웹솔루션 소스를 뜯어 고쳐야 하는 것과 사이트 관리상에 상당한 문제점이 발생할 수 있습니다.
따라서 이러한 문제를 근본적으로 해결할 수 있는 것이 바로 reverse proxy add forward(RPAF)입니다.
이 모듈을 올려주면 이러한 문제가 해결이 되므로 가상서버, VPS, UML에서는 필수적인 모듈입니다.
1. 설치방법 방법은 http://www.just4fun.co.kr/drupal/?q=node/233 에서 소개한 것처럼 하면 됩니다.
wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
tar xzvf mod_rpaf-0.6.tar.gz
cd mod_rpaf-0.6
/usr/local/httpd/bin/apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c
2. mod_rpaf-2.0라는 공유객체가 생성이 되면 아파치 모듈에 자동 복사되어 넣어집니다. LoadModue에도 자동 추가 됩니다.(httpd.conf)
LoadModule rpaf_module modules/mod_rpaf-2.0.so
3. 다음을 2번 아래에 추가합니다.
RPAFenable On
RPAFsethostname On
RPAFproxy_ips [내부IP]
여기서 내부IP는 자신의 가상서버의 IP가 아닌 또다른 내부IP입니다. 제생각에는 포워딩을 해주는 프록시 IP같은데, 아파치 로그를 보면 계속 어떤 특정한 IP로 찍히는 것을 확인할 수 있을 것입니다. 그것을 기입합니다. (예를들면 10.0.0.177 또는 192.0.0.20)
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 10.0.0.177
4. 이제 아파치를 재가동하면 정상적으로 IP가 기록되는 것을 로그파일로 확인할 수 있습니다.
5. 로그설정에서 IP(X-Forwarded-For)식으로 2개를 활용하면 IP(실제IP)가 잡힙니다.
*** 간혹 프록시를 이용해서 장난치는 경우도 실제IP를 파악할 수 있습니다
LogFormat "%v %{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" X-Forwarded-For
CustomLog /var/log/apache/www.example.com-xforwarded.log X-Forwarded-For
EX)
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
LogFormat "%v %{X-Forwarded-For}i %l %u %t \"%r\" %>s %b" X-Forwarded-For
* X-Forwarded-For 헤더를 이용한 Apache ACL 설정
이 설정은 추가 모듈을 필요로 하지 않으며, 현재 Apache에서 제공하는 ACL 기능만으로 구현이 가능합니다.
설정 예)
X-Forwarded-For 헤더값으로 넘어오는 IP가 172.21.21.* network인 모든 Client와 192.168.122.111 인 Client만 접속을 허용하고 나머지에 대해서는 접속을 거부(403 access deny) 함.
<Directory "/app/apache/htdocs">
SetEnvIf X-Forwarded-For ^172\.21\.21\.* allow_ip
SetEnvIf X-Forwarded-For ^192\.168\.122\.111 allow_ip
Order deny,allow
Deny from all
Allow from env=allow_ip
< /Directory>
위의 allow_ip는 중복해서 계속 추가해서 쓰면 됩니다.
Cache를 통한 서비스를 제공하다보면 오리진쪽에서는 실제 클라이어트 IP를 일반적인 header나 로그로 확인을 할 수가 없습니다. 이럴때 X-Forwarded-For 를 사용하면 실제 클라이언트 IP확인이 가능합니다.
* Tomcat 의 Access log의 경우
// Look for a proxy address firstString
_ip = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
// If there is no proxy, get the standard remote address
If (_ip == "" || _ip.ToLower == "unknown")
_ip = Request.ServerVariables["REMOTE_ADDR"];
Based on code from OxyScripts.
function GetUserIP() {
if (isset($_SERVER)) {
if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]))
return $_SERVER["HTTP_X_FORWARDED_FOR"];
if (isset($_SERVER["HTTP_CLIENT_IP"]))
return $_SERVER["HTTP_CLIENT_IP"];
return $_SERVER["REMOTE_ADDR"]; }
if (getenv('HTTP_X_FORWARDED_FOR'))
return getenv('HTTP_X_FORWARDED_FOR');
if (getenv('HTTP_CLIENT_IP'))
return getenv('HTTP_CLIENT_IP');
return getenv('REMOTE_ADDR');}
String ipaddress = request.getHeader("HTTP_X_FORWARDED_FOR");
if (ipaddress == null)
ipaddress = request.getRemoteAddr();
ipaddress = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
if ipaddress = ""
then
ipaddress = Request.ServerVariables("REMOTE_ADDR"
)end if
<CFCOMPONENT>
<CFIF #CGI.HTTP_X_Forwarded_For# EQ "">
<CFSET ipaddress="#CGI.Remote_Addr#">
<CFELSE>
<CFSET ipaddress="#CGI.HTTP_X_Forwarded_For#">
</CFIF>
</CFCOMPONENT>
$ip = $req->header('Client-IP') || $req->header('Remote-Addr');
if ($req->header('X-Forwarded-For'))
{ $proxy = $ip; $ip = $req->header('X-Forwarded-For');}
If you know anymore, just ping them in my general direction and they can be added.