Cuando tenemos que configurar un servidor web como Apache2 una de las típicas configuraciones es hacer que este servicio funcione a través de HTTPS para que nuestras webs sean seguras.

Pero no solo queremos que sean seguras nuestras webs, también queremos que carguen lo más rápido posible, y por ello acabamos configurando Varnish. Pero la configuración por HTTPS hace que esta configuración se complique un poco más.

Esto es debido a que Varnish por el momento no soporta HTTPS -aunque es cierto que no tiene planes de hacerlo-. Por lo tanto, no se puede confugurar Varnish si tenemos Apache2 únicamente escuchando por HTTPS.

Pero se puede hacer un trapicheo y configurar Apache para que haya un intermediario que acepte las conexiones HTTPS, las descifre y luego las entregue como peticiones HTTP a Varnish y luego las vuelva a cifrar al salir. Este intermediario lo vamos a llamar Terminación SSL -o en inglés SSL Termination-.

Hay muchos tutoriales en Internet que explican hacer esto junto a Nginx o algún otro Software para que haga de intermediario, pero no es necesario, ya que Apache puede terminar las conexiones SSL.

A continuación veremos como configurar Apache2 para que funcione como Terminación SSL y Varnish como servidor caché. Además exploraremos diferentes configuraciones:

HTTP y HTTPS: La web se servirá desde HTTP y HTTPS.

Sólo HTTPS: La web únicamente se servirá desde HTTPS.

Este tutorial ha sido probada en Debian 9.8 aunque seguramente en Ubuntu y otras distribuciones funcione igual.

Instalación de Apache y Varnish

Lo primero, como siempre actualizamos repositorios:

apt update apt upgrade

Instalamos Apache y Varnish:

apt install apache2 varnish

Y habilitamos los siguientes módulos necesarios:

a2enmod ssl a2enmod proxy a2enmod proxy_balancer a2enmod proxy_http

Y reiniciamos Apache:

systemctl restart apache2

Configuración HTTP y HTTPS

En esta configuración lo que haremos será configurar Apache para que tenga un VirtualHost escuchando a la IP externa para conexiones HTTPS y otro VirtualHost escuchando para localhost y así atender a las peticiones de Varnish.

Además, Varnish también aceptará las peticiones HTTP en las IP’s externas e internas y así se de HTTP.

Para que nos quede claro como se va a montar, he creado un diagrama para que quede claro:

Creación del certificado SSL

Como que vamos a configurar directamente el puerto 433 del Apache, primero necesitamos generar un certificado, para ello usaremos Certbot y lo primero que haremos será instalarlo:

apt-get install certbot python-certbot-apache

Y creamos certificado para nuestro dominio:

certbot --apache certonly -d dominio.es

Configuración Apache Externo

Ahora que ya tenemos certificado, creamos nuestro fichero para el Apache Externo en /etc/apache2/sites-available/external-htps.conf con el siguiente contenido:

<VirtualHost *:443> ServerName [DOMINIO] ErrorLog /var/www/html/vhosts/[DOMINIO]/logs/external-https_error.log CustomLog /var/www/html/vhosts/[DOMINIO]/logs/external-https_access.log combined SSLCertificateFile /etc/letsencrypt/live/[DOMINIO]/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/[DOMINIO]/privkey.pem ProxyPreserveHost On ProxyPass / http://127.0.0.1:80/ ProxyPassReverse / http://127.0.0.1:80/ </VirtualHost>

Como podéis observar, en el VirtualHost no aparece la directiva DocumentRoot . Esto es debido a que más abajo se establecen las directivas de Proxy. De esta forma, hacemos que Apache redirija las peticiones entrantes a 127.0.0.1:8080 (pasando por Varnish) y también para que acepte las respuestas desde la misma ubicación en lugar de servir el contenido directamente.

Lo siguiente será configurar el segundo VirtualHost para que Apache acepte peticiones HTTP y pueda servir el contenido con Varnish. Para ello crearemos este fichero /etc/apache2/sites-available/internal-htps.conf con el siguiente contenido:

<VirtualHost 127.0.0.1:8080> ServerName [DOMINIO] DocumentRoot /var/www/html/vhosts/[DOMINIO]/www ErrorLog /var/www/html/vhosts/[DOMINIO]/logs/internal-https_error.log CustomLog /var/www/html/vhosts/[DOMINIO]/logs/internal-https_access.log combined </VirtualHost>

La configuración final de Apache es hacer que Apache escuche por el puerto 8080 y no por el puerto 80, por eso modificamos /etc/apache2/ports.conf y comentamos el Listen 80 y añadimos lo siguiente:

#Listen 80 Listen 127.0.0.1:8080

Finalmente habilitamos los dos VirtualHosts y reiniciamos Apache:

a2ensite external-htps.conf a2ensite internal-htps.conf systemctl reload apache2

Configuración de Varnish

Lo primero que tenemos que configurar de Varnish es el archivo de SystemD, ya que este archivo establece el puerto en el que Varnish estará escuchando. El archivo se puede encontrar en /lib/systemd/system/varnish.service y lo dejamos así:

ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :80-T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m

Lo que hay que modificar es el -a :6081 por -a :80

Si nos fijamos un poco más, veremos que hay también malloc,256m . Esto es el tamaño de cache que va a guardar Varnish, si queremos augmentar el tamaño simplemente hay que cambiar el valor.



Y actualizamos SystemD:

systemctl daemon-reload

