워드프레스에 역방향 프록시 설정 시 주의할 점
지난번 블로그 글에서 잘못된 정보를 제공하였기에 이에 대하여 정정하고자 글을 쓴다. Synology NAS에서 Docker를 이용해 워드프레스를 운영하면, 역방향 프록시(Reverse Proxy, 리버스 프록시) 문제로 인해 댓글을 다는 사용자의 IP가 제대로 잡히지 않는다고 했었는데, 사실이 아니었음을 밝힌다.
Synology에는 문제가 없다
본인이 순정주의자라고 말하긴 했지만, 순정을 좋아한 나머지 원래의 기능이 어떻게 구현되는지 그 원리를 알아보고자 하는데 조금 소홀했던 것 같다. 우선 핵심부터 말하자면, Synology의 역방향 프록시 기능에는 아무 문제가 없었다.
DSM웹의 백엔드는 Nginx로 구현되어 있다. 그 설정값은 SSH로 접속하여 확인해보면 /etc/nginx/app.d/server.ReverseProxy.conf
파일에 저장되어 있음을 알 수 있다. 역방향 프록시 설정을 추가할 때마다 conf 파일 내에 설정한 내용이 추가되는데, 모든 역방향 프록시 설정값에 다음과 같이 코드가 추가되어 있다.
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_intercept_errors on;
proxy_http_version 1.1;
프록시 환경에서 Client의 IP값을 알아내기 위한 X-Forwarded-For
헤더가 설정되어 있다. 다시말해서 Synology NAS에는 아무런 문제가 없다는 말이었다. 그렇다면 문제는 다른 곳에 있다는 말인데…
워드프레스가 진범이었다
정말 몰랐다. 워드프레스에서 이 문제가 굉장히 오래된 이슈였다는 것을. 관련된 키워드로 이것저것 검색하다보니 Github Gist 쪽에서 해결책이 제시되었는데 이게 세상에 3년전 코드였다.
알고봤더니 서버에 X-Forwarded-For
헤더 정보가 제대로 들어와도, 워드프레스 코드 자체에서 이를 제대로 써먹질 않는 것이었다. 위의 코드를 wp-config.php
파일에 넣어주면 Client IP를 제대로 읽어올 수 있다.
그런데, 정말?
아무리 그래도 워드프레스가 이렇게 허술할까 싶어서 관련 항목들을 좀 찾아보았다. 워드프레스 자체에서는 정말로 이 문제에 대해서 아무 생각이 없을까? 그건 아닐것 같았다. Automattic이 그렇게 큰 회사는 아니라지만 그래도 워드프레스급 프로젝트가 되면 이런 상황 정도는 알고 있을게 분명한데.
찾아다니다보니 워드프레스 코덱스 사이트까지 들어가보게 되었다. 워드프레스야, Hook를 이용해 온갖 잡다한 플러그인을 다 만들수 있으니 관련 Hook가 있지 않을까 싶었다. 그래서 찾아낸게 아래의 문서다.
Since it is easy to forge an X-Forwarded-For header the given information should be used with care. The last IP address is always the IP address that connects to the last proxy, which means it is the most reliable source of information. X-Forwarded-For data can be used in a forward or reverse proxy scenario.
Plugin API/Filter Reference/pre comment user ip
지금 보니 워드프레스는 이 건에 대해서 인식을 하고는 있었다. 다만 X-Forwarded-For
헤더는 너무 위조하기가 쉬워서 이 부분에 대해서 주의깊게 사용해야 한다고 생각한것 같다. 페이지 하단에는 위의 Gist 코드보다 좀더 자세한 PHP 코드를 언급하면서, 이걸 이용해서 역방향 프록시 환경에 대응하라고 되어 있었다.
//applied to the comment author's IP address prior to saving the comment in the database.
add_filter( 'pre_comment_user_ip', 'auto_reverse_proxy_pre_comment_user_ip');
function auto_reverse_proxy_pre_comment_user_ip()
{
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
if (!empty($_SERVER['X_FORWARDED_FOR'])) {
$X_FORWARDED_FOR = explode(',', $_SERVER['X_FORWARDED_FOR']);
if (!empty($X_FORWARDED_FOR)) {
$REMOTE_ADDR = trim($X_FORWARDED_FOR[0]);
}
}
/*
* Some php environments will use the $_SERVER['HTTP_X_FORWARDED_FOR']
* variable to capture visitor address information.
*/
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$HTTP_X_FORWARDED_FOR= explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
if (!empty($HTTP_X_FORWARDED_FOR)) {
$REMOTE_ADDR = trim($HTTP_X_FORWARDED_FOR[0]);
}
}
return preg_replace('/[^0-9a-f:\., ]/si', '', $REMOTE_ADDR);
}
아까보다 훨씬 더 복잡해졌지만 좀더 다양한 환경에 대응할 수 있도록 되어 있는것 같아 보인다. 위의 코드를 테마함수 파일(테마 폴더 안의 function.php
)에 집어넣거나 하면 구동될 것이다. 그런데 생각해보니 이 코드를 테마 바꿀때나 환경 변경할때마다 집어넣어 수정하려면 너무나 귀찮을 것 같다는 생각이 들었다.
아예 플러그인으로 제작
그래서 저 코드를 쉽게 활성화 시킬 수 있도록 아예 워드프레스 플러그인으로 제작해버렸다. 이제 제 아무리 환경을 바꿔도 이 플러그인 하나 깔면 바로 구동될 것이다. 플러그인은 처음 만들어봤지만 이정도 간단한 코드는 금방 만들수 있었다. 워드프레스 만만세!
본인의 프로젝트 배포 페이지에 가면 플러그인 ZIP 파일을 다운로드 받을 수 있다. 추후에 저 코드가 변경된다거나 하면 수정해야하니까 일단은 버전 0.1로 해놓았다. 플러그인을 설치하면 다음과 같이 플러그인 목록에 추가될 것이다.
댓글없음