要实现一个Apache服务器上提供多个SSL虚拟主机,可以:
* 使用多域名SSL证书,可以实现一个IP,一个443端口上多个SSL虚拟主机;
* 一个ip,为所有SSL虚拟主机配置单独的端口。比如,默认的虚拟主机使用443,其他的使用8080或8081等,且每个SSL虚
拟主机必须独占一个端口;
* 为Apache服务器配置多个IP,每个SSL虚拟主机独占IP。如果只有一张物理网卡,可以配置为网卡配置子接口;
* 使用mod_gnutls模块,创建多个SSL虚拟主机



1. Apache中同一IP多个HTTPS虚拟主机的实现
在 Apache 文档中提到,不能在单个 IP 上同时有多个按名字识别的虚拟主机(“named virtual host”)。不完全是这样。

HTTPS协议的过程是:服务器首先与客户机之间进行服务器身份验证并协商安全会话,然后,客户端向服务器发送 HTTP 请求。这样一来,在客户端开始发送HTTP请求之前,服务器就已经把证书发给了客户端(客户端根据本地的根证书去验证证书链,等等)。而最重要的是,为了表明身份,这个证书的”Common Name”填写的应该是域名,否则浏览器会给出警告。
既然在这个过程中,客户端就所访问的域名所处的地位是”被告知”的地位,因此,客户端再发出的 Host: 请求头也就显得不那么有意义了。另一方面,如果客户请求的域名与Common Name不符,浏览器也会给出警告。至少,在表面上看是这样。

不过,对于自行签署的证书,以及一些发证机构而言,其实还可以签署一种普适HTTPS证书,这种证书的Common Name一栏是 *.domain.tld 这样的形式,即其主机名部分可以是任意字符串,而只有域名部分是确定的。
当然,这种证书的安全性有一定的负面影响:由于一个证书可以验证整个域下面的所有服务器,一旦其被破解,则所有加密通讯也就同时失密了(当然,可以每台服务器使用自己的单独的证书),不过这个问题并不是太严重,通常还算是尚可接受的范围。另一个潜在的影响是,某些手机上运行的浏览器不能正确处理这种证书,不过这个问题仅限于希望给手机提供服务的网站。

因此,简而言之,符合这样几个条件的前提下,是可以在同一个IP上部署多个HTTPS虚拟主机的:
a) 这些虚拟主机是同属于同一域名的子域名
b) 拥有普适证书
c) 正确地配置Apache。

如果要在一个IP地址上需要部署多个SSL网站
(1)一种方法
:如果要在同一个IP地址的443端口上部署多个网站,必须保证这些网站的域名都能匹配相同的一张SSL证书。这是因为SSL握手协议过程中,是通过IP+Port来进行通信,一个IP的一个端口只能返给客户一张SSL证书(即使有多张证书,也只能返回第一张,因为无法分辨用户会需要返回哪张证书),如果这张证书能够满足这些网站的主机名匹配要求(访问b.test.com时,使用a.test.com段的证书,证书中包含a.test.com,于虚拟主机中的主机名之一匹配),就可以使用。
一般能匹配多个主机名的证书有通配符证书*.domain.com和多域名证书(www.domain.com,ftp.domain.com 等),以下我们提供一个典型同一个IP上的多主机名部署配置,www.domain.com对应的根目录在WWW下,ftp.domain.com对应的根目录在FTP下,www.domain.com与ftp.domain.com使用相同的证书:
NameVirtualHost 11.22.33.44:443

<VirtualHost 11.22.33.44:443>
DocumentRoot “C:/Apache2.2/htdocs/www”
ServerName www.domain.com
SSLEngine on
SSLCertificateFile “C:/Apache2.2/conf/server.cer”
SSLCertificateKeyFile “C:/Apache2.2/conf/server.key”
</VirtualHost>