Para que toda la configuración se aplique, tenemos que reiniciar Apache y Varnish:

systemctl restart apache2 systemctl restart varnish

Ahora comprobamos que los servicios están escuchando por los puertos que toca:

netstat -tulpn | grep 'apache2\|varnishd'

Este comando nos debería de mostrar lo siguiente:

tcp 0 0 127.0.0.1:6082 0.0.0.0:* LISTEN 21586/varnishd tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 21586/varnishd tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 21499/apache2 tcp6 0 0 :::443 :::* LISTEN 21499/apache2

Configuración HTTP únicamente

La segunda configuración será para que solo Apache esté configurado para escuchar conexiones HTTPS en la dirección IP externa -y escuchando por el puerto 433-. A diferencia de la otra configuración HTTP y HTTPS, Varnish esta vez no se configurará para que escuche en una IP pública.

Para esta configuración, el diagrama es el siguiente:

Para esta configuración tendremos que crear primero un certificado con Certbot del mismo modo que hacemos en Creación del certificado SSL en el primer apartado Configuración HTTP y HTTPS.

certbot --apache certonly -d dominio.es

Una vez tenemos el certificado, creamos los ficheros de configuración de Apache con lo siguiente.

Para external-https.conf :

<VirtualHost *:443> ServerName [DOMINIO] ErrorLog /var/www/html/vhosts/[DOMINIO]/logs/external-https_error.log CustomLog /var/www/html/vhosts/[DOMINIO]/logs/external-https_access.log combined SSLCertificateFile /etc/letsencrypt/live/[DOMINIO]/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/[DOMINIO]/privkey.pem ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/ </VirtualHost>

Para internal-https.conf :

<VirtualHost 127.0.0.1:8080> ServerName [DOMINIO] DocumentRoot /var/www/html/vhosts/[DOMINIO]/www ErrorLog /var/www/html/vhosts/[DOMINIO]/logs/internal-https_error.log CustomLog /var/www/html/vhosts/[DOMINIO]/logs/internal-https_access.log combined </VirtualHost>

La configuración final de Apache es hacer que Apache escuche por el puerto 8181 y no por el puerto 80, por eso modificamos /etc/apache2/ports.conf y comentamos el Listen 80 y añadimos lo siguiente:

#Listen 80 Listen 127.0.0.1:8181

Finalmente habilitamos los dos VirtualHosts y reiniciamos Apache:

a2ensite external-htps.conf a2ensite internal-htps.conf systemctl reload apache2

Configuración de Varnish

Lo primero que tenemos que configurar de Varnish es el archivo de SystemD, ya que este archivo establece el puerto en el que Varnish estará escuchando. El archivo se puede encontrar en /lib/systemd/system/varnish.service y lo dejamos así:

ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a 127.0.0.1:8080 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m

Lo que hay que modificar es el -a :6081 por -a 127.0.0.1:8080

Si nos fijamos un poco más, veremos que hay también malloc,256m . Esto es el tamaño de cache que va a guardar Varnish, si queremos augmentar el tamaño simplemente hay que cambiar el valor.



Y actualizamos SystemD:

systemctl daemon-reload

Luego también tendremos que modificar /etc/varnish/default.vcl para que Varnish escuche por el puerto 8181:

backend default { .host = "127.0.0.1"; .port = "8181"; }

Para que toda la configuración se aplique, tenemos que reiniciar Apache y Varnish:

systemctl restart apache2 systemctl restart varnish

Ahora comprobamos que los servicios están escuchando por los puertos que toca:

netstat -tulpn | grep 'apache2\|varnishd'

Este comando nos debería de mostrar lo siguiente:

tcp 0 0 127.0.0.1:6082 0.0.0.0:* LISTEN 21586/varnishd tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 13072/varnishd tcp 0 0 127.0.0.1:8181 0.0.0.0:* LISTEN 21499/apache2 tcp6 0 0 :::443 :::* LISTEN 21499/apache2

Comprobar que está funcionando

Ahora que ya lo tenemos montado, el siguiente paso sería comprobar que está funcionando correctamente.

Como hemos visto antes, con el netstat ya hemos visto que los servicios están escuchando correctamente, eso ya es un indicativo de que todo está funcionando correctamente, aún así, podemos probar lo siguiente.

Desde otro terminal podemos ejecutar lo siguiente:

curl -v [dominio]

Y obtendremos lo siguiente:

* Rebuilt URL to: [dominio]/ * Trying 93.189.88.30... * TCP_NODELAY set * Connected to [dominio] ([IP SERVER]) port 80 (#0) > GET / HTTP/1.1 > Host: [dominio] > User-Agent: curl/7.50.3 > Accept: */* > < HTTP/1.1 200 OK < Date: Fri, 22 Feb 2019 14:13:56 GMT < Server: Apache/2.4.25 (Debian) < Vary: Accept-Encoding < Content-Type: text/html;charset=UTF-8 < X-Varnish: 32802 32793 < Age: 107 < Via: 1.1 varnish (Varnish/5.0) < Accept-Ranges: bytes < Content-Length: 554 < Connection: keep-alive <html> Test page for using Apache as SSL termination. </html> * Curl_http_done: called premature == 0 * Connection #0 to host [dominio] left intact

Si nos fijamos en las cabeceras HTTP vemos que:

< X-Varnish: 32802 32793 < Age: 107 < Via: 1.1 varnish (Varnish/5.0)

Eso significa que está funcionando correctamente. También tenemos comandos internos donde revisar que funciona correctamente: