Apache HTTP Server Version 2.4
가상호스트 코드는 아파치 1.3에서 거의 다시
작성되었다. 이 문서는 아파치가 요청을 받으면 어떤 가상호스트가
서비스할지 결정하는 방법을 설명한다. 새로운 NameVirtualHost
지시어를 사용하여
가상호스트 설정이 1.3 버전 이전보다 더 쉽고 안전해졌다.
어떻게 동작하는지 이해하지않고 단지 동작하게만 하고 싶다면, 예제들을 참고하라.
<VirtualHost>
설정을 제외한 설정이
주서버를 만든다. <VirtualHost>
섹션으로 정의한
부분을 가상호스트라고 부른다.
Listen
,
ServerName
,
ServerPath
,
ServerAlias
지시어는
서버 정의 어느곳에서도 사용할 수 있다. 그러나 같은 지시어가
여러번 나오면 (그 서버에서) 마지막 지시어만이 유효하다.
주서버 Listen
의 기본값은 80이다. 주서버의
ServerPath
나 ServerAlias
에는
기본값은 없다. ServerName
의 기본값은 서버의
IP 주소이다.
주서버의 Listen 지시어는 두가지 기능을 한다. 첫째는 아파치가 연결할 기본 네트웍 포트를 지정하는 일이다. 둘째는 리다이렉션할 절대 URI에 사용할 포트 번호를 지정하는 일이다.
주서버와 달리 가상호스트의 포트는 아파치가 연결을 기다리는 포트에 영향을 주지 않는다.
VirtualHost
지시어에 포트를 지정할 수 있다.
포트를 지정하지않으면 주서버의 가장 최근 Listen
값을 사용한다. 특별한 포트 *
는 어떤 포트라도
지칭하는 와일드카드이다. (DNS 검색 결과의 여러 A
레코드를 포함하여) 가상호스트의 주소를 모두 총칭하여 가상호스트의
주소집합(address set)이라고 부른다.
특정 IP 주소에 대한 NameVirtualHost
지시어가 없다면
그 주소를 포함하는 첫번째 가상호스트를 IP기반 가상호스트로 취급한다.
IP 주소에 와일드카드 *
를 사용할 수도 있다.
이름기반 가상호스트를 사용한다면 이름기반 가상호스트에
사용할 IP 주소를 NameVirtualHost
지시어에
사용해야 한다. 즉, 설정파일의 NameVirtualHost
지시어에 이름기반 가상호스트의 호스트별명(CNAME)에 해당하는
IP 주소를 지정해야 한다.
특정 IP:포트 쌍에 대해 오직 한 NameVirtualHost
지시어만을 사용한다면, 여러 NameVirtualHost
지시어와
VirtualHost
지시어를 섞어서 사용할 수 있다.
NameVirtualHost
와 VirtualHost
지시어의 순서는 중요하지 않기때문에 다음 두 예는 같다 (오직
한 주소집합에 대한 VirtualHost
의
순서가 중요하다. 아래 참고):
|
|
(왼쪽 설정이 더 읽기 편하다.)
VirtualHost
지시어를 읽을 다음, 가상호스트
서버는 VirtualHost
지시어에 지정한 포트를 기본
Listen
으로 한다.
VirtualHost
지시어의 이름이 모두 같은
주소집합에 속한다면 ServerAlias
와 같이 취급한다
(그러나 다른 ServerAlias
의 영향을 받지 않는다).
가상호스트에 추가로 사용한 Listen
은 주소집합이
지정한 포트에 영향을 주지 않음을 주의하라.
시작할때 IP 주소 목록을 만들어 해쉬테이블에 추가한다.
NameVirtualHost
지시어에 IP 주소를 사용하면
목록은 그 IP 주소에 대한 모든 이름기반 가상호스트를 포함한다.
그 주소에 대한 가상호스트가 없다면 NameVirtualHost
지시어를 무시하고 로그에 오류를 기록한다. IP기반 가상호스트는
해쉬테이블에 목록을 추가하지 않는다.
빠른 해쉬함수를 사용하기때문에 요청시 IP 주소를 해싱하는 부담은 거의 없다. 또 해쉬테이블은 IP 주소의 마지막 부분의 차이에 최적화되있다.
가상호스트에 여러 기본값이 설정된다. 특히:
ServerAdmin
,
ResourceConfig
,
AccessConfig
,
Timeout
,
KeepAliveTimeout
,
KeepAlive
,
MaxKeepAliveRequests
,
SendBufferSize
지시어가 없다면 주서버에서 해당 값을 가져온다. (즉,
주서버의 설정값을 사용한다.)기본적으로 주서버는 가상호스트를 만드는 "기본" 혹은 "기반"이 된다. 그러나 설정파일에서 주서버를 정의하는 위치는 관계없다. 마지막으로 설정을 합치기 전에 주서버의 모든 설정을 읽어들인다. 그래서 주서버 정의가 가상호스트 정의 뒤에 나와도 가상호스트 정의에 영향을 준다.
주서버에 ServerName
이 없다면 웹서버를 실행하는
컴퓨터의 호스트명을 대신 사용한다. 주서버의
ServerName
을 DNS 겁색하여 얻은 IP 주소들을
주서버 주소집합이라고 부른다.
이름기반 가상호스트의 ServerName
을 정의하지
않으면 가상호스트를 정의하는 VirtualHost
에서
처음으로 나온 주소를 기본값으로 사용한다.
특별한 _default_
와일트카드를 포함하는
가상호스트는 주서버와 같은 ServerName
을 가진다.
서버는 아래와 같은 방법으로 어떤 가상호스트가 요청을 처리할지 결정한다:
클라이언트가 처음 연결하면 연결한 IP 주소를 내부 IP 해쉬테이블에서 찾는다.
IP 주소를 찾을 수 없고 클라이언트가 요청을 보낸 포트에
해당하는 가상호스트가 있다면, _default_
가상호스트가
요청을 서비스한다. _default_
가상호스트가
없다면 주서버가 요청을 서비스한다.
해쉬테이블에 IP 주소가 없지만 포트 번호가
NameVirtualHost *
에 해당할 수 있다. 이 경우
이름기반 가상호스트처럼 처리한다.
찾았다면 (목록에서 IP 주소에 해당하는 항목을 찾으면), IP기반 가상호스트인지 이름기반 가상호스트인지 결정한다.
찾은 항목에 이름 목록이 없다면 IP기반 가상호스트이다. 더 이상 작업이 필요없고, 그 가상호스트가 요청을 처리한다.
이름 목록에 한개 이상의 가상호스트 구조가 포함되면
이름기반 가상호스트이다. 이 목록에서 가상호스트들은 설정파일의
VirtualHost
순서대로 위치한다.
목록에서 첫번째 가상호스트(설정파일에서 해당 IP 주소를
포함하는 첫번째 가상호스트)는 가장 높은 우선순위를 가지며,
서버명을 알 수 없거나 Host:
헤더가 없는 요청을
처리한다.
클라이언트가 Host:
헤더를 주면, 목록에서
첫번째로 ServerName
이나
ServerAlias
가 대응하는 가상호스트가 요청을
서비스한다. Host:
헤더에 포트 번호가 나올 수
있지만, 아파치는 항상 클라이언트가 요청을 보낸 실제 포트를
찾는다.
클라이언트가 Host:
헤더없이 HTTP/1.0 요청을
하면 클라이언트가 어떤 서버에 연결하려는지 알 수 없기때문에
요청의 URI에 해당하는 ServerPath
가 있는지 찾는다.
목록에서 제일 먼저 찾은 경로를 사용하고, 그 가상호스트가
요청을 서비스한다.
대응하는 가상호스트를 찾을 수 없다면, (이미 앞에 말했듯이) 클라이언트가 연결한 IP에 대한 목록에서 일치하는 포트 번호를 포함하는 첫번째 가상호스트가 요청을 서비스한다.
IP는 위에서 설명한데로 특정 TCP/IP 세션당 한번만 찾지만, 이름은 KeepAlive/지속 연결동안 매 요청때마다 찾는다. 즉, 클라이언트는 지속 연결동안 여러 이름기반 가상호스트의 페이지를 요청할 수 있다.
요청의 URI가 절대 URI이고 클라이언트가 보낸 요청의 호스트명과 포트가 주서버나 특정 가상호스트에 해당하면, 그 주서버 혹은 가상호스트는 URI 앞의 스킴/호스트명/포트 부분을 제외한 나머지 상대 URI를 서비스한다. 해당하는 주서버나 가상호스트가 없다면 URI를 그대로 두고 요청을 프록시 요청으로 처리한다.
NameVirtualHost
지시어로 정의한 주소집합의
IP 주소를 통해서만 접근할 수 있다.ServerAlias
와
ServerPath
를 절대로 검사하지 않는다._default_
가상호스트, NameVirtualHost
지시어의 순서는 중요하지 않다. 특정 주소집합에 대한
이름기반 가상호스트들의 순서만이 중요하다. 설정파일에서
앞에 나오는 이름기반 가상호스트는 자신이 속한 주소집합에서
가장 높은 우선순위를 가진다.Host:
헤더에 포함된 포트
번호는 절대로 사용하지 않는다. 아파치는 항상 클라이언트가
요청을 보낸 실제 포트를 사용한다.Host:
헤더가 없다고
가정하면,) ServerPath
지시어가 설정파일에서
뒤에 나오는 다른 ServerPath
지시어의 앞부분을
지칭하는 경우 항상 앞에 나온 지시어를 사용한다._default_
가상호스트는 요청의 IP 주소와
포트 번호에 해당하는 가상호스트가 없을때만 요청을 처리한다.
클라이언트가 요청을 보낸 포트 번호가 _default_
가상호스트의 포트 번호(기본값은 Listen
)와
같을때만 요청을 처리한다. 어떤 포트의 요청이라도 잡기위해
(예를 들어, _default_:*
) 와일드카드
포트를 사용할 수 있다. NameVirtualHost *
가상호스트도 마찬가지다._default_
가상호스트를 포함하여)
가상호스트가 없을때만 요청을 서비스한다. 즉, 주서버는
(그 포트에 해당하는 _default_
가상호스트가
없다면) 지정하지않은 주소/포트 쌍에 대한 요청만을 처리한다.NameVirtualHost
지시어에서) 이름기반 가상호스트 주소(와 포트)에 연결한
경우 Host:
헤더를 알 수 없거나 헤더가 없는
요청을 보내면 요청은 절대로 _default_
가상호스트나 주서버에서 처리하지 않는다.VirtualHost
지시어에 DNS 이름을 사용하지마라.
게다가 열거한 모든 도메인의 DNS를 통제하지 않는다면
보안상 위험도 있다. 이에 대한 정보가 있다.ServerName
를 항상
정의해야 한다. 안그러면 가상호스트마다 DNS를 찾게 된다.DNS 문제 페이지의 팁에 추가로 아래에 팁이 있다:
VirtualHost
정의 앞에
두어라. (그러면 설정을 읽기 편하다. 안그러면 나중에 설정이
합쳐질때 가상호스트들 사이에 섞인 정의가 모든 가상호스트에
영향을 줄 수 있기때문에 혼란스럽다.)NameVirtualHost
과
VirtualHost
정의들을 묶어라.ServerPath
가 다른 ServerPath
의
앞부분을 지칭하는 경우를 피하라. 피할 수 없다면 설정파일에서
앞부분이 더 긴 (더 자세한) 가상호스트를 짧은 (덜 자세한)
가상호스트보다 앞에 두어라. (예를 들어,
"ServerPath /abc"는 "ServerPath /abc/def" 다음에 두어야
한다.