<VirtualHost 11.22.33.44:443>
DocumentRoot “C:/Apache2.2/htdocs/ftp”
ServerName ftp.domain.com
SSLEngine on
SSLCertificateFile “C:/Apache2.2/conf/server.cer”
SSLCertificateKeyFile “C:/Apache2.2/conf/server.key”
</VirtualHost>

(2)另一种办法就是给每个网站分配不同的端口号
<VirtualHost 11.22.33.44:443>
DocumentRoot “C:/Apache2.2/htdocs/www”
ServerName www.domain.com
SSLEngine on
SSLCertificateFile “C:/Apache2.2/conf/server.cer”
SSLCertificateKeyFile “C:/Apache2.2/conf/server.key”
</VirtualHost>

<VirtualHost 11.22.33.44:8443>
DocumentRoot “C:/Apache2.2/htdocs/ftp”
ServerName ftp.domain.com
SSLEngine on
SSLCertificateFile “C:/Apache2.2/conf/server.cer”
SSLCertificateKeyFile “C:/Apache2.2/conf/server.key”
</VirtualHost>

基于域名的虚拟主机只能使用同一个证书,或者说,即使有不同的证书,最终使用的都是排在前面的默认的第一个


2. Apache中一张网卡绑定不同IP实现多个HTTPS虚拟主机
一张网卡绑定多个ip,ifconfig eth0:0……
<VirtualHost 220.181.75.109:8443>
ServerAdmin lala@corp.net.com
DocumentRoot /home/lala/apache/htdocs/test
ServerName a.test.com
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /home/lala/apache/conf/ssl.key/server.crt
SSLCertificateKeyFile /home/lala/apache/conf/ssl.key/server.key
#Include /home/lala/apache/conf/ssl.conf
#ErrorLog logs/dummy-a.test.com-error_log
#CustomLog logs/a.test.com-access_log common
</VirtualHost>

<VirtualHost 220.181.75.65:8443>
ServerAdmin lala@corp.net.com
DocumentRoot /home/lala/apache/htdocs/test2
ServerName d.test.com
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /home/lala/apache/conf/ssl.key/server2.crt
SSLCertificateKeyFile /home/lala/apache/conf/ssl.key/server2.key
#Include /home/lala/apache/conf/ssl.conf
#ErrorLog logs/dummy-a.test.com-error_log
#CustomLog logs/a.test.com-access_log common
</VirtualHost>


3. 使用mod_gnutls模块,创建多个SSL虚拟主机 (已经过时)
待研究~~

雖然 Apache 的文件上已明白說明單一IP無法建置多重 SSL 網站,不過這類需求與嘗試永遠存在。

有一陣子熱衷於尋找解法之際,曾看過 Everyday Work 的這篇解法,直接在 Certificate 中塞進多個 CN。最近則看到了國外提到用 mod_gnutls 這個 Apache Module 來實行,而且竟然又是個老早就有的專案。

mod_gnutls 是實做出 RFC3546 中的 Server Name Indication(SNI)解決方案,透過 TLS extension 達成 name-based 的 SSL 虛擬主機設定。mod_gnutls 的開發目的類似於 mod_ssl,但它並不依賴 OpenSSL,一方面是因為 OpenSSL 到目前 0.98 為止仍未支援 SNI,不過據說 0.99 會開始支援。

在下載並編譯後,將 libmod_gnutls.so 複製到 Apahce modules 目錄 (依平台而不同,如 /usr/lib/httpd/modules 或 /usr/local/libexec/apache2 等),並更名為 mod_gnutls.so,再將剛剛來源目錄中的 dhfile、rsafile 複製到 Apache 設定檔 httpd.conf 所在目錄。

接下來就是用你原本的方法產生每個網站的 Certificate,並參考官方說明文件編輯 Apache 設定檔:

 

### Main server configuration
# Load the module into Apache. LoadModule gnutls_module modules/mod_gnutls.so
# Using 4 memcache servers to distribute the SSL Session Cache. GnuTLSCache memcache "mc1.example.com mc2.example.com mc3.example.com mc4.example.com"
# With normal SSL Websites, you need one IP Address per-site. Listen 1.2.3.1:443

 

