mirror of
https://github.com/apache/httpd.git
synced 2025-05-30 01:07:09 +03:00
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@421086 13f79535-47bb-0310-9956-ffa450edef68
2006 lines
63 KiB
XML
2006 lines
63 KiB
XML
<?xml version="1.0" encoding="EUC-KR"?>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="ko" xml:lang="ko"><head><!--
|
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
This file is generated from xml source: DO NOT EDIT
|
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
-->
|
|
<title>URL 재작성 지침서 - Apache HTTP Server</title>
|
|
<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
|
|
<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" />
|
|
<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" />
|
|
<link href="../images/favicon.ico" rel="shortcut icon" /></head>
|
|
<body id="manual-page"><div id="page-header">
|
|
<p class="menu"><a href="../mod/">모듈</a> | <a href="../mod/directives.html">지시어들</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">용어</a> | <a href="../sitemap.html">사이트맵</a></p>
|
|
<p class="apache">Apache HTTP Server Version 2.3</p>
|
|
<img alt="" src="../images/feather.gif" /></div>
|
|
<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div>
|
|
<div id="path">
|
|
<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.3</a> > <a href="./">Miscellaneous Documentation</a></div><div id="page-content"><div id="preamble"><h1>URL 재작성 지침서</h1>
|
|
<div class="toplang">
|
|
<p><span>가능한 언어: </span><a href="../en/misc/rewriteguide.html" hreflang="en" rel="alternate" title="English"> en </a> |
|
|
<a href="../ko/misc/rewriteguide.html" title="Korean"> ko </a></p>
|
|
</div>
|
|
<div class="outofdate">이 문서는 최신판 번역이 아닙니다.
|
|
최근에 변경된 내용은 영어 문서를 참고하세요.</div>
|
|
|
|
<div class="note">
|
|
<p>원저자<br />
|
|
<cite>Ralf S. Engelschall <rse@apache.org></cite><br />
|
|
1997년 12월</p>
|
|
</div>
|
|
|
|
<p>이 문서는 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code> <a href="../mod/mod_rewrite.html">참조 문서</a>를 보충한다.
|
|
이 문서는 웹관리자가 실제 작업에서 부딪치게되는 전형적인
|
|
URL관련 문제를 해결하기위해서 어떻게 아파치
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용하는지 설명한다. URL
|
|
재작성 규칙을 설정하여 문제를 해결하는 방법을 자세히 설명한다.</p>
|
|
|
|
</div>
|
|
<div id="quickview"><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#ToC1"><code>mod_rewrite</code> 소개</a></li>
|
|
<li><img alt="" src="../images/down.gif" /> <a href="#ToC2">실용적인 해결책</a></li>
|
|
<li><img alt="" src="../images/down.gif" /> <a href="#url">URL 구조</a></li>
|
|
<li><img alt="" src="../images/down.gif" /> <a href="#content">컨텐츠 다루기</a></li>
|
|
<li><img alt="" src="../images/down.gif" /> <a href="#access">접근 제한</a></li>
|
|
<li><img alt="" src="../images/down.gif" /> <a href="#other">기타</a></li>
|
|
</ul></div>
|
|
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
|
<div class="section">
|
|
<h2><a name="ToC1" id="ToC1"><code>mod_rewrite</code> 소개</a></h2>
|
|
|
|
|
|
|
|
<p>아파치 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code> 모듈은 굉장하다.
|
|
즉, URL을 조작할 수 있는 강력하고 실로 정교한 모듈이다.
|
|
상상해왔던 거의 모든 종류의 URL 조작이 가능하다. 그러나
|
|
그 대가로 사용하기 복잡하다. <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>의
|
|
최대 단점은 초보자가 이해하고 사용하기 쉽지 않다는 점이다.
|
|
심지어 아파치 전문가도 종종 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>의
|
|
새로운 용도를 발견한다.</p>
|
|
|
|
<p>다른 말로: <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>에 대해 당신은
|
|
처음에 겁을 먹고 절대로 다시 사용하지 않거나, 강력함에 매료되어
|
|
앞으로 삶 동안 사랑에 빠질 것이다. 이 글은 첫번째 경우를
|
|
막기위해 이미 알려진 몇가지 성공사례를 소개하려고 한다.</p>
|
|
|
|
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
|
<div class="section">
|
|
<h2><a name="ToC2" id="ToC2">실용적인 해결책</a></h2>
|
|
|
|
|
|
|
|
<p>이제 내가 직접 만들었거나 다른 사람들이 만든 많은 실용적인
|
|
해결책이 나온다. 예제에서 URL 재작성의 흑마술을 마음껏 배우길
|
|
바란다.</p>
|
|
|
|
<div class="warning">주의: 서버 설정에 따라 상황에 맞게
|
|
예제를 조금 수정해야 할 경우가 있다. 예를 들어, 추가로
|
|
<code class="module"><a href="../mod/mod_alias.html">mod_alias</a></code>, <code class="module"><a href="../mod/mod_userdir.html">mod_userdir</a></code>
|
|
등을 사용한다면 <code>[PT]</code> 플래그를 추가한다. 혹은
|
|
주서버설정/가상호스트 사용장소가 아닌 <code>.htaccess</code>
|
|
사용장소에 알맞게 규칙을 수정할 수도 있다. 사용하기 전에
|
|
항상 규칙이 어떤 기능을 하는지 이해하도록 해라. 그러면 문제를
|
|
피할 수 있다.</div>
|
|
|
|
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
|
<div class="section">
|
|
<h2><a name="url" id="url">URL 구조</a></h2>
|
|
|
|
|
|
|
|
<h3>기준이 되는 URL</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>한 리소스에 대해 여러 URL을 가지는 웹서버가 있다.
|
|
보통 (실제 사용하고 알려져야 할) 기준이 되는 URL과,
|
|
단축 혹은 내부 용도의 URL이 있다. 사용자가 요청에
|
|
어떤 URL을 사용하던지 기준이 되는 URL만을 보여줘야
|
|
한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>기준이 되지않는 모든 URL을 브라우저가 알도록 고치기위해
|
|
외부 HTTP 리다이렉션한다. 예를 들어 아래 규칙은
|
|
<code>/~user</code>를 기준이 되는 <code>/u/user</code>로
|
|
대체하고, <code>/u/user</code> 마지막에 슬래쉬가 없다면
|
|
추가한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^/<strong>~</strong>([^/]+)/?(.*) /<strong>u</strong>/$1/$2 [<strong>R</strong>]
|
|
RewriteRule ^/([uge])/(<strong>[^/]+</strong>)$ /$1/$2<strong>/</strong> [<strong>R</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>기준이 되는 호스트명</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>...</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<div class="example"><pre>
|
|
RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
|
|
RewriteCond %{HTTP_HOST} !^$
|
|
RewriteCond %{SERVER_PORT} !^80$
|
|
RewriteRule ^/(.*) http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
|
|
RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
|
|
RewriteCond %{HTTP_HOST} !^$
|
|
RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3><code>DocumentRoot</code>를 옮긴 경우</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>웹서버의 <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code>는 보통 URL
|
|
"<code>/</code>"과 직접 관련있다. 그러나 이곳에 모든
|
|
자료가 있지 않고, 자료가 다른 여러 곳에 흩어져있는
|
|
경우가 있다. 예를 들어 인트라넷 사이트에 (외부를 위한
|
|
홈페이지) <code>/e/www/</code>와 (인트라넷을 위한
|
|
홈페이지) <code>/e/sww/</code>가 있다고 하자. 이제
|
|
<code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code>가
|
|
<code>/e/www/</code>이기때문에, 요청에서 페이지에
|
|
포함된 그림 등을 이곳에서 가져와야 한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>우리는 URL <code>/</code>를 <code>/e/www/</code>로
|
|
리다이렉션만 하면 된다. 사소해 보이지만 실제로
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용해서만 가능하다.
|
|
(<code class="module"><a href="../mod/mod_alias.html">mod_alias</a></code> 등이 제공하는) URL
|
|
<em>Alias</em> 같은 전형적인 방법은 <em>앞부분</em>만
|
|
찾는다. <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code>가
|
|
모든 URL의 앞부분이기때문에 이 방법을 사용하여 리다이렉션을
|
|
할 수 없다. <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용하면
|
|
진짜 간단하다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteRule <strong>^/$</strong> /e/www/ [<strong>R</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>마지막 슬래쉬 문제</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>디렉토리를 지칭하는 URL의 마지막 슬래쉬 문제가
|
|
없다면 모든 웹관리자는 환호할 것이다. 슬래쉬가 없다면,
|
|
즉 <code>/~quux/foo/</code> 대신 <code>/~quux/foo</code>를
|
|
사용하면 서버가 <code>foo</code>라는 <em>파일</em>을
|
|
찾기때문에 오류가 발생한다. 파일이 디렉토리이기때문에
|
|
받아들이지 않는다. 대부분의 경우 보통 서버가 자동으로
|
|
URL을 고치지만, 가끔 직접 해줘야 할 경우가 있다. 예를
|
|
들어, CGI 스크립트 등으로 복잡한 URL 재작성을 한 후에
|
|
그러하다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>이 미묘한 문제의 해결방법은 서버가 자동으로 마지막
|
|
슬래쉬를 추가하는 것이다. 브라우저가 나머지 그림 등을
|
|
올바로 요청할 수 있도록, 외부 리다이렉션을 해야 한다.
|
|
내부 리다이렉션을 한다면 디렉토리 페이지에만 동작하여
|
|
이 페이지가 상대 URL로 포함하는 그림을 브라우저가
|
|
요청할때 찾을 수 없다. 예를 들어, 외부 리다이렉션을
|
|
사용하지 않을때 <code>/~quux/foo/index.html</code>에서
|
|
<code>image.gif</code>를 요청하면
|
|
<code>/~quux/image.gif</code>를 요청하게 된다!</p>
|
|
|
|
<p>그래서 이를 해결하기위해 다음과 같이 설정한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteRule ^foo<strong>$</strong> foo<strong>/</strong> [<strong>R</strong>]
|
|
</pre></div>
|
|
|
|
<p>홈디렉토리의 최상위 <code>.htaccess</code> 파일에
|
|
다음과 같이 설정할 수도 있다. 그러나 처리하는데 부담이
|
|
된다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteCond %{REQUEST_FILENAME} <strong>-d</strong>
|
|
RewriteRule ^(.+<strong>[^/]</strong>)$ $1<strong>/</strong> [R]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>일관된 URL 구조로 만든 웹클러스터</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>인트라넷 웹서버군의 모든 웹서버에 동일하고 일관된
|
|
URL 구조를 만들고 싶다. 즉, 모든 (정의상 서버에 속하여
|
|
서버에 의존적인!) URL을 서버 <em>독립적으로</em> 만든다!
|
|
웹 이름공간에 서버독립적인 동일한 구조를 부여해야 한다:
|
|
URL은 실제 서버를 지칭하면 안된다. 서버군이 자동으로
|
|
실제 서버로 유도한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>먼저 사용자, 그룹, 독립체의 위치 정보를 저장한
|
|
(분산된) 외부맵에 실제 서버 정보를 얻어온다. 외부맵은
|
|
다음과 같은 형식이다</p>
|
|
|
|
<div class="example"><pre>
|
|
user1 server_of_user1
|
|
user2 server_of_user2
|
|
: :
|
|
</pre></div>
|
|
|
|
<p>우리는 이 정보를 각각 <code>map.xxx-to-host</code>
|
|
파일에 저장했다. 다음으로 모든 서버에서 URL이 서버에
|
|
없다면 다음과 같은 URL을,</p>
|
|
|
|
<div class="example"><pre>
|
|
/u/user/anypath
|
|
/g/group/anypath
|
|
/e/entity/anypath
|
|
</pre></div>
|
|
|
|
<p>다음과 같이 리다이렉션한다</p>
|
|
|
|
<div class="example"><pre>
|
|
http://physical-host/u/user/anypath
|
|
http://physical-host/g/group/anypath
|
|
http://physical-host/e/entity/anypath
|
|
</pre></div>
|
|
|
|
<p>아래 규칙은 맵파일을 사용하여 이 작업을 한다 (server0은
|
|
맵에 항목이 없는 경우 사용할 기본서버라고 가정한다):</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
|
|
RewriteMap user-to-host txt:/path/to/map.user-to-host
|
|
RewriteMap group-to-host txt:/path/to/map.group-to-host
|
|
RewriteMap entity-to-host txt:/path/to/map.entity-to-host
|
|
|
|
RewriteRule ^/u/<strong>([^/]+)</strong>/?(.*) http://<strong>${user-to-host:$1|server0}</strong>/u/$1/$2
|
|
RewriteRule ^/g/<strong>([^/]+)</strong>/?(.*) http://<strong>${group-to-host:$1|server0}</strong>/g/$1/$2
|
|
RewriteRule ^/e/<strong>([^/]+)</strong>/?(.*) http://<strong>${entity-to-host:$1|server0}</strong>/e/$1/$2
|
|
|
|
RewriteRule ^/([uge])/([^/]+)/?$ /$1/$2/.www/
|
|
RewriteRule ^/([uge])/([^/]+)/([^.]+.+) /$1/$2/.www/$3\
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>홈디렉토리를 다른 웹서버로 이전</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>많은 웹관리자는 웹서버의 모든 홈디렉토리를 다른
|
|
웹서버로 이전한 경우 해결책을 물어본다. 이 방법은
|
|
이전 서버를 대체할 새로운 서버를 구성하는데 시간이
|
|
걸리는 경우에 필요하다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p><code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용하면 간단하다.
|
|
이전 웹서버는 모든 <code>/~user/anypath</code> URL을
|
|
<code>http://newserver/~user/anypath</code>로
|
|
리다이렉션하면 된다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteRule ^/~(.+) http://<strong>newserver</strong>/~$1 [R,L]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>홈디렉토리 구조 만들기</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>사용자가 수천명인 사이트는 보통 홈디렉토리 구조를
|
|
만든다. 즉, 예를 들어 이름이 사용자명의 첫번째 문자인
|
|
하위디렉토리에 홈디렉토리를 둔다. 그래서,
|
|
<code>/~foo/anypath</code>는
|
|
<code>/home/<strong>f</strong>/foo/.www/anypath</code>이고,
|
|
<code>/~bar/anypath</code>는
|
|
<code>/home/<strong>b</strong>/bar/.www/anypath</code>이다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>물결표시가 있는 URL을 위와 같은 구조로 변환하기위해
|
|
다음 규칙을 사용한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteRule ^/~(<strong>([a-z])</strong>[a-z0-9]+)(.*) /home/<strong>$2</strong>/$1/.www$3
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>파일시스템 재구성</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>이 예는 실로 하드코어적이다: 디렉토리별
|
|
<code>RewriteRules</code>를 매우 많이 사용하여 자료
|
|
자체는 그대로 둔체로 웹에 자료를 자연스럽게 브라우징하도록
|
|
한다. 배경: 나는 1992년 부터 자유롭게 사용할 수 있는
|
|
유닉스 소프트웨어들을 <strong><em>net.sw</em></strong>에
|
|
모아두고 있었다. 이는 내가 컴퓨터과학을 공부하면서
|
|
여러해동안 여가시간에 시스템 관리자와 네트웍 관리자를
|
|
해왔기때문에 내 취미이자 일이다. 매주마다 새로 소프트웨어가
|
|
추가될 때마다 디렉토리를 깊게 만들어왔다:</p>
|
|
|
|
<div class="example"><pre>
|
|
drwxrwxr-x 2 netsw users 512 Aug 3 18:39 Audio/
|
|
drwxrwxr-x 2 netsw users 512 Jul 9 14:37 Benchmark/
|
|
drwxrwxr-x 12 netsw users 512 Jul 9 00:34 Crypto/
|
|
drwxrwxr-x 5 netsw users 512 Jul 9 00:41 Database/
|
|
drwxrwxr-x 4 netsw users 512 Jul 30 19:25 Dicts/
|
|
drwxrwxr-x 10 netsw users 512 Jul 9 01:54 Graphic/
|
|
drwxrwxr-x 5 netsw users 512 Jul 9 01:58 Hackers/
|
|
drwxrwxr-x 8 netsw users 512 Jul 9 03:19 InfoSys/
|
|
drwxrwxr-x 3 netsw users 512 Jul 9 03:21 Math/
|
|
drwxrwxr-x 3 netsw users 512 Jul 9 03:24 Misc/
|
|
drwxrwxr-x 9 netsw users 512 Aug 1 16:33 Network/
|
|
drwxrwxr-x 2 netsw users 512 Jul 9 05:53 Office/
|
|
drwxrwxr-x 7 netsw users 512 Jul 9 09:24 SoftEng/
|
|
drwxrwxr-x 7 netsw users 512 Jul 9 12:17 System/
|
|
drwxrwxr-x 12 netsw users 512 Aug 3 20:15 Typesetting/
|
|
drwxrwxr-x 10 netsw users 512 Jul 9 14:08 X11/
|
|
</pre></div>
|
|
|
|
<p>1996년 7월 이 저장소를 멋있는 웹 인터페이스를 통해
|
|
세상에 공개하기로 결정햇다. "멋있다"는 말은, 최상위
|
|
디렉토리에 CGI 스크립트를 두지 않고도, 저장소 계층구조를
|
|
직접 브라우질하길 바란다는 뜻이다. 왜? 저장소를 나중에
|
|
FTP로도 접근할 수 있도록 만들 예정이였기때문에 웹이나
|
|
CGI와 관련된 내용을 같이 두기 싫었다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>해결책은 두 부분으로 나뉜다: 먼저 디렉토리 수준에서
|
|
필요한 모든 페이지를 동적으로 만드는 CGI 스크립트가
|
|
필요하다. 나는 이 스크립트들을 다음과 같이
|
|
<code>/e/netsw/.www/</code>에 두었다:</p>
|
|
|
|
<div class="example"><pre>
|
|
-rw-r--r-- 1 netsw users 1318 Aug 1 18:10 .wwwacl
|
|
drwxr-xr-x 18 netsw users 512 Aug 5 15:51 DATA/
|
|
-rw-rw-rw- 1 netsw users 372982 Aug 5 16:35 LOGFILE
|
|
-rw-r--r-- 1 netsw users 659 Aug 4 09:27 TODO
|
|
-rw-r--r-- 1 netsw users 5697 Aug 1 18:01 netsw-about.html
|
|
-rwxr-xr-x 1 netsw users 579 Aug 2 10:33 netsw-access.pl
|
|
-rwxr-xr-x 1 netsw users 1532 Aug 1 17:35 netsw-changes.cgi
|
|
-rwxr-xr-x 1 netsw users 2866 Aug 5 14:49 netsw-home.cgi
|
|
drwxr-xr-x 2 netsw users 512 Jul 8 23:47 netsw-img/
|
|
-rwxr-xr-x 1 netsw users 24050 Aug 5 15:49 netsw-lsdir.cgi
|
|
-rwxr-xr-x 1 netsw users 1589 Aug 3 18:43 netsw-search.cgi
|
|
-rwxr-xr-x 1 netsw users 1885 Aug 1 17:41 netsw-tree.cgi
|
|
-rw-r--r-- 1 netsw users 234 Jul 30 16:35 netsw-unlimit.lst
|
|
</pre></div>
|
|
|
|
<p><code>DATA/</code> 하위디렉토리에 위에서 말한 저장소가
|
|
있다. 실제 <strong><em>net.sw</em></strong>의 내용은 보통
|
|
<code>rdist</code>를 사용하여 자동으로 가져온다. 두번째
|
|
부분이 남았다: 어떻게 이 두 구조를 하나의 자연스러운
|
|
URL 구조로 연결하는가? 사용자에게 <code>DATA/</code>
|
|
디렉토리를 감추고, URL마다 적절한 CGI 스크립트를 실행하고
|
|
싶다. 해결책은 다음과 같다: 먼저 서버의 <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code>에서 공개된
|
|
URL <code>/net.sw/</code>를 내부 경로 <code>/e/netsw</code>로
|
|
재작성하기위해 디렉토리별 설정파일에 다음과 같이 설정한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^net.sw$ net.sw/ [R]
|
|
RewriteRule ^net.sw/(.*)$ e/netsw/$1
|
|
</pre></div>
|
|
|
|
<p>첫번째 규칙은 마지막에 슬래쉬가 없는 요청을 위해서
|
|
사용했다! 두번째 규칙이 실제 작업을 한다. 그리고 디렉토리별
|
|
설정파일 <code>/e/netsw/.www/.wwwacl</code>에 결정적인
|
|
설정이 나온다:</p>
|
|
|
|
<div class="example"><pre>
|
|
Options ExecCGI FollowSymLinks Includes MultiViews
|
|
|
|
RewriteEngine on
|
|
|
|
# 앞 부분이 /net.sw/ 로 접근한다
|
|
RewriteBase /net.sw/
|
|
|
|
# 먼저 최상위 디렉토리를
|
|
# cgi 스크립트로 재작성한다
|
|
RewriteRule ^$ netsw-home.cgi [L]
|
|
RewriteRule ^index\.html$ netsw-home.cgi [L]
|
|
|
|
# 브라우저가 디렉토리별 페이지를 요청한 경우
|
|
# 하위디렉토리를 추출한다
|
|
RewriteRule ^.+/(netsw-[^/]+/.+)$ $1 [L]
|
|
|
|
# 이제 재작성을 마친다
|
|
RewriteRule ^netsw-home\.cgi.* - [L]
|
|
RewriteRule ^netsw-changes\.cgi.* - [L]
|
|
RewriteRule ^netsw-search\.cgi.* - [L]
|
|
RewriteRule ^netsw-tree\.cgi$ - [L]
|
|
RewriteRule ^netsw-about\.html$ - [L]
|
|
RewriteRule ^netsw-img/.*$ - [L]
|
|
|
|
# 다른 cgi 스크립트가 처리할
|
|
# 하위디렉토리가 남았다
|
|
RewriteRule !^netsw-lsdir\.cgi.* - [C]
|
|
RewriteRule (.*) netsw-lsdir.cgi/$1
|
|
</pre></div>
|
|
|
|
<p>해석을 위한 힌트:</p>
|
|
|
|
<ol>
|
|
<li>네번째 부분에서 대체 필드('<code>-</code>')가
|
|
없고 <code>L</code> (last) 플래그가 있음을 주목하라</li>
|
|
|
|
<li>마지막 부분에서 첫번째 규칙에 <code>!</code>
|
|
(not) 문자와 <code>C</code> (chain) 플래그를 주목하라</li>
|
|
|
|
<li>마지막 규칙에서 기타 해당하지 않는 모든 경우를
|
|
잡아내는 패턴을 주목하라</li>
|
|
</ol>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>NCSA imagemap을 아파치 <code>mod_imagemap</code>으로</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>사람들은 NCSA 웹서버에서 현대적인 아파치 웹서버로
|
|
자연스럽게 옮겨가길 바란다. 그래서 오래된 NCSA
|
|
<code>imagemap</code> 프로그램을 사용한 페이지를 현대적인
|
|
아파치 <code class="module"><a href="../mod/mod_imagemap.html">mod_imagemap</a></code>로 처리하길 바란다.
|
|
문제는 <code>imagemap</code> 프로그램을
|
|
<code>/cgi-bin/imagemap/path/to/page.map</code>과
|
|
같이 참조하는 하이퍼링크가 많다는 것이다. 아파치는
|
|
<code>/path/to/page.map</code>과 같은 요청을 받아야
|
|
한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>모든 요청에서 앞부분을 동적으로 제거하는 전역 규칙을
|
|
사용한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteRule ^/cgi-bin/imagemap(.*) $1 [PT]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>여러 디렉토리에서 페이지 검색</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>가끔 웹서버가 여러 디렉토리에서 파일을 찾아야 할
|
|
때가 있다. 이 경우 MultiViews나 다른 방법은 도움이
|
|
안된다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>여러 디렉토리에서 파일을 찾는 규칙을 직접 프로그램한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
|
|
# 먼저 custom/에서 찾길 시도하고...
|
|
# ...찾으면 끝!
|
|
RewriteCond /your/docroot/<strong>dir1</strong>/%{REQUEST_FILENAME} -f
|
|
RewriteRule ^(.+) /your/docroot/<strong>dir1</strong>/$1 [L]
|
|
|
|
# 두번째로 pub/에서 찾길 시도한다...
|
|
# ...찾으면 끝!
|
|
RewriteCond /your/docroot/<strong>dir2</strong>/%{REQUEST_FILENAME} -f
|
|
RewriteRule ^(.+) /your/docroot/<strong>dir2</strong>/$1 [L]
|
|
|
|
# 못찾으면 다른 Alias나 ScriptAlias 지시어 등으로 진행한다.
|
|
RewriteRule ^(.+) - [PT]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>URL에 따라 환경변수를 설정한다</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>요청들간에 상태정보를 유지하기위해 URL에 정보를
|
|
인코딩하는 방법도 있다. 그러나 단지 이 정보를 제거하기위해
|
|
모든 페이지에 CGI wrapper를 사용하고 싶지 않다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>재작성 규칙을 사용하여 상태정보를 추출하고, 추출한
|
|
정보를 나중에 XSSI나 CGI에서 사용하기위해 환경변수에
|
|
저장한다. 그래서 URL <code>/foo/S=java/bar/</code>는
|
|
<code>/foo/bar/</code>로 변환되고 <code>STATUS</code>라는
|
|
환경변수 값을 "java"로 설정한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteRule ^(.*)/<strong>S=([^/]+)</strong>/(.*) $1/$3 [E=<strong>STATUS:$2</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>가상 사용자 호스트</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>가상호스트를 사용하지 않고 같은 컴퓨터로 DNS A
|
|
레코드를 설정하여
|
|
<code>www.<strong>username</strong>.host.domain.com</code>을
|
|
사용자의 홈페이지로 제공하고 싶다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>HTTP/1.0 요청의 경우 방법이 없지만, Host: HTTP
|
|
헤더를 포함한 HTTP/1.1 요청은 다음 규칙을 사용하여
|
|
내부적으로 <code>http://www.username.host.com/anypath</code>를
|
|
<code>/home/username/anypath</code>로 재작성할 수
|
|
있다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteCond %{<strong>HTTP_HOST</strong>} ^www\.<strong>[^.]+</strong>\.host\.com$
|
|
RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
|
|
RewriteRule ^www\.<strong>([^.]+)</strong>\.host\.com(.*) /home/<strong>$1</strong>$2
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>홈디렉토리를 외부 서버로 리다이렉션</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>지역 도메인 <code>ourdomain.com</code> 밖에서 요청이
|
|
들어오면 홈디렉토리 URL을 다른 웹서버
|
|
<code>www.somewhere.com</code>으로 리다리렉션하길
|
|
바란다. 종종 가상호스트 사용장소에서 사용한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>재작성 조건을 사용하면 된다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteCond %{REMOTE_HOST} <strong>!^.+\.ourdomain\.com$</strong>
|
|
RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>실패한 URL을 다른 웹서버로 리다이렉션</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>URL 재작성에 대해서 웹서버 A에 해당 파일이 없는
|
|
경우 웹서버 B로 요청을 리다이렉션하는 방법을 자주
|
|
물어본다. 보통 Perl로 작성한 <code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code> CGI 스크립트를
|
|
사용하지만, <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용하는
|
|
방법도 있다. 그러나 성능은 <code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code> CGI 스크립트보다
|
|
떨어짐을 명심하라!</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>첫번째 방법은 빠르지만 유연성이 떨어지고 완전하지
|
|
않다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteCond /your/docroot/%{REQUEST_FILENAME} <strong>!-f</strong>
|
|
RewriteRule ^(.+) http://<strong>webserverB</strong>.dom/$1
|
|
</pre></div>
|
|
|
|
<p>이 방법의 단점은 <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code> 안에 있는 페이지만
|
|
가능하다는 점이다. (예를 들어 홈디렉토리 등을 위해)
|
|
조건을 추가할 수 있지만, 더 좋은 방법이 있다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteCond %{REQUEST_URI} <strong>!-U</strong>
|
|
RewriteRule ^(.+) http://<strong>webserverB</strong>.dom/$1
|
|
</pre></div>
|
|
|
|
<p><code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>의 URL 전방참조(look-ahead)를
|
|
사용한다. 그래서 모든 URL에 동작하고 안전하다. 그러나
|
|
모든 요청마다 내부 하위요청을 한번 더 하기때문에 웹서버
|
|
성능에 악영향을 준다. 그래서 강력한 CPU에서 웹서버를
|
|
실행한다면 사용하라. 컴퓨터가 느리다면 첫번째 방법이나
|
|
더 나은 <code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code>
|
|
CGI 스크립트를 사용하라.</p>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>확장 리다이렉션</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>가끔 리다이렉션하는 URL을 더 조절할 필요가 있다.
|
|
아파치 내부 URL escape 함수는 "<code>url#anchor</code>"
|
|
같은 URL의 anchor도 escape한다. 아파치의
|
|
<code>uri_escape()</code> 함수는 우물정자(#)도 같이
|
|
escape하므로 사용할 수 없다. 그러면 어떻게 이런 URL로
|
|
리다이렉션할 수 있나?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>직접 리다이렉션하는 NPH-CGI 스크립트를 사용한 해결책이
|
|
필요하다. escape를 하지 않기때문이다 (NPH=non-parseable
|
|
headers). 먼저 다음 서버설정을 하여 (재작성 규칙의
|
|
끝부분에 사용해야 한다) 새로운 URL scheme
|
|
<code>xredirect:</code>를 도입한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \
|
|
[T=application/x-httpd-cgi,L]
|
|
</pre></div>
|
|
|
|
<p>그러면 <code>xredirect:</code>로 시작하는 모든 URL은
|
|
<code>nph-xredirect.cgi</code> 프로그램을 통하게 된다.
|
|
프로그램은 다음과 같다:</p>
|
|
|
|
<div class="example"><pre>
|
|
#!/path/to/perl
|
|
##
|
|
## nph-xredirect.cgi -- NPH/CGI script for extended redirects
|
|
## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
|
|
##
|
|
|
|
$| = 1;
|
|
$url = $ENV{'PATH_INFO'};
|
|
|
|
print "HTTP/1.0 302 Moved Temporarily\n";
|
|
print "Server: $ENV{'SERVER_SOFTWARE'}\n";
|
|
print "Location: $url\n";
|
|
print "Content-type: text/html\n";
|
|
print "\n";
|
|
print "<html>\n";
|
|
print "<head>\n";
|
|
print "<title>302 Moved Temporarily (EXTENDED)</title>\n";
|
|
print "</head>\n";
|
|
print "<body>\n";
|
|
print "<h1>Moved Temporarily (EXTENDED)</h1>\n";
|
|
print "The document has moved <a HREF=\"$url\">here</a>.<p>\n";
|
|
print "</body>\n";
|
|
print "</html>\n";
|
|
|
|
##EOF##
|
|
</pre></div>
|
|
|
|
<p>그러면 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>가 직접 받지못하는
|
|
모든 URL scheme으로 리다이렉션할 수 있다. 예를 들어,
|
|
다음과 같이 <code>news:newsgroup</code>으로 리다이렉션할
|
|
수 있다</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^anyurl xredirect:news:newsgroup
|
|
</pre></div>
|
|
|
|
<div class="note">주의: 위의 특별한 "통과" 규칙을 사용하여
|
|
<code>xredirect:</code>를 마지막에 확장해야 하기때문에
|
|
규칙에 <code>[R]</code>이나 <code>[R,L]</code>을 사용하면
|
|
안된다.</div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>저장소 접근 중계(multiplexer)</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p><a href="http://www.perl.com/CPAN">http://www.perl.com/CPAN</a>에
|
|
있는 대단한 CPAN (Comprehensive Perl Archive Network)을
|
|
아는가? 이 주소는 세계에 흩어진 여러 CPAN 미러 FTP
|
|
서버중 클라이언트에 가까이 있는 서버로 리다이렉션한다.
|
|
이를 FTP 접근 중계 서비스라고 한다. CPAN은 CGI 스크립트를
|
|
사용하지만, <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용하여
|
|
비슷하게 만들 수 있을까?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>먼저 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code> 3.0.0 버전부터
|
|
리다이렉션에 "<code>ftp:</code>" scheme을 사용할 수
|
|
있다. 다음으로 클라이언트의 최상위 도메인을 <code class="directive"><a href="../mod/mod_rewrite.html#rewritemap">RewriteMap</a></code>과 같이
|
|
사용하여 위치를 추정할 수 있다. 복잡히 엮인 규칙에서
|
|
최상위 도메인을 중계맵의 키로 사용한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteMap multiplex txt:/path/to/map.cxan
|
|
RewriteRule ^/CxAN/(.*) %{REMOTE_HOST}::$1 [C]
|
|
RewriteRule ^.+\.<strong>([a-zA-Z]+)</strong>::(.*)$ ${multiplex:<strong>$1</strong>|ftp.default.dom}$2 [R,L]
|
|
</pre></div>
|
|
|
|
<div class="example"><pre>
|
|
##
|
|
## map.cxan -- Multiplexing Map for CxAN
|
|
##
|
|
|
|
de ftp://ftp.cxan.de/CxAN/
|
|
uk ftp://ftp.cxan.uk/CxAN/
|
|
com ftp://ftp.cxan.com/CxAN/
|
|
:
|
|
##EOF##
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>시간에 따른 재작성</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>시간에 따라 다른 내용을 서비스하는 경우 많은 웹관리자는
|
|
잠시 특별한 페이지로 리다이렉션하기위해 CGI 스크립트를
|
|
사용한다. <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>로는 어떻게
|
|
할 수 있는가?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>재작성 조건에서 사용할 수 있는 여러 <code>TIME_xxx</code>
|
|
변수가 있다. 변수와 특별한 사전순서 비교
|
|
<code><STRING</code>, <code>>STRING</code>,
|
|
<code>=STRING</code>을 사용하여 시간에 따라 리다이렉션할
|
|
수 있다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
|
|
RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
|
|
RewriteRule ^foo\.html$ foo.day.html
|
|
RewriteRule ^foo\.html$ foo.night.html
|
|
</pre></div>
|
|
|
|
<p>URL <code>foo.html</code>을 요청하면
|
|
<code>07:00-19:00</code> 동안 <code>foo.day.html</code>
|
|
내용을 서비스하고, 나머지 시간 동안
|
|
<code>foo.night.html</code> 내용을 서비스한다. 홈페이지에서
|
|
사용하기 좋은 기능이다...</p>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>YYYY를 XXXX로 이전한 경우 역호환</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>여러 <code>.html</code> 파일을 <code>.phtml</code>로
|
|
변환하는 등 <code>document.YYYY</code>를
|
|
<code>document.XXXX</code>로 이전한후 역호환(backward
|
|
compatibility) URL을 (가상적으로 존재하게) 만들 수
|
|
있나?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>이름을 기본이름으로 재작성한후 새로운 확장자를
|
|
가진 파일이 있는지 검사한다. 있다면 그 파일명을 사용하고,
|
|
없으면 URL을 원래 상태로 재작성한다.</p>
|
|
|
|
|
|
<div class="example"><pre>
|
|
# 문서.html 이 없고
|
|
# 문서.phtml 만 있는 경우
|
|
# 문서.html 을 문서.phtml 로
|
|
# 재작성하는 역호환 규칙
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
# 기본이름을 찾고, 찾았다는 사실을 기억한다
|
|
RewriteRule ^(.*)\.html$ $1 [C,E=WasHTML:yes]
|
|
# 파일이 있다면 문서.phtml 로 재작성한다
|
|
RewriteCond %{REQUEST_FILENAME}.phtml -f
|
|
RewriteRule ^(.*)$ $1.phtml [S=1]
|
|
# 아니면 앞에서 찾은 기본이름을 되돌린다
|
|
RewriteCond %{ENV:WasHTML} ^yes$
|
|
RewriteRule ^(.*)$ $1.html
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
|
<div class="section">
|
|
<h2><a name="content" id="content">컨텐츠 다루기</a></h2>
|
|
|
|
|
|
|
|
<h3>새로 이전 (감추기)</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>최근 <code>foo.html</code>을 <code>bar.html</code>로
|
|
변경하고 역호환성을 위해 이전 URL을 계속 제공하고
|
|
싶다고 가정하자. 사용자는 이전 URL이 변경되었다는
|
|
사실을 눈치채지 못한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>다음 규칙으로 이전 URL을 내부적으로 새로운 URL로
|
|
재작성한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteRule ^<strong>foo</strong>\.html$ <strong>bar</strong>.html
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>새로 이전 (알리기)</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>다시 <code>foo.html</code>을 <code>bar.html</code>로
|
|
변경하고 역호환성을 위해 이전 URL을 계속 제공하고
|
|
싶다고 가정하자. 그러나 이제는 이전 URL을 사용하면
|
|
사용자에게 새로운 URL을 힌트로 알려준다. 즉, 브라우저
|
|
주소창이 변한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>새로운 URL로 HTTP 리다이렉션하다. 그러면 브라우저가
|
|
새로운 URL를 보이고 변경사실을 사용자가 알게된다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteRule ^<strong>foo</strong>\.html$ <strong>bar</strong>.html [<strong>R</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>브라우저에 따른 내용</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>최소한 중요한 최상위 페이지는 브라우저에 최적화된
|
|
내용으로 서비스해야할 경우가 있다. 즉, 최신 Netscape
|
|
브라우저에게는 최상의 버전을, Lynx 브라우저에게는
|
|
최저 버전을, 나머지 브라우저에는 평균적인 버전을
|
|
제공한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>브라우저가 내용협상을 위해 자신의 종류에 대한 정보를
|
|
제공하지 않기때문에 내용협상을 사용할 수 없다. 대신
|
|
HTTP "User-Agent" 헤더를 사용한다. 다음 규칙은 HTTP
|
|
"User-Agent" 헤더가 "Mozilla/3"으로 시작하면
|
|
<code>foo.html</code> 페이지를 <code>foo.NS.html</code>로
|
|
재작성하고 재작성을 중단한다. 브라우저가 "Lynx"나
|
|
"Mozilla" 버전 1 혹은 2라면 URL은
|
|
<code>foo.20.html</code>이 된다. 나머지 브라우저는
|
|
<code>foo.32.html</code> 페이지를 받는다. 아래 규칙이
|
|
이 작업을 한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{HTTP_USER_AGENT} ^<strong>Mozilla/3</strong>.*
|
|
RewriteRule ^foo\.html$ foo.<strong>NS</strong>.html [<strong>L</strong>]
|
|
|
|
RewriteCond %{HTTP_USER_AGENT} ^<strong>Lynx/</strong>.* [OR]
|
|
RewriteCond %{HTTP_USER_AGENT} ^<strong>Mozilla/[12]</strong>.*
|
|
RewriteRule ^foo\.html$ foo.<strong>20</strong>.html [<strong>L</strong>]
|
|
|
|
RewriteRule ^foo\.html$ foo.<strong>32</strong>.html [<strong>L</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>동적 미러</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>외부 호스트에 우리 사이트로 가져오고 싶은 좋은
|
|
웹페이지가 있다고 가정하자. FTP 서버의 경우 직접 외부
|
|
자료의 최신복사본을 유지하는 <code>mirror</code> 프로그램을
|
|
사용할 수 있고, 웹서버라면 HTTP로 비슷한 작업을 하는
|
|
<code>webcopy</code> 프로그램을 사용할 수 있다. 그러나
|
|
두 방법 모두 단점이 있다: 복사본은 가끔씩 프로그램을
|
|
실행해줄 때만 최신판으로 유지된다. 직접 구성해야하는
|
|
정적인 미러가 아니라면 좋겠다. 대신 (외부 호스트에서
|
|
자료가 갱신되면) 필요할때 자동으로 자료를 갱신하는
|
|
동적 미러가 필요하다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>이를 위해 <dfn>Proxy Throughput</dfn> 기능을 (플래그
|
|
<code>[P]</code>) 사용하여 외부 웹페이지 혹은 외부
|
|
웹공간 전체를 우리 이름공간으로 대응한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteRule ^<strong>hotsheet/</strong>(.*)$ <strong>http://www.tstimpreso.com/hotsheet/</strong>$1 [<strong>P</strong>]
|
|
</pre></div>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteRule ^<strong>usa-news\.html</strong>$ <strong>http://www.quux-corp.com/news/index.html</strong> [<strong>P</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>동적 역미러</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>...</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteCond /mirror/of/remotesite/$1 -U
|
|
RewriteRule ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>없는 자료를 인트라넷에서 가져오기</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>실제 자료를 방화벽이 보호하는 (내부) 인트라넷 웹서버에
|
|
(<code>www2.quux-corp.dom</code>) 저장하면서, 기업의
|
|
(외부) 인터넷 웹서버를 (<code>www.quux-corp.dom</code>)
|
|
실행하는 것처럼 보이게 한다. 외부 웹서버는 요청한
|
|
자료를 내부 웹서버에서 가져온다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>먼저 방화벽이 내부 웹서버를 보호하고 외부 웹서버만이
|
|
내부 웹서버에서 자료를 얻을 수 있게 한다. 다음과 같이
|
|
패킷필터링 방화벽을 설정한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
<strong>ALLOW</strong> Host www.quux-corp.dom Port >1024 --> Host www2.quux-corp.dom Port <strong>80</strong>
|
|
<strong>DENY</strong> Host * Port * --> Host www2.quux-corp.dom Port <strong>80</strong>
|
|
</pre></div>
|
|
|
|
<p>실제 설정문법에 알맞게 고쳐라. 없는 자료를 내부적으로
|
|
proxy throughput 기능을 통해 요청하는
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code> 규칙을 작성한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^/~([^/]+)/?(.*) /home/$1/.www/$2
|
|
RewriteCond %{REQUEST_FILENAME} <strong>!-f</strong>
|
|
RewriteCond %{REQUEST_FILENAME} <strong>!-d</strong>
|
|
RewriteRule ^/home/([^/]+)/.www/?(.*) http://<strong>www2</strong>.quux-corp.dom/~$1/pub/$2 [<strong>P</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>로드밸런싱 (부하 분산하기)</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p><code>www.foo.com</code>의 통신량을
|
|
<code>www[0-5].foo.com</code> (총 서버 6대)으로 분산하고
|
|
싶다. 어떻게 하는가?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>매우 다양한 방법으로 이 문제를 해결할 수 있다.
|
|
먼저 DNS를 사용한 잘 알려진 방법을 설명하고,
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>를 사용하는 경우를 살펴보자:</p>
|
|
|
|
<ol>
|
|
<li>
|
|
<strong>DNS Round-Robin</strong>
|
|
|
|
<p>가장 간단한 로드밸런싱 방법은 <code>BIND</code>의
|
|
DNS round-robin 방식을 사용하는 것이다. 다음과
|
|
같이 DNS A(address) 레코드에
|
|
<code>www[0-9].foo.com</code>을 설정한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
www0 IN A 1.2.3.1
|
|
www1 IN A 1.2.3.2
|
|
www2 IN A 1.2.3.3
|
|
www3 IN A 1.2.3.4
|
|
www4 IN A 1.2.3.5
|
|
www5 IN A 1.2.3.6
|
|
</pre></div>
|
|
|
|
<p>그리고 다음 항목을 추가한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
www IN CNAME www0.foo.com.
|
|
IN CNAME www1.foo.com.
|
|
IN CNAME www2.foo.com.
|
|
IN CNAME www3.foo.com.
|
|
IN CNAME www4.foo.com.
|
|
IN CNAME www5.foo.com.
|
|
IN CNAME www6.foo.com.
|
|
</pre></div>
|
|
|
|
<p>잘못된 것처럼 보이지만, 실제로 <code>BIND</code>의
|
|
의도된 기능이다. 이제 <code>www.foo.com</code>을
|
|
찾으면, <code>BIND</code>는 매번 순서를 조금씩
|
|
바꿔가며 <code>www0-www6</code>을 반환한다. 그래서
|
|
클라이언트들을 여러 서버로 분산한다. 그러나 DNS
|
|
검색 결과가 네트웍의 다른 네임서버에 캐쉬되여
|
|
<code>www.foo.com</code>을 찾은 결과가 특정
|
|
<code>wwwN.foo.com</code>이면 클라이언트의 다음
|
|
요청들도 같은 <code>wwwN.foo.com</code>으로
|
|
보내지기때문에 완벽한 로드밸런싱 기법이 아님을
|
|
주의하라. 그러나 크게 보면 요청이 여러 웹서버에
|
|
분산되므로 효과가 좋다.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<strong>DNS 로드밸런싱</strong>
|
|
|
|
<p><a href="http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html">http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html</a>에
|
|
있는 <code>lbnamed</code> 프로그램을 사용하여
|
|
정교한 DNS기반 로드밸런싱을 할 수 있다. DNS가
|
|
실제 로드밸런싱을 하도록 만드는 여러 도구와 Perl
|
|
5 프로그램이다.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<strong>Proxy Throughput Round-Robin</strong>
|
|
|
|
<p>이 방법은 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>와 proxy
|
|
throughput 기능을 사용한다. 먼저 DNS에 다음 항목을
|
|
사용하여 <code>www0.foo.com</code>이 실제
|
|
<code>www.foo.com</code>을 전담하게 한다</p>
|
|
|
|
<div class="example"><pre>
|
|
www IN CNAME www0.foo.com.
|
|
</pre></div>
|
|
|
|
<p>그리고 <code>www0.foo.com</code>을 프록시전용
|
|
서버로 변경한다. 즉, URL을 받으면 서버는 내부
|
|
프록시를 통해 다른 5대 서버중 (<code>www1-www5</code>)
|
|
한대로 보내기만 한다. 이를 위해 먼저 모든 URL을
|
|
로드밸런싱 스크립트 <code>lb.pl</code>로 보내는
|
|
규칙을 만든다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteMap lb prg:/path/to/lb.pl
|
|
RewriteRule ^/(.+)$ ${lb:$1} [P,L]
|
|
</pre></div>
|
|
|
|
<p><code>lb.pl</code>을 작성한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
#!/path/to/perl
|
|
##
|
|
## lb.pl -- 로드밸런싱 스크립트
|
|
##
|
|
|
|
$| = 1;
|
|
|
|
$name = "www"; # 기본 호스트명
|
|
$first = 1; # 첫번째 서버 (자신이 0이기 때문에, 0을 사용하지 않는다)
|
|
$last = 5; # round-robin에서 마지막 서버
|
|
$domain = "foo.dom"; # 도메인명
|
|
|
|
$cnt = 0;
|
|
while (<STDIN>) {
|
|
$cnt = (($cnt+1) % ($last+1-$first));
|
|
$server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
|
|
print "http://$server/$_";
|
|
}
|
|
|
|
##EOF##
|
|
</pre></div>
|
|
|
|
<div class="note">마지막 주의: 왜 이 방법이 유용한가?
|
|
<code>www0.foo.com</code>에 부담이 가지않는가?
|
|
물론, 부담이 된다. 그러나 단순한 proxy throughput
|
|
요청만 하기때문에 괜찮다! 모든 SSI, CGI, ePerl
|
|
등은 전적으로 다른 서버가 처리한다. 이것이 핵심이다.</div>
|
|
</li>
|
|
|
|
<li>
|
|
<strong>하드웨어/TCP Round-Robin</strong>
|
|
|
|
<p>하드웨어를 사용한 해결책도 있다. Cisco는 TCP/IP
|
|
수준에서 로드밸런싱을 하는 LocalDirector라는 괴물을
|
|
판다. 실제로는 웹서버군 앞단에 위치하는 일종의
|
|
회로수준 게이트웨이다. 자금이 충분하고 고성능
|
|
해결책이 필요하다면 이것을 사용하라.</p>
|
|
</li>
|
|
</ol>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>새로운 MIME-type, 새로운 서비스</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>네트웍에는 멋진 CGI 프로그램들이 많다. 그러나 사용하기
|
|
번거러워서 많은 웹관리자가 사용하지 않는다. 아파치의
|
|
MIME-type에 따른 Action 핸들러 기능도 CGI 프로그램이
|
|
특별한 URL을 (정확히 <code>PATH_INFO</code>와
|
|
<code>QUERY_STRINGS</code>) 프로그램의 입력으로 사용하지
|
|
않을 때만 적절하다. 먼저, 확장자가 (secure CGI를 줄여)
|
|
<code>.scgi</code>인 파일을 유명한 <code>cgiwrap</code>
|
|
프로그램으로 처리하기위해 새로운 type을 설정한다.
|
|
문제는 (위에서 본) 일관된 URL 구조를 사용하는 경우
|
|
사용자 홈디렉토리가 <code>/u/user/foo/bar.scgi</code>같은
|
|
URL인 점이다. <code>cgiwrap</code>는
|
|
<code>/~user/foo/bar.scgi/</code> 형식의 URL을
|
|
원하기때문이다. 다음 규칙이 문제를 해결한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^/[uge]/<strong>([^/]+)</strong>/\.www/(.+)\.scgi(.*) ...
|
|
... /internal/cgi/user/cgiwrap/~<strong>$1</strong>/$2.scgi$3 [NS,<strong>T=application/x-http-cgi</strong>]
|
|
</pre></div>
|
|
|
|
<p>이제 다른 멋진 프로그램, (URL 하위트리에 대한
|
|
<code>access.log</code>를 출력하는) <code>wwwlog</code>와
|
|
(URL 하위트리에 Glimpse를 실행하는) <code>wwwidx</code>가
|
|
있다고 가정하자. 우리는 프로그램에게 작업할 대상인
|
|
URL 영역을 알려줘야 한다. 그러나 요청할때마다 항상
|
|
적어줘야 하기때문에 깔끔하지 않다. 즉, 보통
|
|
<code>/u/user/foo/</code>에 대해 <code>swwidx</code>
|
|
프로그램을 실행한다면 다음과 같은 링크를 사용한다</p>
|
|
|
|
<div class="example"><pre>
|
|
/internal/cgi/user/swwidx?i=/u/user/foo/
|
|
</pre></div>
|
|
|
|
<p>깔끔하지 않다. 링크에 영역의 위치<strong>와</strong>
|
|
CGI 위치를 <strong>모두</strong> 적어야 하기때문이다.
|
|
영역을 재구성한다면 여러 하이퍼링크를 수정하는데 많은
|
|
시간이 걸릴 것이다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>해결책은 자동으로 적절한 CGI를 실행하는 새로운
|
|
특별한 URL 형식을 만드는 것이다. 다음과 같이 설정한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^/([uge])/([^/]+)(/?.*)/\* /internal/cgi/user/wwwidx?i=/$1/$2$3/
|
|
RewriteRule ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3
|
|
</pre></div>
|
|
|
|
<p>이제 <code>/u/user/foo/</code>을 검색하는 링크는
|
|
다음과 같다</p>
|
|
|
|
<div class="example"><pre>
|
|
HREF="*"
|
|
/u/user/foo/* (???)
|
|
</pre></div>
|
|
|
|
<p>내부적으로 다음과 같이 자동변환된다</p>
|
|
|
|
<div class="example"><pre>
|
|
/internal/cgi/user/wwwidx?i=/u/user/foo/
|
|
</pre></div>
|
|
|
|
<p>같은 방법으로 링크 뒤에 <code>:log</code>를 사용하여
|
|
접근 로그 CGI 프로그램을 실행할 수 있다.</p>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>정적에서 동적으로</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>어떻게 브라우저와 사용자가 모르게 자연스럽게 정적
|
|
페이지 <code>foo.html</code>을 동적인 <code>foo.cgi</code>로
|
|
변경할 수 있나.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>URL을 CGI 스크립트로 재작성하고, MIME-type을 수정하여
|
|
CGI 스크립트로 실행하게 한다. 그래서
|
|
<code>/~quux/foo.html</code>를 요청하면 내부적으로
|
|
<code>/~quux/foo.cgi</code>를 실행하게 된다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteBase /~quux/
|
|
RewriteRule ^foo\.<strong>html</strong>$ foo.<strong>cgi</strong> [T=<strong>application/x-httpd-cgi</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>즉석 컨텐츠 재생성</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>이 방법은 실로 비기이다: 동적으로 페이지를 생성하지만,
|
|
정적으로 페이지를 서비스한다. 즉, 페이지는 순수하게
|
|
(파일시스템에서 읽은 내용을 그대로) 정적 페이지로
|
|
전달되지만, 없을 경우 웹서버가 동적으로 생성한다.
|
|
그러면 누가 (혹은 cron 작업이) 정적 컨텐츠를 지우지않는
|
|
한 CGI가 생성한 페이지를 정적으로 서비스한다. 컨텐츠를
|
|
지우면 내용을 갱신한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
다음 규칙을 사용한다:
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{REQUEST_FILENAME} <strong>!-s</strong>
|
|
RewriteRule ^page\.<strong>html</strong>$ page.<strong>cgi</strong> [T=application/x-httpd-cgi,L]
|
|
</pre></div>
|
|
|
|
<p>여기서 <code>page.html</code>를 요청할때
|
|
<code>page.html</code>이 없거나 파일크기가 0인 경우
|
|
내부적으로 <code>page.cgi</code>를 실행한다. 여기서
|
|
비결은 <code>page.cgi</code>가 일반적인 CGI 스크립트와
|
|
같이 <code>STDOUT</code>에 출력하고, 추가로 출력을
|
|
<code>page.html</code> 파일에 적는다. 한번 실행한후
|
|
서버는 <code>page.html</code>의 정보를 보낸다. 웹관리자가
|
|
강재로 내용을 갱신하고 싶다면, (보통 cron 작업이)
|
|
<code>page.html</code>을 지우기만 하면 된다.</p>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>자동으로 새로 고침하는 문서</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>복잡한 웹페이지를 만들때 편집자가 내용을 수정할
|
|
때마다 자동으로 페이지를 새로 고침하는 웹브라우저가
|
|
있으면 얼마나 좋을까? 불가능한가?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>가능하다! MIME multipart 기능과 웹서버 NPH 기능,
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>의 URL 조작 능력을 결합하면
|
|
된다. 먼저, 새로운 URL 기능을 만든다: URL에
|
|
<code>:refresh</code>를 추가하기만 하면 파일시스템에서
|
|
수정될 때마다 새로 고침한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteRule ^(/[uge]/[^/]+/?.*):refresh /internal/cgi/apache/nph-refresh?f=$1
|
|
</pre></div>
|
|
|
|
<p>이제 다음 URL에 접근하면</p>
|
|
|
|
<div class="example"><pre>
|
|
/u/foo/bar/page.html:refresh
|
|
</pre></div>
|
|
|
|
<p>다음 URL을 내부적으로 부른다</p>
|
|
|
|
<div class="example"><pre>
|
|
/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
|
|
</pre></div>
|
|
|
|
<p>이제 NPH-CGI 스크립트만 남았다. 보통 "독자에게
|
|
연습으로 남겨둠"이라고 말하지만 ;-) 나는 이것도 제공한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
#!/sw/bin/perl
|
|
##
|
|
## nph-refresh -- NPH/CGI script for auto refreshing pages
|
|
## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
|
|
##
|
|
$| = 1;
|
|
|
|
# split the QUERY_STRING variable
|
|
@pairs = split(/&/, $ENV{'QUERY_STRING'});
|
|
foreach $pair (@pairs) {
|
|
($name, $value) = split(/=/, $pair);
|
|
$name =~ tr/A-Z/a-z/;
|
|
$name = 'QS_' . $name;
|
|
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
|
eval "\$$name = \"$value\"";
|
|
}
|
|
$QS_s = 1 if ($QS_s eq '');
|
|
$QS_n = 3600 if ($QS_n eq '');
|
|
if ($QS_f eq '') {
|
|
print "HTTP/1.0 200 OK\n";
|
|
print "Content-type: text/html\n\n";
|
|
print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
|
|
exit(0);
|
|
}
|
|
if (! -f $QS_f) {
|
|
print "HTTP/1.0 200 OK\n";
|
|
print "Content-type: text/html\n\n";
|
|
print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
|
|
exit(0);
|
|
}
|
|
|
|
sub print_http_headers_multipart_begin {
|
|
print "HTTP/1.0 200 OK\n";
|
|
$bound = "ThisRandomString12345";
|
|
print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
|
|
&print_http_headers_multipart_next;
|
|
}
|
|
|
|
sub print_http_headers_multipart_next {
|
|
print "\n--$bound\n";
|
|
}
|
|
|
|
sub print_http_headers_multipart_end {
|
|
print "\n--$bound--\n";
|
|
}
|
|
|
|
sub displayhtml {
|
|
local($buffer) = @_;
|
|
$len = length($buffer);
|
|
print "Content-type: text/html\n";
|
|
print "Content-length: $len\n\n";
|
|
print $buffer;
|
|
}
|
|
|
|
sub readfile {
|
|
local($file) = @_;
|
|
local(*FP, $size, $buffer, $bytes);
|
|
($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
|
|
$size = sprintf("%d", $size);
|
|
open(FP, "&lt;$file");
|
|
$bytes = sysread(FP, $buffer, $size);
|
|
close(FP);
|
|
return $buffer;
|
|
}
|
|
|
|
$buffer = &readfile($QS_f);
|
|
&print_http_headers_multipart_begin;
|
|
&displayhtml($buffer);
|
|
|
|
sub mystat {
|
|
local($file) = $_[0];
|
|
local($time);
|
|
|
|
($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
|
|
return $mtime;
|
|
}
|
|
|
|
$mtimeL = &mystat($QS_f);
|
|
$mtime = $mtime;
|
|
for ($n = 0; $n &lt; $QS_n; $n++) {
|
|
while (1) {
|
|
$mtime = &mystat($QS_f);
|
|
if ($mtime ne $mtimeL) {
|
|
$mtimeL = $mtime;
|
|
sleep(2);
|
|
$buffer = &readfile($QS_f);
|
|
&print_http_headers_multipart_next;
|
|
&displayhtml($buffer);
|
|
sleep(5);
|
|
$mtimeL = &mystat($QS_f);
|
|
last;
|
|
}
|
|
sleep($QS_s);
|
|
}
|
|
}
|
|
|
|
&print_http_headers_multipart_end;
|
|
|
|
exit(0);
|
|
|
|
##EOF##
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>대량의 가상호스트</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>가상호스트가 몇개만 있다면 아파치의 <code class="directive"><a href="../mod/core.html#virtualhost"><VirtualHost></a></code>
|
|
기능이 잘 동작한다. 그러나 가상호스트가 수백개 있는
|
|
ISP라면 이 기능이 최선은 아니다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>이 기능을 제공하려면 <dfn>Proxy Throughput</dfn>
|
|
기능을 (플래그 <code>[P]</code>) 사용하여 외부 웹페이지
|
|
혹은 전체 외부 웹영역을 우리의 이름공간에 대응한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
##
|
|
## vhost.map
|
|
##
|
|
www.vhost1.dom:80 /path/to/docroot/vhost1
|
|
www.vhost2.dom:80 /path/to/docroot/vhost2
|
|
:
|
|
www.vhostN.dom:80 /path/to/docroot/vhostN
|
|
</pre></div>
|
|
|
|
<div class="example"><pre>
|
|
##
|
|
## httpd.conf
|
|
##
|
|
:
|
|
# 리다이렉트할때 정규 호스트명을 사용한다.
|
|
UseCanonicalName on
|
|
|
|
:
|
|
# 가상호스트를 CLF 형식 앞에 추가한다
|
|
CustomLog /path/to/access_log "%{VHOST}e %h %l %u %t \"%r\" %>s %b"
|
|
:
|
|
|
|
# 주서버에서 재작성 엔진을 사용한다
|
|
RewriteEngine on
|
|
|
|
# 두 맵을 정의한다: 하나는 URL을 고치고,
|
|
# 다른 하나는 가상호스트별 DocumentRoot를
|
|
# 정의한다.
|
|
RewriteMap lowercase int:tolower
|
|
RewriteMap vhost txt:/path/to/vhost.map
|
|
|
|
# 이제 크고 복잡한 규칙 한개를 사용하여
|
|
# 가상호스트로 대응한다.
|
|
#
|
|
# 1. 가상호스트들이 같이 사용하는 위치는 대응하지 않는다
|
|
RewriteCond %{REQUEST_URL} !^/commonurl1/.*
|
|
RewriteCond %{REQUEST_URL} !^/commonurl2/.*
|
|
:
|
|
RewriteCond %{REQUEST_URL} !^/commonurlN/.*
|
|
#
|
|
# 2. 우리가 현재 사용하는 방법이 Host 헤더를
|
|
# 가상호스트를 지원하므로
|
|
# Host 헤더가 있는지 확인한다
|
|
RewriteCond %{HTTP_HOST} !^$
|
|
#
|
|
# 3. 호스트명을 소문자로 만든다
|
|
RewriteCond ${lowercase:%{HTTP_HOST}|NONE} ^(.+)$
|
|
#
|
|
# 4. vhost.map에서 호스트명을 찾고
|
|
# 경로일때만 기억한다
|
|
# (위에서 "NONE"은 아니다)
|
|
RewriteCond ${vhost:%1} ^(/.*)$
|
|
#
|
|
# 5. 마지막으로 URL을 문서 위치로 대응하고
|
|
# 로그에 남기기위해 가상호스트를 기억해 둔다
|
|
RewriteRule ^/(.*)$ %1/$1 [E=VHOST:${lowercase:%{HTTP_HOST}}]
|
|
:
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
|
<div class="section">
|
|
<h2><a name="access" id="access">접근 제한</a></h2>
|
|
|
|
|
|
|
|
<h3>로봇 막기</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>어떻게 하면 특정 웹공간의 페이지를 긁어모으는 귀찮은
|
|
로봇을 막을 수 있나? "Robot Exclusion Protocol" 항목을
|
|
저장한 <code>/robots.txt</code> 파일은 보통 이런 로봇을
|
|
막는데 충분하지 않다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>(아마도 디렉토리가 깊어서 로봇이 돌아다니면 서버에
|
|
부담이 큰 경우) 웹공간 <code>/~quux/foo/arc/</code>에
|
|
있는 URL들을 거부하는 규칙을 사용한다. 우리는 특정
|
|
로봇의 접근을 막아야 한다. 즉, 로봇을 실행하는 호스트를
|
|
막는 것으로는 불충분하며, 그 호스트의 사용자도 막아버리게
|
|
된다. User-Agent HTTP 헤더 정보도 비교한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{HTTP_USER_AGENT} ^<strong>NameOfBadRobot</strong>.*
|
|
RewriteCond %{REMOTE_ADDR} ^<strong>123\.45\.67\.[8-9]</strong>$
|
|
RewriteRule ^<strong>/~quux/foo/arc/</strong>.+ - [<strong>F</strong>]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>그림 퍼가기 방지</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p><code>http://www.quux-corp.de/~quux/</code>에 있는
|
|
페이지들이 GIF 그림을 포함한다고 가정하자. 이 그림이
|
|
멋있어서, 다른 사람들이 자신의 페이지에 직접 링크를
|
|
건다. 서버에 불필요한 부담이 되므로 막고 싶다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>그림을 100% 보호할 수는 없지만, 최소한 브라우저가
|
|
HTTP Referer 헤더를 보내는 경우 제한할 수 있다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{HTTP_REFERER} <strong>!^$</strong>
|
|
RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
|
|
RewriteRule <strong>.*\.gif$</strong> - [F]
|
|
</pre></div>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{HTTP_REFERER} !^$
|
|
RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
|
|
RewriteRule <strong>^inlined-in-foo\.gif$</strong> - [F]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>호스트 거부</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>어떻게 외부에서 서버에 접근할 수 없는 호스트 목록을
|
|
설정할 수 있나?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>아파치 >= 1.3b6에서:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteMap hosts-deny txt:/path/to/hosts.deny
|
|
RewriteCond ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
|
|
RewriteCond ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
|
|
RewriteRule ^/.* - [F]
|
|
</pre></div>
|
|
|
|
<p>아파치 <= 1.3b6에서:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteMap hosts-deny txt:/path/to/hosts.deny
|
|
RewriteRule ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
|
|
RewriteRule !^NOT-FOUND/.* - [F]
|
|
RewriteRule ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
|
|
RewriteRule !^NOT-FOUND/.* - [F]
|
|
RewriteRule ^NOT-FOUND/(.*)$ /$1
|
|
</pre></div>
|
|
|
|
<div class="example"><pre>
|
|
##
|
|
## hosts.deny
|
|
##
|
|
## 주의! 이것은 목록처럼 보이지만 목록이 아니라 맵이다.
|
|
## mod_rewrite는 이 정보를 키/값 쌍으로 해석하기때문에,
|
|
## 각 항목의 값 자리에 최소한 "-"가 필요하다.
|
|
##
|
|
|
|
193.102.180.41 -
|
|
bsdti1.sdm.de -
|
|
192.76.162.40 -
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>프록시 거부</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>어떻게 특정 호스트 혹은 특정 호스트의 사용자가
|
|
아파치 프록시를 사용할 수 없도록 하나?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>먼저 아파치 웹서버를 컴파일할때 구성파일에서
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>가 <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code>
|
|
아래에(!) 있어야 한다. 그러면 <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>는
|
|
<code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> <em>이전에</em> 불린다.
|
|
이제 다음과 같이 특정 호스트를 거부하도록 설정한다...</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{REMOTE_HOST} <strong>^badhost\.mydomain\.com$</strong>
|
|
RewriteRule !^http://[^/.]\.mydomain.com.* - [F]
|
|
</pre></div>
|
|
|
|
<p>...그리고 다음은 user@host에 따라 거부한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>^badguy@badhost\.mydomain\.com$</strong>
|
|
RewriteRule !^http://[^/.]\.mydomain.com.* - [F]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>특별한 인증 방식</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상활설명:</dt>
|
|
|
|
<dd>
|
|
<p>가끔 매우 특별한 인증이 필요할 때가 있다. 예를
|
|
들어, 미리 설정해둔 사용자인지 검사한다. 이들에게만
|
|
(<code class="module"><a href="../mod/mod_auth_basic.html">mod_auth_basic</a></code>의 Basic Auth를 사용한
|
|
경우와 달리) 별다른 물음없이 접근을 허용한다.</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>친구만 접근이 가능하도록 재작성 규칙들을 사용한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend1@client1.quux-corp\.com$</strong>
|
|
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend2</strong>@client2.quux-corp\.com$
|
|
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend3</strong>@client3.quux-corp\.com$
|
|
RewriteRule ^/~quux/only-for-friends/ - [F]
|
|
</pre></div>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
<h3>Referer기반 변환기(deflector)</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>"Referer" HTTP 헤더에 따라 원하는대로 참조페이지를
|
|
설정할 수 있는 유연한 URL 변환기를 만들 수 있는가?</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>다음과 같이 복잡한 규칙을...</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteMap deflector txt:/path/to/deflector.map
|
|
|
|
RewriteCond %{HTTP_REFERER} !=""
|
|
RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
|
|
RewriteRule ^.* %{HTTP_REFERER} [R,L]
|
|
|
|
RewriteCond %{HTTP_REFERER} !=""
|
|
RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
|
|
RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]
|
|
</pre></div>
|
|
|
|
<p>... 재작성 맵과 같이 사용한다:</p>
|
|
|
|
<div class="example"><pre>
|
|
##
|
|
## deflector.map
|
|
##
|
|
|
|
http://www.badguys.com/bad/index.html -
|
|
http://www.badguys.com/bad/index2.html -
|
|
http://www.badguys.com/bad/index3.html http://somewhere.com/
|
|
</pre></div>
|
|
|
|
<p>그러면 요청을 자동으로 (맵에서 값으로 "<code>-</code>"를
|
|
사용한 경우) 참조페이지나 (URL이 맵에 있는 경우 두번째
|
|
아규먼트로) 특정 URL로 리다이렉션한다.</p>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
|
|
<div class="section">
|
|
<h2><a name="other" id="other">기타</a></h2>
|
|
|
|
|
|
|
|
<h3>외부 재작성 엔진</h3>
|
|
|
|
|
|
|
|
<dl>
|
|
<dt>상황설명:</dt>
|
|
|
|
<dd>
|
|
<p>FAQ: 어떻게 이런저런 잡다한 문제를 풀 수 있는가?
|
|
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>로는 해결책이 안보인다...</p>
|
|
</dd>
|
|
|
|
<dt>해결책:</dt>
|
|
|
|
<dd>
|
|
<p>외부 <code class="directive"><a href="../mod/mod_rewrite.html#rewritemap">RewriteMap</a></code>을 사용하라.
|
|
즉, 프로그램이 <code class="directive"><a href="../mod/mod_rewrite.html#rewritemap">RewriteMap</a></code> 역할을
|
|
한다. 프로그램은 아파치가 시작할때 시작하여
|
|
<code>STDIN</code>에서 요청한 URL을 받고, (같은 순서로!)
|
|
결과 (보통 재작성된) URL을 <code>STDOUT</code>에 출력한다.</p>
|
|
|
|
<div class="example"><pre>
|
|
RewriteEngine on
|
|
RewriteMap quux-map <strong>prg:</strong>/path/to/map.quux.pl
|
|
RewriteRule ^/~quux/(.*)$ /~quux/<strong>${quux-map:$1}</strong>
|
|
</pre></div>
|
|
|
|
<div class="example"><pre>
|
|
#!/path/to/perl
|
|
|
|
# 아파치 서버가 멈추지 않도록
|
|
# 입출력 버퍼를 사용하지 않는다
|
|
$| = 1;
|
|
|
|
# stdin에서 한줄씩 URL을 읽고
|
|
# stdout에 변환한 URL을 출력한다
|
|
while (<>) {
|
|
s|^foo/|bar/|;
|
|
print $_;
|
|
}
|
|
</pre></div>
|
|
|
|
<p>설명하기위해 모든 <code>/~quux/foo/...</code> URL을
|
|
<code>/~quux/bar/...</code>로 재작성하는 스크립트를
|
|
예로 들었다. 실제로 마음대로 프로그래밍할 수 있다.
|
|
그러나 일반 사용자가 이런 맵을 <strong>사용할</strong>
|
|
수 있다고 하더라고, 오직 시스템 관리자만이 맵을
|
|
<strong>정의해야</strong> 함을 주의하라.</p>
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
</div></div>
|
|
<div class="bottomlang">
|
|
<p><span>가능한 언어: </span><a href="../en/misc/rewriteguide.html" hreflang="en" rel="alternate" title="English"> en </a> |
|
|
<a href="../ko/misc/rewriteguide.html" title="Korean"> ko </a></p>
|
|
</div><div id="footer">
|
|
<p class="apache">Copyright 2006 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
|
|
<p class="menu"><a href="../mod/">모듈</a> | <a href="../mod/directives.html">지시어들</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">용어</a> | <a href="../sitemap.html">사이트맵</a></p></div>
|
|
</body></html> |