apache 2.2 - Multiple SSL domains on the same IP address and same port?

17
2014-04
  • John

    This is a Canonical Question about Hosting multiple SSL websites on the same IP.

    I was under the impression that each SSL Certificate required it's own unique IP Address/Port combination. But the answer to a previous question I posted is at odds with this claim.

    Using information from that Question, I was able to get multiple SSL certificates to work on the same IP address and on port 443. I am very confused as to why this works given the assumption above and reinforced by others that each SSL domain website on the same server requires its own IP/Port.

    I am suspicious that I did something wrong. Can multiple SSL Certificates be used this way?

  • Answers
  • voretaq7

    For the most up-to-date information on Apache and SNI, including additional HTTP-Specific RFCs, please refer to the Apache wiki:http://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI


    FYsI: "Multiple (different) SSL certificates on one IP" is brought to you by the magic of TLS Upgrading. It works with newer Apache servers (2.2.x) and reasonably recent browsers (don't know versions off the top of my head).

    RFC 2817 (upgrading to TLS within HTTP/1.1) has the gory details, but basically it works for a lot of people (if not the majority).
    You can reproduce the old funky behavior with openssl's s_client command (or any "old enough" browser) though.

    Edit to add: apparently curl can show you what's happening here better than openssl:


    SSLv3

    mikeg@flexo% curl -v -v -v -3 https://www.yummyskin.com
    * About to connect() to www.yummyskin.com port 443 (#0)
    *   Trying 69.164.214.79... connected
    * Connected to www.yummyskin.com (69.164.214.79) port 443 (#0)
    * successfully set certificate verify locations:
    *   CAfile: /usr/local/share/certs/ca-root-nss.crt
      CApath: none
    * SSLv3, TLS handshake, Client hello (1):
    * SSLv3, TLS handshake, Server hello (2):
    * SSLv3, TLS handshake, CERT (11):
    * SSLv3, TLS handshake, Server key exchange (12):
    * SSLv3, TLS handshake, Server finished (14):
    * SSLv3, TLS handshake, Client key exchange (16):
    * SSLv3, TLS change cipher, Client hello (1):
    * SSLv3, TLS handshake, Finished (20):
    * SSLv3, TLS change cipher, Client hello (1):
    * SSLv3, TLS handshake, Finished (20):
    * SSL connection using DHE-RSA-AES256-SHA
    * Server certificate:
    *    subject: serialNumber=wq8O9mhOSp9fY9JcmaJUrFNWWrANURzJ; C=CA; 
                  O=staging.bossystem.org; OU=GT07932874;
                  OU=See www.rapidssl.com/resources/cps (c)10;
                  OU=Domain Control Validated - RapidSSL(R);
                  CN=staging.bossystem.org
    *    start date: 2010-02-03 18:53:53 GMT
    *    expire date: 2011-02-06 13:21:08 GMT
    * SSL: certificate subject name 'staging.bossystem.org'
           does not match target host name 'www.yummyskin.com'
    * Closing connection #0
    * SSLv3, TLS alert, Client hello (1):
    curl: (51) SSL: certificate subject name 'staging.bossystem.org'
    does not match target host name 'www.yummyskin.com'
    

    TLSv1

    mikeg@flexo% curl -v -v -v -1 https://www.yummyskin.com
    * About to connect() to www.yummyskin.com port 443 (#0)
    *   Trying 69.164.214.79... connected
    * Connected to www.yummyskin.com (69.164.214.79) port 443 (#0)
    * successfully set certificate verify locations:
    *   CAfile: /usr/local/share/certs/ca-root-nss.crt
      CApath: none
    * SSLv3, TLS handshake, Client hello (1):
    * SSLv3, TLS handshake, Server hello (2):
    * SSLv3, TLS handshake, CERT (11):
    * SSLv3, TLS handshake, Server key exchange (12):
    * SSLv3, TLS handshake, Server finished (14):
    * SSLv3, TLS handshake, Client key exchange (16):
    * SSLv3, TLS change cipher, Client hello (1):
    * SSLv3, TLS handshake, Finished (20):
    * SSLv3, TLS change cipher, Client hello (1):
    * SSLv3, TLS handshake, Finished (20):
    * SSL connection using DHE-RSA-AES256-SHA
    * Server certificate:
    *    subject: C=CA; O=www.yummyskin.com; OU=GT13670640;
                  OU=See www.rapidssl.com/resources/cps (c)09;
                  OU=Domain Control Validated - RapidSSL(R);
                  CN=www.yummyskin.com
    *    start date: 2009-04-24 15:48:15 GMT
    *    expire date: 2010-04-25 15:48:15 GMT
    *    common name: www.yummyskin.com (matched)
    *    issuer: C=US; O=Equifax Secure Inc.; CN=Equifax Secure Global eBusiness CA-1
    *    SSL certificate verify ok.
    
  • Michael Hampton

    Yes, but there are some caveats.

    This is accomplished through Server Name Indication, an extension to Transport Layer Security.

    What is Server Name Indication?

    Server Name Indication (RFC 6066; obsoleted RFC 4366, RFC 3546) is an extension to Transport Layer Security which allows the client to tell the server the name of the host it is trying to reach.

    SNI is compatible with TLS 1.0 and higher according to spec, but implementations may vary (see below). It cannot be used with SSL, so a connection must negotiate TLS (see RFC 4346 appendix E) for SNI to be used. This generally happens automatically with supported software.

    Why is SNI needed?

    In a normal HTTP connection, the browser informs the server of the hostname of the server it is trying to reach using the Host: header. This allows for a web server on a single IP address to serve content for multiple hostnames, which is commonly known as name-based virtual hosting.

    The alternative is to assign unique IP addresses for each web hostname to be served. This was commonly done in the very early days of the web, before it was widely known that IP addresses would run out and conservation measures began, and is still done this way for SSL virtual hosts (not using SNI).

    Because this method of transmitting the host name requires the connection to be already established, it does not work with SSL/TLS connections. By the time the secure connection is set up, the web server must already know which hostname it is going to serve to the client, because the web server itself is setting up the secure connection.

    SNI solves this problem by having the client transmit the hostname as part of the TLS negotiation, so that the server is already aware of which virtual host should be used to service the connection. The server can then use the certificate and configuration for the correct virtual host.

    Why not use different IP addresses?

    The HTTP Host: header was defined to allow more than one Web host to be served from a single IP address due to the shortage of IPv4 addresses, recognized as a problem as early as the mid-1990s. In shared web hosting environments, hundreds of unique, unrelated Web sites can be served using a single IP address this way, conserving address space.

    Shared hosting environments then found that the largest consumer of IP address space was the need for secure web sites to have unique IP addresses, creating the need for SNI as a stop-gap measure on the way to IPv6. Today it is sometimes difficult to obtain as few as 5 IP addresses (/29) without significant justification, often resulting in deployment delays.

    With the advent of IPv6, such address conservation techniques are no longer necessary, since a single host can have more IPv6 addresses assigned to it than the entire Internet contains today, but the techniques will probably still be used far into the future to service legacy IPv4 connections.

    Caveats

    Some operating system/browser combinations do not support SNI (see below), so using SNI is not appropriate for all situations. Sites targeting such system/browser combinations would have to forgo SNI and continue to use unique IP addresses for each virtual host.

    Of particular note, no version of Internet Explorer on Windows XP supports SNI. As this combination still represents a significant (but steadily decreasing; about 16% of Internet traffic in December 2012 according to NetMarketShare) portion of Internet traffic, SNI would be inappropriate for a site targeting these user populations.

    Support

    Many, but not all, commonly used software packages support SNI.

    (Omission from this list doesn't necessarily mean lack of support; it means there was a limit to how much I could type, or I couldn't quickly find the information in a search. If your software package isn't listed, searching for its name plus sni should reveal if support exists and how to set it up.)

    Library Support

    Most packages depend on an external library to provide SSL/TLS support.

    • GNU TLS
    • JSSE (Oracle Java) 7 or higher, only as a client
    • libcurl 7.18.1 or higher
    • NSS 3.1.1 or higher
    • OpenSSL 0.9.8j or higher
      • OpenSSL 0.9.8f or higher, with configure flags
    • Qt 4.8 or higher

    Server Support

    Most current versions of popular server software support SNI. Setup instructions are available for most of these:

    Client Support

    Most current web browsers and command line user agents support SNI.

    Desktop

    • Chrome 5 or higher
      • Chrome 6 or higher on Windows XP
    • Firefox 2 or higher
    • Internet Explorer 7 or higher, running on Windows Vista/Server 2008 or higher
      • Internet Explorer on Windows XP does not support SNI regardless of IE version
    • Konqueror 4.7 or higher
    • Opera 8 or higher (may require TLS 1.1 enabled to function)

    Mobile

    • Android Browser on 3.0 Honeycomb or higher
    • iOS Safari on iOS 4 or higher
    • Windows Phone 7 or higher

    Command Line

    • cURL 7.18.1 or higher
    • wget 1.14 or higher (Distributions may have backported a patch for SNI support)

    No Support

    • BlackBerry Browser
    • Internet Explorer (any version) on Windows XP

    (Note: Some information for this answer was obtained from Wikipedia.)

  • Kenny Rasschaert

    The problem:

    When a web client and a web server talk to each other over HTTPS, the very first thing that needs to happen is the secure handshake.

    Here is a simplified example of such a handshake:

    tls handshake

    If this were HTTP and not HTTPS, the first thing the client would have sent would have been something like this:

    GET /index.html HTTP/1.1
    Host: example.com
    

    This made multiple virtual hosts on a single IP address possible, since the server knows exactly what domain the client wants to access, namely example.com.

    HTTPS is different. Like I said earlier, the handshake comes before everything else. If you look at the third step of the handshake illustrated above (Certificate), the server needs to present a certificate to the client as part of the handshake, but has no clue what domain name the client is trying to access. The only option the server has is to send the same certificate every time, it's default certificate.

    You could still set up virtual hosts on your web server, but the server would always send the same certificate to each client. If you tried to host both the example.com and example.org websites on your server, the server would always send the certificate for example.com when a client requests a HTTPS connection. So when a client requests example.org over an established HTTPS connection, this would happen:

    enter image description here

    This problem effectively limits the number of domains you can server over HTTPS to one per IP address.

    The solution:

    The easiest way to solve this problem is for the client to tell the server which domain it wants to access during the handshake. This way the server can serve up the correct certificate.

    This is exactly what SNI, or Server Name Indication does.

    With SNI, the client sends the server name it wants to access as part of the first message, the "Client Hello" step in the handshake diagram above.

    Some older web browsers do not support SNI. For instance, on Windows XP there isn't a single version of Internet Explorer that has support for SNI. When accessing a resource over HTTPS on a server that makes use of SNI virtual hosts, you will be presented with a generic certificate, which may cause the browser to display a warning or error.

    enter image description here

    I've simplified things here to just explain the principle behind the problem and the solution. If you would like a more technical explanation, the wikipedia page or RFC 6066 might serve as good starting points. You can also find an up to date of list of servers and browsers that support SNI on wikipedia

  • Craig

    http://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI

    The client browser must also support SNI. Here are some browsers that do:

    * Mozilla Firefox 2.0 or later
    * Opera 8.0 or later (with TLS 1.1 enabled)
    * Internet Explorer 7.0 or later (on Vista, not XP)
    * Google Chrome
    * Safari 3.2.1 on Mac OS X 10.5.6 
    
  • Falcon Momot

    The server name indication (RFC6066) TLS extension is required for name-based vhosts to work over HTTPS.

    The extension is widely implemented and I have yet to encounter any issues with current software, but there is a chance that some clients (those not supporting it) will be routed to your default site if you depend on SNI.


  • Related Question

    ubuntu - Multiple SSL websites on the same Apache server
  • John

    I am still having issues trying to get multiple valid SSL certificates to work for multiple website domains on the same Apache-Ubuntu server. Client browsers need to successfully validate SSL certificates for Internet Explorer in WinXP, Vista and Win 7, FF on all operating systems, and Safari on Mac OSX.

    I tried to ask this question a couple of times previously, but because I didn't articulate my problem well, I got good answers that didn't help me achieve my end goal.

    For example, I tried to get multiple SSL to work on a single IP and port(q1) using NameBasedVirtual hosting and SNI(q2).

    But the problem is that it doesn't work for some of the older browsers like Internet Explorer 7 on Windows XP (works fine in IE7 on Windows Vista).

    So then I tried something I think is called IP aliasing. I purchased a new IP address 2.2.2.2. Now I have two: 1.1.1.1 and 2.2.2.2. I issued the following shell commands to add 2.2.2.2 to my server:

    john@server> ifconfig eth0:1 2.2.2.2 netmask 255.255.255.0
    john@server> route add -host 2.2.2.2 dev eth0:1
    

    And I made sure the following two lines existed in my /etc/hosts file

    1.1.1.1 john1
    2.2.2.2 john2
    

    I then set up my vhost files exactly as shown in q1. I restarted Apache but all my websites came through on the 1.1.1.1 IP instead of the 2.2.2.2 IP. As a result IE7 on Win XP threw a "certificate can't be trusted" error. When I changed any of the <VirtualHost *:443> to <VirtualHost 2.2.2.2:443>, ALL client browsers complained that the website's "certificate can't be trusted" (probably had something to do with the site using 1.1.1.1 IP address instead of 2.2.2.2 IP address).

    So I'm back to my original problem. Where can I find a working step-by-step guide on how to set up multiple SSL on the same apache-ubuntu server? Can anyone help me troubleshoot this problem?

    Thanks


  • Related Answers
  • goose

    You're on the right track here. Basically you must have a singular IP address per SSL website you plan on hosting for. The reasoning for this is that the SSL handshake is performed first and knows nothing of the domain name you're trying to connect too. Only after the SSL handshake is performed will the HTTP request be transmitted to the server.

    My suggestion would be to go to a more basic setup & enable one SSL virtualhost per domain with a corresponding IP address.

  • John

    Ok i figured out my problem. I needed to go to the zone file/dns manager and point each domain to their respective A record IP address (eg. site2.com to 2.2.2.2). After that, the VirtualHost files were able to recognize

    <VirtualHost 2.2.2.2:80> and <VirtualHost 2.2.2.2:443>
    

    That way, Apache could then start associating each domain name to their respective IP address.