其中 GnuTLSCache 是設定 SSL Session Cache,為了效能考量,不建議關閉(None),如果沒有採用分散架構,可以用 dbm 取代上面的 memcache。先自行建立一個用以存放 cache 資料的目錄,並將 Apache 執行帳號設為擁有者,回到剛剛編輯的 Apache 設定檔:

 

GnuTLSCache dbm "剛剛建立之絕對路徑"
# Set a timeout for the SSL Session Cache entries.
# Usually, this is set to 300 seconds:
GnuTLSCacheTimeout 300

 

最後就是虛擬主機設定部份:

 

### Virtual Hosts
NameVirtualHost 1.2.3.1:443
<VirtualHost 1.2.3.1:443>
GnuTLSEnable on
GnuTLSPriorities NORMAL
DocumentRoot /www/site1.example.com/html
ServerName site1.example.com:443
GnuTLSCertificateFile conf/ssl/site1.crt
GnuTLSKeyFile conf/ss/site1.key
</VirtualHost>
<VirtualHost 1.2.3.1:443>
GnuTLSEnable on
GnuTLSPriorities NORMAL
DocumentRoot /www/site2.example.com/html
ServerName site2.example.com:443
GnuTLSCertificateFile conf/ssl/site2.crt
GnuTLSKeyFile conf/ss/site2.key
</VirtualHost>

Multiple SSL NameVirtualHosts in Apache2

其實這資訊 lag 了一年多了吧 (現在都 2.2.17 了)。
前幾週被人問到 SSL 時丟相關資訊給他,
才發現 wikipedia 的 SNI 那頁更新過了:Server Name Indication

這功能是從 Apache 2.3 merge 回來的:#34607 – Support for Server Name Indication
設定範例可以參考 Apache 的 wiki:SSL with Virtual Hosts Using SNI
其實設定上沒什麼新東西要注意,
一切都恢復到過去設 SSL vhost 的方式即可。
最多就是記得要擺 NameVirtualHost *:443 和 SSLStrictSNIVHostCheck off 這兩行吧。

說起來好像外國人流行用 MoinMoinWiki
像是 GCC Wiki 和 FreeBSD Wiki 都是用這套。
不清楚是因為有什麼便利性或功能性?
還是說單純就是因為偏好 Python 寫的東西?
找時間來玩玩看好了…
最近要忙著做 LLVM 的 trace 和 porting,
因為有簽萬惡的 NDA所以相關資訊不便公開。

總之因為 Apache 的 mod_ssl 已經原生支援 SNI 了,
所以這兩篇可以拿去丟了:
Multiple SSL NameVirtualHosts in Apache2
mod_gnutls 0.5.6 是地雷 (地雷?要炸就讓它繼續炸吧。I don’t care.)
不過我沒有砍文章的習慣,所以就留個提示訊息在上面吧。

 

Apache2.2.xでVirtualHost + SSL

まずはデフォルトでインストールされているOpenSSLで証明書を作成しておきます。

[ 証明書の作成 ]
mkdir ~/keys
cd ~/keys
openssl genrsa -des3 1024 > server.key
openssl rsa -in server.key -out server.key
openssl req -new -key server.key -out server.cert
openssl x509 -in server.cert -out server.cert -req -signkey server.key -days 3650

openssl-0.9.8i.tar.gzが必要になるので、そちらをインストールします。

[ OpenSSL インストール ]
cd /usr/local/src
wget http://www.openssl.org/source/openssl-0.9.8i.tar.gz
tar xzf openssl-0.9.8i.tar.gz
cd openssl-0.9.8i
./config –prefix=/usr/local/openssl enable-tlsext; make depend; make; make install; make clean;

パッチを充てて、Apacheをインストール。

