一个IP地址如何部署多个网站域名:Web服务器的虚拟主机


记得大学时作为计算机专业学生,对计算机和网络世界很是好奇,时常会想BAT的平台服务都是怎么做出来的,有些机制是如何实现的。那时候就是逐渐了解到负载均衡的问题。后来毕业工作,更是接触到了网站建设,也有了做个人网站的想法,那时候就想到一个问题:能不能在同一台服务器上搭建多个网站,每个网站的域名不同,但IP地址都相同,能不能做到呢?如果能,要如何实现多一个域名解析到同一个IP地址,并且能区分出不同的网站内容?

我们都知道到用url(协议 + 域名)访问一个网站,首先会通过DNS服务将域名解析成IP地址,然后客户端和服务器最终都是通过IP地址来互通的。那么我们在互利网上部署网站,一般会也涉及到域名Domain和IP地址的对应关系问题:

1、最简单的情况下是一对一的关系,即一个域名和一个IP地址绑定,不存在共用的情况;
2、其次比较常见的是一对多的关系,即一个域名会被解析到多个IP地址,多见于有一定访问规模的网站,通常用路由就近访问和负载均衡的方案来实现;
3、然后就是今天要说的多对一的关系,即多个域名被解析到一个IP地址,多见于小流量网站。

现在回答开头有背景文字的问题:能实现,实现方案是web服务器的虚拟主机功能。果真是:我们能想到的问题,这世间早就有人想过了,我们遇到的问题,世间早就有人遇到了,并且很可能已经有解决方案了。事实上笔者已经有三个网站就是部署在同一个服务器上的,已经完美实现。

试想一下:
我们知道将一个域名要解析到某个IP,一般是在注册域名的服务商的系统中添加域名解析即可,即将域名和IP地址建立绑定关系,将多个域名绑定到同一个IP,也是完全可以的。这个IP被多个域名绑定,那么当客户端访问其中一个域名的url时,服务器如何知道客户端访问的是哪个域名呢,进而展示出响应域名网站的内容呢?
其实每个网站或服务在服务器中都对应着一个资源路径(一般是服务器磁盘文件系统中的文件夹),这个路径或文件夹一般叫“网站的根目录”,一个服务器上部署了多个网站,那一般也就对应着多个根目录文件夹。可见只要让服务器知道访问的当前IP地址的域名,让web服务器返回响应域名的根目录文件夹即可。

事实上在客户端发起HTTP请求时,会在请求头中会将访问的域名带上一并发给服务器,那么只要服务器上部署的“web服务器程序”能介绍收到域名信息,web服务器就可以根据不同的域名来返回对应的目录资源。
用HTTP代理工具抓数据包就能看到域名字段,如下图是一些示例:

实现:
是的,web服务器程序可以根据请求头的中的域名返回对应目录资源,这称作web服务器的“虚拟主机”功能。虚拟主机这个词相信大家都很熟悉,不过多数人所知道的虚拟主机一般是使用虚拟化技术(虚拟机软件)将物理服务器虚拟化为多个虚拟主机,常见的虚拟机软件有VMwareWorkstation、VirtualBox,不过这里说的web服务器的虚拟主机和虚拟化技术的虚拟技术是两回事。

以最常用的Apache服务器软件为例,要实现虚拟主机功能,只需要做一些虚拟主机的配置即可。

先打开Apache的主配置文件httpd.conf,找到Virtual hosts部分,将下面一行Include前的#删除,表示需要加载虚拟主机配置文件conf/extra/httpd-vhosts.conf:

然后打开虚拟配置文件conf/extra/httpd-vhosts.conf,这里是关键了:


如上图,一对VirtualHost标签就是一个虚拟主机(一个域名)的配置(上图两对VirtualHost标签,分别是该域名的HTTP访问80端口和HTTPS访问334端口的配置)。

<VirtualHost *:80>,表示网站是支持80端口的,这个很重要,因为一般我们在浏览器地址栏直接访问一个域名,就默认是走80端口的;
ServerName是主机名,一般填网站的域名;
ServerAlias是主机别名;
DocumentRoot是该域名对应网站的根目录文件夹路径;

11、12、13三行是开启重HTTP自动重定向到HTTPS(如果网站不做HTTPS化则可以不配置);

<VirtualHost *:443>,是HTTPS协议访问走443端口的配置:
ServerName、ServerAlias、DocumentRoot同上,与80端口的配置相同
SSLEngine on 表示打开SSL引擎
SSLCertificateFile是 SSL证书文件路径;
SSLCertificateKeyFile 是私钥文件路径;
SSLCertificateChainFile 是证书链文件;
Directory 标签配置网站根目录路径。

关于网站的HTTPS配置部署在后续文章中再详细说。

