Esta semana tuve la necesidad de habilitar SSL en un servidor Web que aloja diferentes dominios (cada uno con su certificado SSL/TLS provisto por Let's Encrypt). El problema es que este servidor Web posee una única dirección IP a la cual resuelven todos los nombres de host de los diferentes dominios y sitios Web hospedados en el mismo.

Tradicionalmente sólo se podía habilitar SSL en un sitio Web si éste estaba ligado a una y sólo una dirección IP en particular. Esto era una limitación muy grande pues si, por ejemplo, necesitaba habilitar SSL en 3 sitios Web diferentes, necesitaba 3 direcciones IP dedicadas a cada uno.

Afortunadamente, con la llegada de Apache 2.2.12 en 2009 se agregó el soporte para SNI (Server Name Indication). SNI es una extensión del protocolo TLS a través de la cual los clientes le indican al servidor el nombre de host al cual están tratando de conectarse, para que éste les envíe el certificado correspondiente. De esta forma es posible tener múltiples certificados asociados a diferentes nombres de host en una misma dirección IP. Por supuesto los clientes deben soportar esta extensión.

Actualmente la mayoría de los clientes soportan esta extensión, a excepción de unas pocas librerías y sistemas operativos cuasi-obsoletos como Symbian o Blackberry OS, al igual que el navegador de línea de comandos ELinks.

Gracias a SNI es posible configurar sitios HTTPS basados en nombre, de la misma forma en que se configuran sitios HTTP basados en nombre (VirtualHosts).



Los requisitos para poder utilizar SNI en un servidor Web son los siguientes:

  • Correr Apache 2.2.12 o superior.
  • Utilizar OpenSSL 0.9.8f o superior compilado con soporte para la extensión TLS.
  • Apache debe ser compilado contra dicha versión de OpenSSL y con soporte para SNI.

Las distribuciones GNU/Linux actuales cumplen con estos requisitos, con lo cual no es necesario realizar ninguna tarea más que verificar las versiones utilizadas:

root@debian7:~# apache2 -version
Server version: Apache/2.2.22 (Debian)
Server built:   Feb 22 2017 15:49:33
root@debian7:~# openssl version
OpenSSL 1.0.1t  3 May 2016

Para comenzar, se debe modificar la configuración de puertos de Apache. Editar le archivo ports.conf:

root@debian7:~# cd /etc/apache2/
root@debian7:/etc/apache2# nano ports.conf

Es necesario permitir que Apache escuche en el puerto 443 en todas las direcciones IP (*) agregando la línea NameVirtualHost *:443. Para ello cambiar:

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
    Listen 443
</IfModule>

Por:

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
    NameVirtualHost *:443
    Listen 443
</IfModule>

Además, deshabilitar el VirtualHost "default-ssl":

root@debian7:/etc/apache2# a2dissite default-ssl

O, si dicho VirtualHost es necesario, cambiar su configuración tal como se indica en el archivo ports.conf.

A continuación, crear todos los sitios SSL necesarios. Se define un VirtualHost para cada sitio SSL. Por ejemplo para "www.sitioejemplo.com.ar" y "www.otrositio.com.ar":

root@debian7:/etc/apache2# nano sites-available/sitioejemplo-ssl
<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName www.sitioejemplo.com.ar
        DocumentRoot /var/www/sitioejemplo

        <Directory /var/www/sitioejemplo>
                Options FollowSymLinks MultiViews
                DirectoryIndex index.html
                AllowOverride none
                Order allow,deny
                allow from all
        </Directory>

        ErrorLog /var/log/apache2/sitioejemplo-ssl-error.log
        LogLevel warn
        CustomLog /var/log/apache2/sitioejemplo-ssl-access.log combined

        SSLEngine on

        SSLCertificateFile /etc/letsencrypt/live/www.sitioejemplo.com.ar/cert.pem
        SSLCertificateChainFile /etc/letsencrypt/live/www.sitioejemplo.com.ar/chain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/www.sitioejemplo.com.ar/privkey.pem

</VirtualHost>
</IfModule>
root@debian7:/etc/apache2# nano sites-available/otrositio-ssl
<VirtualHost *:443>
        ServerName www.otrositio.com.ar
        DocumentRoot /var/www/otrositio

        <Directory /var/www/otrositio>
                Options FollowSymLinks MultiViews
                AllowOverride AuthConfig FileInfo
                Order allow,deny
                allow from all
        </Directory>

        ErrorLog /var/log/apache2/otrositio-error.log
        LogLevel warn
        CustomLog /var/log/apache2/otrositio-access.log combined

        SSLEngine on
        SSLCertificateFile    /etc/letsencrypt/live/www.otrositio.com.ar/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/www.otrositio.com.ar/privkey.pem
        SSLCertificateChainFile /etc/letsencrypt/live/www.otrositio.com.ar/chain.pem

</VirtualHost>

Una vez creados todos los sitios SSL, habilitarlos utilizando a2ensite:

# a2ensite sitioejemplo-ssl
# a2ensite otrositio-ssl

Por último, reiniciar Apache:

# service apache2 restart

Eso es todo, basta verificar el funcionamiento de cada sitio anteponiendo https:// en la URL.

Adicionlamente es posible habilitar la directiva SSLStrictSNIVHostCheck para impedir que los clientes que no soportan SNI accedan al servidor. Por defecto, Apache los redirige al sitio SSL por defecto. Aunque de todas formas no tiene mucho sentido, salvo que en dicho sitio se cree una única página con un mensaje genérico como "Estimado usuario, necesita actualizar su navegador Web para acceder a este sitio. Disculpe las molestias."


Tal vez pueda interesarte


Compartí este artículo