[ Apache2.2 インストール ]
wget http://www.meisei-u.ac.jp/mirror/apache/httpd/httpd-2.2.10.tar.gz
wget https://sni.velox.ch/misc/httpd-2.2.x-sni.patch
tar xzf httpd-2.2.10.tar.gz
cd httpd-2.2.10
patch -p1 < ../httpd-2.2.x-sni.patch
./configure –prefix=/usr/local/apache –enable-so –enable-ssl –with-ssl=/usr/local/openssl
make; make install; make clean
cp ~/keys/* /usr/local/apache/conf/

/usr/local/apache/conf/httpd.conf に下記1行を追記。
[ /usr/local/apache/conf/httpd.conf ]
# My configration
Include conf/extra/httpd-my.conf

httpd-my.confで設定を行う

vi ./conf/extra/httpd-my.conf
——————————-
#
# When we also provide SSL we have to listen to the
# standard HTTP port (see above) and to the HTTPS port
#
# Note: Configurations that use IPv6 but not IPv4-mapped addresses need two
#       Listen directives: “Listen [::]:443″ and “Listen 0.0.0.0:443″
#
Listen 443

##
##  SSL Global Context
##
##  All SSL configuration in this context applies both to
##  the main server and all SSL-enabled virtual hosts.
##

#
#   Some MIME-types for downloading Certificates and CRLs
#
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl

#   Pass Phrase Dialog:
#   Configure the pass phrase gathering process.
#   The filtering dialog program (`builtin’ is a internal
#   terminal dialog) has to provide the pass phrase on stdout.
#SSLPassPhraseDialog  builtin

#   Inter-Process Session Cache:
#   Configure the SSL Session Cache: First the mechanism
#   to use and second the expiring timeout (in seconds).
#SSLSessionCache         “dbm:/usr/local/apache/logs/ssl_scache”
#SSLSessionCache        “shmcb:/usr/local/apache/logs/ssl_scache(512000)”
#SSLSessionCacheTimeout  300

#   Semaphore:
#   Configure the path to the mutual exclusion semaphore the
#   SSL engine uses internally for inter-process synchronization.
#SSLMutex  “file:/usr/local/apache/logs/ssl_mutex”

#
# Virtual Hosts

NameVirtualHost *:80
NameVirtualHost *:443

<VirtualHost *:80>
ServerAdmin webmaster@hoge.com
DocumentRoot “/home/www/v1″
ServerName v1.hoge.com

<Directory “/home/www/v1″>
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

<VirtualHost *:80>
ServerAdmin webmaster@hoge.com
DocumentRoot “/home/www/v2″
ServerName v2.hoge.com

<Directory “/home/www/v2″>
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

# Secure Shell ver.
<VirtualHost *:443>
ServerAdmin webmaster@hoge.com
DocumentRoot “/home/www/v1″
ServerName v1.hoge.com:443

#SSL Engine Switch:
#Enable/Disable SSL for this virtual host.
SSLEngine on

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you’ve both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
    SSLCertificateFile       “/usr/local/apache/conf/server.cert”
SSLCertificateKeyFile “/usr/local/apache/conf/server.key”

<Directory “/home/www/v1″>
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

<VirtualHost *:443>
ServerAdmin webmaster@hoge.com
DocumentRoot “/home/www/v2″
ServerName v2.hoge.com:443

#SSL Engine Switch:
#Enable/Disable SSL for this virtual host.
SSLEngine on

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you’ve both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateFile “/usr/local/apache/conf/server.cert”
SSLCertificateKeyFile “/usr/local/apache/conf/server.key”

<Directory “/home/www/v2″>
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
——————————-
VirtualHostとSSLを併用する場合は、<VirtualHost *:443><VirtualHost *:80>を必要台数分記述します。

■追記
Apache 2.2.11 の場合は https://sni.velox.ch/misc/ から対応しているパッチを落として充てて下さい。

■追記その2 -2009/10/12-
Apache 2.2.12以降はパッチ適用の必要がなくなりました。
./configure –prefix=/usr/local/apache –enable-so –enable-ssl –with-ssl=/usr/local/openssl;
make; make install; make clean

だけで大丈夫です。opensslはenable-tlsext を指定して下さい。