现在举个例子,有三个域名和其对应的网站根目录如下:

www.example01.com --> /webroot/example01/
www.example02.com --> /webroot/example02/
www.example03.com --> /webroot/example03/

虚拟主机配置文件应该是这样的:

### www.example01.com的HTTP配置 ###
<VirtualHost *:80>
    # This first-listed virtual host is also the default for *:80
    ServerName www.example01.com
    ServerAlias www.example01.com
    DocumentRoot /webroot/example01/

    #HTTP_TO_HTTPS_START
    #301-START
    RewriteEngine on
    RewriteCond  %{HTTPS} !=on
    RewriteRule  ^(.*)  https://%{SERVER_NAME}$1 [L,R]

    DirectoryIndex index.php
    ErrorLog /var/log/blog.mimvp.com-error_log
    CustomLog /var/log/blog.mimvp.com-access_log common
</VirtualHost>

### www.example01.com的HTTPS配置 ###
<VirtualHost *:443>
    # This first-listed virtual host is also the default for *:80
    ServerName www.example01.net
    ServerAlias www.example01.net
    DocumentRoot /webroot/example01/
        SSLEngine on
        SSLProtocol all -SSLv2 -SSLv3
        SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
        SSLHonorCipherOrder on
        SSLCertificateFile "cert/example01/example01_public.crt"
        SSLCertificateKeyFile "cert/example01/example01.key"
        SSLCertificateChainFile "cert/example01/example01_chain.crt"
        <Directory "/webroot/example01/">
                Options FollowSymLinks ExecCGI
                AllowOverride All
                Order allow,deny
                Allow from all
                Require all granted
        </Directory>
</VirtualHost>

### www.example02.com的HTTP配置 ###
<VirtualHost *:80>
    # This first-listed virtual host is also the default for *:80
    ServerName www.example02.com
    ServerAlias www.example02.com
    DocumentRoot /webroot/example02/

    #HTTP_TO_HTTPS_START
    #301-START
    RewriteEngine on
    RewriteCond  %{HTTPS} !=on
    RewriteRule  ^(.*)  https://%{SERVER_NAME}$1 [L,R]

    DirectoryIndex index.php
    ErrorLog /var/log/blog.mimvp.com-error_log
    CustomLog /var/log/blog.mimvp.com-access_log common
</VirtualHost>

### www.example02.com的HTTPS配置 ###
<VirtualHost *:443>
    # This first-listed virtual host is also the default for *:80
    ServerName www.example02.net
    ServerAlias www.example02.net
    DocumentRoot /webroot/example02/
        SSLEngine on
        SSLProtocol all -SSLv2 -SSLv3
        SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
        SSLHonorCipherOrder on
        SSLCertificateFile "cert/example02/example02_public.crt"
        SSLCertificateKeyFile "cert/example02/example02.key"
        SSLCertificateChainFile "cert/example02/example02_chain.crt"
        <Directory "/webroot/example02/">
                Options FollowSymLinks ExecCGI
                AllowOverride All
                Order allow,deny
                Allow from all
                Require all granted
        </Directory>
</VirtualHost>

### www.example03.com的HTTP配置 ###
<VirtualHost *:80>
    # This first-listed virtual host is also the default for *:80
    ServerName www.example03.com
    ServerAlias www.example03.com
    DocumentRoot /webroot/example03/

    #HTTP_TO_HTTPS_START
    #301-START
    RewriteEngine on
    RewriteCond  %{HTTPS} !=on
    RewriteRule  ^(.*)  https://%{SERVER_NAME}$1 [L,R]

    DirectoryIndex index.php
    ErrorLog /var/log/blog.mimvp.com-error_log
    CustomLog /var/log/blog.mimvp.com-access_log common
</VirtualHost>

### www.example03.com的HTTPS配置 ###
<VirtualHost *:443>
    # This first-listed virtual host is also the default for *:80
    ServerName www.example03.net
    ServerAlias www.example03.net
    DocumentRoot /webroot/example03/
        SSLEngine on
        SSLProtocol all -SSLv2 -SSLv3
        SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
        SSLHonorCipherOrder on
        SSLCertificateFile "cert/example03/example03_public.crt"
        SSLCertificateKeyFile "cert/example03/example03.key"
        SSLCertificateChainFile "cert/example03/example03_chain.crt"
        <Directory "/webroot/example03/">
                Options FollowSymLinks ExecCGI
                AllowOverride All
                Order allow,deny
                Allow from all
                Require all granted
        </Directory>
</VirtualHost>

更多的域名依次配置,其中的网站根目录和证书路径按照自己的实际情况配置即可。

不过一台服务器上部署的网站数量比较多的情况下,这种配置似乎也比较繁琐和重复,以后再发现是否有更简介的办法。


一片冰心在玉壶