# 虚拟主机示例
本文档试图解释一些在设置虚拟主机时经常问及的问题。这些示例向你展示了如何在一个服务器上通过[基于域名](#calibre_link-75)的或是[基于IP](#calibre_link-653)的虚拟主机来部署多个web站点。另一份关于如何在一个代理服务器后构建基于多个服务器的站点的说明文档也很快就会出来。
## 在一个IP地址上运行多个基于域名的web站点
您的服务器有只一个IP地址,而在DNS中有很多域名(CNAMES)映射到这个机器。您而您想要在这个机器上运行`www.example.com`和`www.example.org`两个站点。
### 注意
在您的Apache服务器配置中创建一个虚拟主机并不会自动在您的DNS中对主机名做相应更新。您_必须_自己在DNS中添加域名来指向您的IP地址。否则别人是无法看到您的web站点的。您可以在您的`hosts`文件中添加这一条目来进行测试,但这种方法仅适用于那些有这些`hosts`文件的机器来使用。
### 服务器配置
```
# 确保Apache在监听80端口
Listen 80
# 为虚拟主机在所有IP地址上监听
NameVirtualHost *:80
<VirtualHost *:80>
DocumentRoot /www/example1
ServerName www.example.com
# 你可以在这里添加其他指令
</VirtualHost>
<VirtualHost *:80>
DocumentRoot /www/example2
ServerName www.example.org
# 你可以在这里添加其他指令
</VirtualHost>
```
因为星号匹配所有IP地址,所以主服务器不接收任何请求。因为`www.example.com`首先出现在配置文件中,所以它拥有最高优先级,可以认为是<cite class="calibre27">默认</cite>或<cite class="calibre27">主</cite>服务器。这意味着如果一个请求不能与某个`ServerName`指令相匹配,它将会由第一个`<VirtualHost>`段所伺服。
### 注意
如果您愿意,您可以用确定的IP地址来取代"`*`"。在这种情况下,`VirtualHost`的参数_必须_与`NameVirtualHost`的参数相符:
```
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
# 其他 ...
```
然而,当您的IP地址无法确定的时候,使用"`*`"是很方便的,比如说,您的ISP给您配置的是动态IP地址,而您又使用了某种动态域名解析系统时。因为"`*`"匹配任何IP地址,所以在这种情况下,不论IP地址如何变化,您都不需要另外进行配置。
上述配置就是您在绝大多数情况下使用基于域名的虚拟主机时将要用到的。事实上,仅在一种情况下这样的配置不会让您满意:您想为不同的IP地址或是端口提供不同的内容。
## 在多于一个IP的情况下使用基于域名的虚拟主机。
### 注意
在这里讨论的任何技术都可以推广到使用任意数量的IP地址。
服务器有两个IP地址。一个(`172.20.30.40`)用于主服务器`server.domain.com` ,另外一个(`172.20.30.50`)用于构建两个或多个虚拟主机。
### 服务器配置
```
Listen 80
# "主"服务器运行于:172.20.30.40
ServerName server.domain.com
DocumentRoot /www/mainserver
# 这是另外一个IP地址
NameVirtualHost 172.20.30.50
<VirtualHost 172.20.30.50>
DocumentRoot /www/example1
ServerName www.example.com
# 你可以在这里添加其他指令 ...
</VirtualHost>
<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
# 你可以在这里添加其他指令 ...
</VirtualHost>
```
任何不是针对`172.20.30.50`的请求都将由主服务器来伺服。而提交给`172.20.30.50`却没有主机名或没有"`Host:`"头的请求,都将由`www.example.com`伺服。
## 在不同的IP的地址(比如一个内部和一个外部地址)上提供相同的内容
服务器有两个IP地址(`192.168.1.1`和`172.20.30.40`)。这个机器位于内部(局域网)网络和外部(广域网)之间。在外部,域名`server.example.com`指向外部地址(`172.20.30.40`),而在内部则指向内部地址(`192.168.1.1`)。
服务器可以为来自内部和外部的请求提供同样的内容,您只需要一个`<VirtualHost>`配置段就可以了。
### 服务器配置
```
NameVirtualHost 192.168.1.1
NameVirtualHost 172.20.30.40
<VirtualHost 192.168.1.1 172.20.30.40>
DocumentRoot /www/server1
ServerName server.example.com
ServerAlias server
</VirtualHost>
```
现在,从不同的网络提交的请求都会由同一个`<VirtualHost>`段来伺服。
### 注意
在内网中,您可以使用`server`这个名字来代替`server.example.com`这个全名。
跟上面一样,在上述的例子里,您可以用"`*`"来代替具体的IP地址,这样就可以对所有的地址都返回相同的内容了。
## 在不同的端口上运行不同的站点
如果您想让同一个IP的不同端口伺服多个域名。您可以借助在`NameVirtualHost`指令中定义端口的方法来达到这个目的。如果您想使用不带"`name:port`"的`<VirtualHost name:port>`或是直接用`Listen`指令,您的配置将无法生效。
### 服务器配置
```
Listen 80
Listen 8080
NameVirtualHost 172.20.30.40:80
NameVirtualHost 172.20.30.40:8080
<VirtualHost 172.20.30.40:80>
ServerName www.example.com
DocumentRoot /www/domain-80
</VirtualHost>
<VirtualHost 172.20.30.40:8080>
ServerName www.example.com
DocumentRoot /www/domain-8080
</VirtualHost>
<VirtualHost 172.20.30.40:80>
ServerName www.example.org
DocumentRoot /www/otherdomain-80
</VirtualHost>
<VirtualHost 172.20.30.40:8080>
ServerName www.example.org
DocumentRoot /www/otherdomain-8080
</VirtualHost>
```
## 建立基于IP的虚拟主机
一个有两个IP地址(`172.20.30.40`和`172.20.30.50`)分别对应域名`www.example.com`和`www.example.org`的配置如下:
### 服务器配置
```
Listen 80
<VirtualHost 172.20.30.40>
DocumentRoot /www/example1
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
</VirtualHost>
```
如果存在主服务器,那么对没有出现在任一个`<VirtualHost>`段中的请求(比如,对`localhost`的请求)都会由主服务器来伺服。
## 混用基于端口和基于IP的虚拟主机
如果您的服务器有两个IP地址(`172.20.30.40`和`172.20.30.50`)分别对应域名`www.example.com`和`www.example.org` 。对每个域名,您都希望在80端口和8080端口发布您的网站。您可以这样配置:
### 服务器配置
```
Listen 172.20.30.40:80
Listen 172.20.30.40:8080
Listen 172.20.30.50:80
Listen 172.20.30.50:8080
<VirtualHost 172.20.30.40:80>
DocumentRoot /www/example1-80
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.40:8080>
DocumentRoot /www/example1-8080
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.50:80>
DocumentRoot /www/example2-80
ServerName www.example.org
</VirtualHost>
<VirtualHost 172.20.30.50:8080>
DocumentRoot /www/example2-8080
ServerName www.example.org
</VirtualHost>
```
## 混用基于域名和基于IP的虚拟主机
您想在一些地址上配置基于域名的虚拟主机而在另外一些地址上配置基于IP的虚拟主机。
### 服务器配置
```
Listen 80
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
DocumentRoot /www/example1
ServerName www.example.com
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/example2
ServerName www.example.org
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/example3
ServerName www.example3.net
</VirtualHost>
# IP-based
<VirtualHost 172.20.30.50>
DocumentRoot /www/example4
ServerName www.example4.edu
</VirtualHost>
<VirtualHost 172.20.30.60>
DocumentRoot /www/example5
ServerName www.example5.gov
</VirtualHost>
```
## 将`<Virtual_host>`和`mod_proxy`模块一起使用
下面的例子允许一个前端机器代理一个运行在其他机器上的虚拟主机。在如下示例中,在`192.168.111.2`机器上配置了一个同名的虚拟主机。这样,万一在同一台机器上代理了多个主机名,`[ProxyPreserveHost](#calibre_link-670) On` 指令能确保指定的主机名顺利通过代理。
```
<VirtualHost *:*>
ProxyPreserveHost On
ProxyPass / http://192.168.111.2
ProxyPassReverse / http://192.168.111.2/
ServerName hostname.example.com
</VirtualHost>
```
## 使用"`_default_`"虚拟主机
### 为所有端口配置"`_default_`"虚拟主机
这样配置可以捕获_所有_指向没指定的IP地址和端口的请求。比如:一个没被任何虚拟主机使用的地址/端口对。
### 服务器配置
```
<VirtualHost _default_:*>
DocumentRoot /www/default
</VirtualHost>
```
这样一个使用通配符端口的默认虚拟主机可以有效的防止请求被主服务器接收。
如果一个地址/端口对已经被一个基于域名的虚拟主机使用,那么"`_default_`"虚拟主机决不会处理发向这个地址/端口对的请求。如果一个"`Host:`"请求头中包含未知信息,或者干脆就没有,那么它会被第一个基于域名的虚拟主机(也就是在配置文件中最先出现的使用了那个地址/端口对的虚拟主机)处理。
您可以用`AliasMatch`或`RewriteRule`来重写任何请求,使它指向一个简单信息页面(或脚本)。
### 为不同的端口配置"`_default_`"虚拟主机
与第一种一样,但我们想让服务器侦听很多端口而第二个"`_default_`"虚拟主机单独侦听80端口。
### 服务器配置
```
<VirtualHost _default_:80>
DocumentRoot /www/default80
# ...
</VirtualHost>
<VirtualHost _default_:*>
DocumentRoot /www/default
# ...
</VirtualHost>
```
侦听80端口的"`_default_`"虚拟主机(_必须_出现在所有使用通配符端口的虚拟主机之前)会捕获所有发向一个未指定的IP地址的请求。主服务器将不会用于伺服任何请求。
### 为单独一个端口配置"`_default_`"虚拟主机
如果我们只想在80端口上建立唯一的一个"`_default_`"虚拟主机,我们应该这样配置:
### 服务器配置
```
<VirtualHost _default_:80>
DocumentRoot /www/default
...
</VirtualHost>
```
发向一个未指定地址的80端口的请求将会由这个虚拟主机伺服;而发向未设定地址的其他端口的请求则由主服务器伺服。
## 将一个基于域名的虚拟主机移植为一个基于IP的虚拟主机
如果一个具有`www.example.org`域名的虚拟主机(就是[基于域名](#calibre_link-671)配置示例中的第二个)得到了自己的IP地址。为了避免一些域名服务器或代理服务器在移植期间仍对这个域名做老的解析,我们可以采用一种过渡方法:同时提供新旧两个IP地址的解析。
达到这个目的很简单。因为我们只要简单的把新地址(`172.20.30.50`)加入`VirtualHost`指令就行了。
### 服务器配置
```
Listen 80
ServerName www.example.com
DocumentRoot /www/example1
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40 172.20.30.50>
DocumentRoot /www/example2
ServerName www.example.org
# ...
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/example3
ServerName www.example.net
ServerAlias *.example.net
# ...
</VirtualHost>
```
现在这个虚拟主机就可以用新地址(表现为一个基于IP的虚拟主机)和旧地址(表现为一个基于域名的虚拟主机)同时进行访问了。
## 使用`ServerPath`指令
如果我们在同一个服务器上运行了两个基于域名的虚拟主机。为了匹配正确的虚拟主机,客户端必须发送正确的"`Host:`"头。而旧的使用HTTP/1.0的客户端无法发送这样的头,这样Apache就无法辨别客户端想要连接哪个虚拟主机(会用主虚拟主机来伺服这个请求)。为了尽量提供向下兼容性,我们可以提供一个主虚拟主机来返回一个页面,在页面中加入指向基于域名的虚拟主机的URL前缀的链接。
### 服务器配置
```
NameVirtualHost 172.20.30.40
<VirtualHost 172.20.30.40>
# 主虚拟主机
DocumentRoot /www/subdomain
RewriteEngine On
RewriteRule ^/.* /www/subdomain/index.html
# ...
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/subdomain/sub1
ServerName www.sub1.domain.tld
ServerPath /sub1/
RewriteEngine On
RewriteRule ^(/sub1/.*) /www/subdomain$1
# ...
</VirtualHost>
<VirtualHost 172.20.30.40>
DocumentRoot /www/subdomain/sub2
ServerName www.sub2.domain.tld
ServerPath /sub2/
RewriteEngine On
RewriteRule ^(/sub2/.*) /www/subdomain$1
# ...
</VirtualHost>
```
由于`ServerPath`指令的作用,发送到`http://www.sub1.domain.tld/sub1/`的请求_总会_被sub1-vhost所伺服。
如果客户端发送了正确的"`Host:`"头,发送到`http://www.sub1.domain.tld/`的请求只会被sub1-vhost所伺服。如果没有发送"`Host:`"头,客户端将会得到从主虚拟主机发送的信息页面。
请注意,这里还有一点小问题:如果客户端没有发送"`Host:`"头,发送到`http://www.sub2.domain.tld/sub1/`的请求还是会被sub1-vhost所伺服。
`RewriteRule`指令用以确保正确发送了"`Host:`"头的客户端可以任意使用这两种URL变量,比如说:使用或不使用URL前缀。
- Apache HTTP Server Version 2.2 文档 [最后更新:2006年3月21日]
- 版本说明
- 从1.3升级到2.0
- 从2.0升级到2.2
- Apache 2.2 新特性概述
- Apache 2.0 新特性概述
- The Apache License, Version 2.0
- 参考手册
- 编译与安装
- 启动Apache
- 停止和重启
- 配置文件
- 配置段(容器)
- 缓冲指南
- 服务器全局配置
- 日志文件
- 从URL到文件系统的映射
- 安全方面的提示
- 动态共享对象(DSO)支持
- 内容协商
- 自定义错误响应
- 地址和端口的绑定(Binding)
- 多路处理模块
- Apache的环境变量
- Apache处理器的使用
- 过滤器(Filter)
- suEXEC支持
- 性能方面的提示
- URL重写指南
- Apache虚拟主机文档
- 基于主机名的虚拟主机
- 基于IP地址的虚拟主机
- 大批量虚拟主机的动态配置
- 虚拟主机示例
- 深入研究虚拟主机的匹配
- 文件描述符限制
- 关于DNS和Apache
- 常见问题
- 经常问到的问题
- Apache的SSL/TLS加密
- SSL/TLS高强度加密:绪论
- SSL/TLS高强度加密:兼容性
- SSL/TLS高强度加密:如何...?
- SSL/TLS Strong Encryption: FAQ
- 如何.../指南
- 认证、授权、访问控制
- CGI动态页面
- 服务器端包含入门
- .htaccess文件
- 用户网站目录
- 针对特定平台的说明
- 在Microsoft Windows中使用Apache
- 在Microsoft Windows上编译Apache
- Using Apache With Novell NetWare
- Running a High-Performance Web Server on HPUX
- The Apache EBCDIC Port
- 服务器和支持程序
- httpd - Apache超文本传输协议服务器
- ab - Apache HTTP服务器性能测试工具
- apachectl - Apache HTTP服务器控制接口
- apxs - Apache 扩展工具
- configure - 配置源代码树
- dbmmanage - 管理DBM格式的用户认证文件
- htcacheclean - 清理磁盘缓冲区
- htdbm - 操作DBM密码数据库
- htdigest - 管理用于摘要认证的用户文件
- httxt2dbm - 生成RewriteMap指令使用的dbm文件
- htpasswd - 管理用于基本认证的用户文件
- logresolve - 解析Apache日志中的IP地址为主机名
- rotatelogs - 滚动Apache日志的管道日志程序
- suexec - 在执行外部程序之前切换用户
- 其他程序
- 杂项文档
- 与Apache相关的标准
- Apache模块
- 描述模块的术语
- 描述指令的术语
- Apache核心(Core)特性
- Apache MPM 公共指令
- Apache MPM beos
- Apache MPM event
- Apache MPM netware
- Apache MPM os2
- Apache MPM prefork
- Apache MPM winnt
- Apache MPM worker
- Apache模块 mod_actions
- Apache模块 mod_alias
- Apache模块 mod_asis
- Apache模块 mod_auth_basic
- Apache模块 mod_auth_digest
- Apache模块 mod_authn_alias
- Apache模块 mod_authn_anon
- Apache模块 mod_authn_dbd
- Apache模块 mod_authn_dbm
- Apache模块 mod_authn_default
- Apache模块 mod_authn_file
- Apache模块 mod_authnz_ldap
- Apache模块 mod_authz_dbm
- Apache模块 mod_authz_default
- Apache模块 mod_authz_groupfile
- Apache模块 mod_authz_host
- Apache模块 mod_authz_owner
- Apache模块 mod_authz_user
- Apache模块 mod_autoindex
- Apache模块 mod_cache
- Apache模块 mod_cern_meta
- Apache模块 mod_cgi
- Apache模块 mod_cgid
- Apache模块 mod_charset_lite
- Apache模块 mod_dav
- Apache模块 mod_dav_fs
- Apache模块 mod_dav_lock
- Apache模块 mod_dbd
- Apache模块 mod_deflate
- Apache模块 mod_dir
- Apache模块 mod_disk_cache
- Apache模块 mod_dumpio
- Apache模块 mod_echo
- Apache模块 mod_env
- Apache模块 mod_example
- Apache模块 mod_expires
- Apache模块 mod_ext_filter
- Apache模块 mod_file_cache
- Apache模块 mod_filter
- Apache模块 mod_headers
- Apache模块 mod_ident
- Apache模块 mod_imagemap
- Apache模块 mod_include
- Apache模块 mod_info
- Apache模块 mod_isapi
- Apache模块 mod_ldap
- Apache模块 mod_log_config
- Apache模块 mod_log_forensic
- Apache模块 mod_logio
- Apache模块 mod_mem_cache
- Apache模块 mod_mime
- Apache模块 mod_mime_magic
- Apache模块 mod_negotiation
- Apache模块 mod_nw_ssl
- Apache模块 mod_proxy
- Apache模块 mod_proxy_ajp
- Apache模块 mod_proxy_balancer
- Apache模块 mod_proxy_connect
- Apache模块 mod_proxy_ftp
- Apache模块 mod_proxy_http
- Apache模块 mod_rewrite
- Apache模块 mod_setenvif
- Apache模块 mod_so
- Apache模块 mod_speling
- Apache模块 mod_ssl
- Apache模块 mod_status
- Apache模块 mod_suexec
- Apache模块 mod_unique_id
- Apache模块 mod_userdir
- Apache模块 mod_usertrack
- Apache模块 mod_version
- Apache模块 mod_vhost_alias
- Developer Documentation for Apache 2.0
- Apache 1.3 API notes
- Debugging Memory Allocation in APR
- Documenting Apache 2.0
- Apache 2.0 Hook Functions
- Converting Modules from Apache 1.3 to Apache 2.0
- Request Processing in Apache 2.0
- How filters work in Apache 2.0
- Apache 2.0 Thread Safety Issues
- 词汇和索引
- 词汇表
- 指令索引
- 指令速查
- 模块索引
- 站点导航