.htaccess

얼마전 태터툴즈 Support 센터를 방문했다가 이번에 버전업된 1.0.4의 경우 루트에 index.php 파일이 없는데 어떻게된 일인지를 묻는 질문을 보았다. 대부분의 사람들은 루트에 당연히 index.php 파일이 있어야 하는 것으로 알고 있다.

태터툴즈의 index.php 파일을 삭제해도 태터툴즈는 정상적으로 동작한다. 그 이유는 바로 mod_rewrite 모듈때문이다. 이 모듈은 쉽게 말해서 요청된 URL을 서버상에서 실시간으로 변경할 수 있는 모듈이다. 태터툴즈의 경우 하위 버전과의 호환성과 동작의 상당수를 이 모듈에 의존한다. 따라서 mod_rewrite 모듈을 지원하지 못하는 서버에는 1.x 버전을 깔 수 없다.

그러면 루트에 index.php 파일이 없어도 정상적으로 동작하는 이유는 무었일까? 조금 이상하게 생각할지 모르지만 그 핵심은 .htaccess에 있다. .htaccess의 내용을 보면 다음과 같은 내용이 포함되어 있다.

RewriteRule ^$ blog/index.php [E=SURI:1,L]

아무것도 아닌 것 같지만 이 문장이 의미하는 바는 요청한 로컬 주소에 경로나 파일이 포함되어 있지 않으면 blog/index.php 파일을 호출하라는 의미이다. 여기서 ^는 정규식에서 시작을 의미하며, $는 끝을 의미한다. 시작과 끝 사이에 아무런 문자도 존재하지 않기때문에 사용자가 https://offree.net/처럼 주소를 입력하면 루트의 index.php 파일이 아니라 blog/index.php 파일이 호출된다.

이 줄 바로 밑에는 다음과 같은 행이 포함되어 있는 것을 알 수 있다.

RewriteRule ^[0-9]+$ blog/item.php [E=SURI:1,L]

이 문장의 의미는 로컬 주소가 하나 이상의 숫자([0-9]+)로 구성되어 있으면 blog/item.php 파일을 호출하라는 의미이다. 즉, 주소가 https://offree.net/454 처럼되어 있으면 blog/item.php 파일이 호출된다는 의미이다. 태터툴즈 0.9 버전에서는 RSS 피드로서 /index.xml 파일을 사용했고, 1.x에서는 /rss를 사용한다. 그러나 어떤 주소를 입력해도 동일한 RSS 피드가 생성된다. 그 이유는 다음의 두 문장때문이다.

RewriteRule ^index\.xml$ blog/rss/index.php [E=SURI:1,L]
RewriteRule ^(.+)$ blog/$1/index.php [E=SURI:1,L]

첫번째 문장은 요청한 로컬 주소가 index.xml 파일인 경우 blog/rss/index.php를 호출하는 문장이며, 두번째 문장은 요청한 로컬 주소가 임의의 문자로 구성되어 있으면 blog/임의의 문자/index.php 파일을 실행하는 문장이다. 만약 예를 들어 rss를 요청한 경우 blog/rss/index.php를 호출하게된다. 따라서 주소에 index.xml를 입력하든 rss를 입력하던 동일한 결과를 얻게된다.

조금 혼란스러워 보이지만 이 모든 것은 Perl의 정규식을 사용한 것(PHP의 경우 PREG 함수)이다. Perl정규식에대해 알고 싶다면 CGI 강좌 중 문자열 일치대치와 변환을 참고하면 된다. 아울러 아파치의 mod_rewrite에 알고 싶다면 Apache mod_rewrite와 바로 적용할 수 있는 예제로 가득찬 URL Rewriting Guide를 참조하기 바란다.

트래픽 플러그인 오류

얘기가 잠시 옆길로 샛다. 2004년부터 지금까지 블로그를 운영하면서 트래픽 초과가 발생한 일이 없었기때문에 400M의 트래픽도 충분할 것으로 알고 Cafe24.com의 64bit 광절약형을 선택했다. 그런데 어제 트래픽 초과가 발생하는 것을 보고 태터툴즈 플러그인트래픽을 표시해주는 플러그인을 설치했다. 플러그인이 정상적으로 동작하는지 확인하기위해 블로그에 접속하자 그림과 같은 오류 메시지가 나타나는 것이었다.

물론 오류 메시지처럼 경로가 틀려서 발생한 문제일 수도 있다. 그러나 난 블로그 주소가 https://offree.net/이므로 트래픽 주소는 https://offree.net/throttle-me가 맞다. 오류는 주소가 틀려서 발생한 것이 아니라 태터툴즈에서 .htaccess 파일을 생성하면서 트래픽에대한 부분을 고려하지 않았기때문에 발생한 현상이다. 이러한 현상이 발생하게된 원인은 다음 문장이다.

RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [L]

이 문장은 요청한 파일 이름이 디렉토리이면 자동으로 파일 이름에 /를 붙여주는 문장이다. /throttle-me는 서버의 설정에따라 다소 달라지겠지만 링크된 디렉토리로 간주된다. 따라서 /throttle-me를 요청하면 주소는 자동으로 /throttle-me/ 로 변경된다. 실제 이 주소를 입력해보면 알 수 있지만 이 주소를 입력하는 경우 서버에 따라 404 File not found 메시지가 나타난다. 따라서 이 문제를 고치려면 .htaccess 파일을 다음처럼 수정하면 된다.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} /throttle-me
RewriteRule (.*) - [L]
RewriteCond %{REQUEST_FILENAME} /twatch
RewriteRule (.*) - [L]
RewriteCond %{ENV:REDIRECT_SURI} !^$
RewriteRule (.*) - [L]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [L]
RewriteRule ^$ blog/index.php [E=SURI:1,L]
RewriteRule ^[0-9]+$ blog/item.php [E=SURI:1,L]
RewriteRule ^favicon\.ico$ blog/favicon.ico.php [E=SURI:1,L]
RewriteRule ^index\.gif$ blog/index.gif.php [E=SURI:1,L]
RewriteCond %{QUERY_STRING} (^|&)pl=([0-9]+)
RewriteRule ^index\.php$ %2 [NE,L]
RewriteRule ^index\.php$ blog/index.php [E=SURI:1,L]
RewriteRule ^index\.xml$ blog/rss/index.php [E=SURI:1,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d  
RewriteRule !^(blog|cache)/ - [L]       
RewriteRule ^(entry|attachment|category|keylog|tag|search|plugin)/? blog/$1/index.php [E=SURI:1,L]
RewriteRule ^(.+)/[0-9]+$ blog/$1/item.php [E=SURI:1,L]
RewriteRule ^(.+)$ blog/$1/index.php [E=SURI:1,L]

여기서

RewriteCond %{REQUEST_FILENAME} /twatch
RewriteRule (.*) - [L]

TraceWatch를 웹 통계 프로그램으로 사용하기 때문에 삽입한 부분이다. 만약 TraceWatch를 웹 통계 프로그램으로 사용하지 않는 경우에는 이 두줄을 삭제하면된다. 이 코드를 삽입한 이유는 웹 통계 보기 주소에 해당하는 https://offree.net/twatch를 입력하면 그림처럼 페이지가 비정상적으로 표시되며, 꼭 twatch/처럼 /를 입력해야 정상적으로 표시되기 때문이다.

물론 이 코드를 삽입하면 /twatch를 삽입하면 /twatch/를 입력하든 정상적으로 표시된다.

관련 글타래