대량의 가상호스트를 동적으로 설정하기 - Apache HTTP Server Version 2.2

Apache HTTP Server Version 2.2

Apache > HTTP Server > Documentation > Version 2.2 > 가상호스트

#### Please note

This document refers to a legacy release (2.2) of Apache httpd. The active release (2.4) is documented here. If you have not already upgraded, please follow this link for more information.

You may follow this link to go to the current version of this document.

# 대량의 가상호스트를 동적으로 설정하기

가능한 언어: en | ko | tr

이 문서는 최신판 번역이 아닙니다. 최근에 변경된 내용은 영어 문서를 참고하세요.

이 문서는 아파치 1.3에서 대량의 가상호스트를 효율적으로 서비스하는 방법을 설명한다.

- Comments

## 동기

당신의 `httpd.conf`에 다음과 같이 서로 비슷한 `<VirtualHost>` 섹션들을 많이 있다면 여기서 설명하는 방법이 도움이 될 것이다:

`NameVirtualHost 111.22.33.44
<VirtualHost 111.22.33.44>
ServerName www.customer-1.com
DocumentRoot /www/hosts/www.customer-1.com/docs
ScriptAlias /cgi-bin/ /www/hosts/www.customer-1.com/cgi-bin
</VirtualHost>
<VirtualHost 111.22.33.44>
ServerName www.customer-2.com
DocumentRoot /www/hosts/www.customer-2.com/docs
ScriptAlias /cgi-bin/ /www/hosts/www.customer-2.com/cgi-bin
</VirtualHost>
# 바보 바보 바보
<VirtualHost 111.22.33.44>
ServerName www.customer-N.com
DocumentRoot /www/hosts/www.customer-N.com/docs
ScriptAlias /cgi-bin/ /www/hosts/www.customer-N.com/cgi-bin
</VirtualHost>`

기본 개념은 정적인 `<VirtualHost>` 설정 모두를 동적으로 처리하도록 대체하는 것이다. 그러면 많은 장점이 있다:

1. 설정파일이 작아져서 아파치가 빨리 시작하고 메모리를 적게 사용한다.
2. 가상호스트를 추가하기위해 파일시스템에 적당한 디렉토리를 만들고 DNS에 항목을 추가하기만 하면된다. 즉, 아파치를 재설정하고 재시작할 필요가 없다.

단점은 각 가상호스트별로 다른 로그파일을 사용할 수 없다는 점이다. 그러나 매우 많은 가상호스트를 사용한다면 파일기술자를 다 써버리기때문에 서로 다른 로그파일을 사용할 수 없다. 파이프나 fifo로 로그를 보내고, 받는 편에서 로그를 처리하여 나누는 방법이 (통계 등을 모을 수도 있다) 더 낫다.

## 개요

가상호스트는 IP 주소와 HTTP 요청의 `Host:` 헤더 정보로 정의한다. 기본적으로 대량의 동적 가상호스트 기술은 자동으로 가상호스트 정보를 요청의 파일경로에 포함한다. 이는 대부분 `mod_vhost_alias`를 사용하여 쉽게 해결할 수 있지만, 아파치 1.3.6 이하를 사용한다면 `mod_rewrite`를 사용해야 한다. 이 두 모듈 모두 기본적으로 서버에 포함되지 않는다. 이 방법을 사용하려면 아파치를 구성하고 컴파일할때 포함해야 한다.

동적 가상호스트를 일반적인 가상호스트처럼 보이게하려면 여러가지를 `속여야' 한다. 가장 중요한 것은 아파치가 자기참조 URL 등을 만들때 사용할 서버명이다. 서버명은 `ServerName` 지시어로 설정하며, CGI에는 `SERVER_NAME` 환경변수로 주어진다. 실행중 실제 서버명은 `UseCanonicalName` 설정에 달렸다. `UseCanonicalName Off`이면 요청의 `Host:` 헤더 내용이 서버명이 된다. `UseCanonicalName DNS`이면 가상호스트의 IP 주소를 역DNS 검색하여 서버명을 알아낸다. 전자는 이름기반 동적 가상호스트에서 사용하고, 후자는 IP기반 가상호스트에서 사용한다. `Host:` 헤더가 없거나 DNS 검색이 실패하여 아파치가 서버명을 알아내지 못하면 `ServerName`으로 설정한 값을 대신 사용한다.

다른 `속일' 것은 (`DocumentRoot`로 설정하며, CGI에는 `DOCUMENT_ROOT` 환경변수로 주어지는) 문서루트이다. 일반적인 경우 core 모듈이 이 설정을 사용하여 URI에 해당하는 파일명을 찾지만, 서버를 동적 가상호스팅을 할때는 다른 모듈이 (`mod_vhost_alias`나 `mod_rewrite`) 다른 방법으로 이런 작업을 한다. 두 모듈 모두 `DOCUMENT_ROOT` 환경변수를 사용하지 않으므로 CGI나 SSI 문서가 이 값을 사용한다면 잘못된 결과를 얻을 수 있다.

## 간단한 동적 가상호스트

위 동기 절의 가상호스트 설정을 `mod_vhost_alias`를 사용하여 더 일반적으로 구현했다.

`# Host: 헤더에서 서버명을 알아낸다
UseCanonicalName Off
# 첫번째 필드를 사용하여 이 로그를 가상호스트별로 나눌 수 있다
LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon
# 요청을 처리하기위해 파일명에 서버명을 포함한다
VirtualDocumentRoot /www/hosts/%0/docs
VirtualScriptAlias /www/hosts/%0/cgi-bin`

이 설정에서 `UseCanonicalName Off`를 `UseCanonicalName DNS`로 변경하기만 하면 IP기반 가상호스트가 된다. 가상호스트의 IP 주소를 가지고 파일명에 추가할 서버명을 알 수 있다.

## 가상으로 호스트하는 홈페이지 시스템

ISP 홈페이지 서버를 위해 위의 설정을 수정했다. 조금 더 복잡한 설정을 사용하면 `www.user.isp.com`의 문서를 `/home/user/`에 두는 식으로 서버명의 일부를 가지고 파일명을 만들 수 있다. 이 설정은 `cgi-bin`을 각 가상호스트가 따로 가지지않고 모든 가상호스트가 같이 사용한다.

`# 기본적인 내용은 위와 같다. 그리고
# 파일명에 서버명의 일부를 포함한다
VirtualDocumentRoot /www/hosts/%2/docs
# 하나의 cgi-bin 디렉토리
ScriptAlias /cgi-bin/ /www/std-cgi/
`

`mod_vhost_alias` 문서에는 더 복잡한 `VirtualDocumentRoot` 설정의 예가 있다.

## 한 서버에 여러 가상호스트 시스템 사용하기

더 복잡한 설정의 예로 아파치의 일반적인 `<VirtualHost>` 지시어를 사용하여 여러 가상호스트 설정의 범위를 조절할 수 있다. 예를 들어, 다음과 같은 설정은 홈페이지 고객에 IP 주소 한개, 상업적인 고객에게 다른 IP 주소 한개를 부여한다. 물론 이전처럼 `<VirtualHost>` 설정 섹션에 모두 묶을 수도 있다.

`UseCanonicalName Off
LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
<Directory /www/commercial>
Options FollowSymLinks
AllowOverride All
</Directory>
<Directory /www/homepages>
Options FollowSymLinks
AllowOverride None
</Directory>
<VirtualHost 111.22.33.44>
ServerName www.commercial.isp.com
CustomLog logs/access_log.commercial vcommon
VirtualDocumentRoot /www/commercial/%0/docs
VirtualScriptAlias /www/commercial/%0/cgi-bin
</VirtualHost>
<VirtualHost 111.22.33.45>
ServerName www.homepages.isp.com
CustomLog logs/access_log.homepages vcommon
VirtualDocumentRoot /www/homepages/%0/docs
ScriptAlias /cgi-bin/ /www/std-cgi/
</VirtualHost>`

## 더 효율적인 IP기반 가상호스트

첫번째 예에서 나는 설정을 간단히 IP기반 가상호스트로 바꿀 수 있다고 말했다. 불행히도 그런 설정은 매 요청마다 DNS를 찾아야하므로 매우 비효율적이다. 이름대신 IP 주소로 파일시스템을 구성하고 같은 방식으로 로그를 수정하면 문제를 해결할 수 있다. 아파치는 서버명을 다룰 필요가 없어지고, DNS 검색도 하지 않게 된다.

`# IP 주소를 역DNS 검색하여 서버명을 알아낸다
UseCanonicalName DNS
# 로그를 나눌 수 있도록 IP 주소를 포함한다
LogFormat "%A %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon
# 파일명에 IP 주소를 포함한다
VirtualDocumentRootIP /www/hosts/%0/docs
VirtualScriptAliasIP /www/hosts/%0/cgi-bin
`

## 아파치 이전 버전 사용하기

위 예들은 아파치 버전 1.3.6 이후에 포함된 `mod_vhost_alias`을 사용한다. `mod_vhost_alias`가 없는 아파치 버전을 사용한다면 이미 말했듯이 `mod_rewrite`를 사용하여, 단 Host:-헤더기반 가상호스트만을, 구현할 수 있다.

또 로그에 관하여 주의할 점이 있다. 아파치 1.3.6에서 로그형식 지시어 `%V`가 포함되었고, 버전 1.3.0 - 1.3.3에서 이 기능을 `%v` 옵션이 대신 했다. 그러나 버전 1.3.4에는 이런 기능이 없다. 어떤 아파치 버전에서도 `.htaccess` 파일에서 `UseCanonicalName` 지시어를 사용할 수 있으므로 로그에 이상한 내용이 기록될 수 있다. 그러므로 가장 좋은 방법은 `%{Host}i` 지시어를 사용하여 `Host:` 헤더를 직접 로그에 남기는 것이다. 또, 이 방법은 `%V`는 포함하지않는 `:port`를 뒤에 추가할 수 있다.

## `mod_rewrite`를 사용한 간단한 동적 가상호스트

다음은 첫번째 예와 같은 일을 하는 `httpd.conf` 예이다. 처음 절반은 첫번째 예와 거의 비슷하지만, 이전 버전과의 호환성과 `mod_rewrite`의 적절한 동작을 위해 수정되었다. 나머지 절반은 실제 작업을 하는 `mod_rewrite`를 설정한다.

특별히 주의해야 할 사항이 있다. 기본적으로 `mod_rewrite`는 (`mod_alias` 등) 다른 URI 번역 모듈 이전에 실행된다. 그래서 다른 URI 번역 모듈들과 같이 동작할 것을 고려하여 `mod_rewrite`를 설정해야 한다. 또, 동적 가상호스트에서 `ScriptAlias`과 같은 기능을 위해서는 특별한 작업이 필요하다.

`# Host: 헤더에서 서버명을 얻는다
UseCanonicalName Off
# splittable logs
LogFormat "%{Host}i %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon
<Directory /www/hosts>
# ScriptAlias 식으로 CGI 실행을 강제할 수 없기때문에
# 여기에 ExecCGI를 사용한다
Options FollowSymLinks ExecCGI
</Directory>
# 이제 어려운 부분이다
RewriteEngine On
# Host: 헤더에서 가져온 서버명에는 대소문자가 뒤섞여있을 수 있다
RewriteMap lowercase int:tolower
## 일반 문서를 먼저 처리한다:
# Alias /icons/ 가 동작하도록 - 다른 alias에 대해서도 반복
RewriteCond %{REQUEST_URI} !^/icons/
# CGI가 동작하도록
RewriteCond %{REQUEST_URI} !^/cgi-bin/
# 특별한 작업
RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/docs/$1
## 이제 CGI를 처리한다 - MIME type을 강제해야 한다
RewriteCond %{REQUEST_URI} ^/cgi-bin/
RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/cgi-bin/$1 [T=application/x-httpd-cgi]
# 끝!`

## `mod_rewrite`를 사용한 홈페이지 시스템

다음은 두번째 예와 같은 일을 한다.

`RewriteEngine on
RewriteMap lowercase int:tolower
# CGI가 동작하도록
RewriteCond %{REQUEST_URI} !^/cgi-bin/
# RewriteRule이 동작하도록 호스트명이 올바른지 검사한다
RewriteCond ${lowercase:%{SERVER_NAME}} ^www\.[a-z-]+\.isp\.com$
# 가상호스트명을 URI 앞에 붙인다
# [C]는 이 결과를 가지고 다음 재작성을 수행함을 뜻한다
RewriteRule ^(.+) ${lowercase:%{SERVER_NAME}}$1 [C]
# 이제 실제 파일명을 만든다
RewriteRule ^www\.([a-z-]+)\.isp\.com/(.*) /home/$1/$2
# 전체 CGI 디렉토리를 정의한다
ScriptAlias /cgi-bin/ /www/std-cgi/`

## 별도의 가상호스트 설정파일 사용하기

다음은 `mod_rewrite`의 고급 기능을 사용하여 별도의 설정파일을 가지고 가상호스트의 문서루트를 알아낸다. 더 유연하지만 더 복잡한 설정이 필요하다.

`vhost.map` 파일은 다음과 같다:

`www.customer-1.com /www/customers/1
www.customer-2.com /www/customers/2
# ...
www.customer-N.com /www/customers/N
`

`http.conf`는 다음과 같다:

`RewriteEngine on
RewriteMap lowercase int:tolower
# 대응파일을 정의한다
RewriteMap vhost txt:/www/conf/vhost.map
# 위와 같이 alias들을 처리한다
RewriteCond %{REQUEST_URI} !^/icons/
RewriteCond %{REQUEST_URI} !^/cgi-bin/
RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$
# 파일 내용을 가지고 찾는다
RewriteCond ${vhost:%1} ^(/.*)$
RewriteRule ^/(.*)$ %1/docs/$1
RewriteCond %{REQUEST_URI} ^/cgi-bin/
RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$
RewriteCond ${vhost:%1} ^(/.*)$
RewriteRule ^/(.*)$ %1/cgi-bin/$1`

가능한 언어: en | ko | tr

## Comments

Notice:
This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our mailing lists.