Servir WebDAV tras un proxy HTTP/HTTPS
Web Distributed Authoring and Versioning (WebDAV) es una extensión del protocolo HTTP que añade verbos adicionales para poder, por ejemplo, realizar cambios en el servidor. Lo más evidente es almacenar o modificar ficheros, pero los cambios pueden ser semánticos. Por ejemplo, modificaciones coordinadas en documentos compartidos como un calendario o una agenda telefónica.
Apache soporta WebDAV y, de hecho, es la opción que yo recomiendo en vez del vetusto FTP, por ejemplo. Hay muchas ventajas: atravesar cortafuegos con facilidad, cifrado integrado a través de HTTPS y, en general, unificación con toda la infraestructura web.
Una cosa que suelo hacer con frecuencia es dar acceso a infraestructura protegida o unificar varios servidores web bajo un árbol común. Esto lo hago a través del módulo mod_proxy de Apache. Básicamente mod_proxy puede hacer que http://www.example.com/servidorA nos enseñe el contenido del servidor A y que http://www.example.com/servidorB nos muestre el contenido del servidor B. Hacer esto con mod_proxy es trivial, rutina. El cliente web se conecta a http://www.example.com/, indica la carpeta que quiere y mod_proxy realiza una petición HTTP/HTTPS por detrás al servidor adecuado para completar la petición del cliente.
Es importante, en estas circunstancias, que los enlaces que genera el servidor A sean o bien relativos o que se cambien para que parezcan provenir de http://www.example.com/servidorA. En el contexto de mod_proxy solemos usar la directiva ProxyPassReverse. Esta directiva nos permite interceptar las redirecciones HTTP generadas por el servidor A para que parezcan provenir de http://www.example.com/servidorA.
¿Qué pasa con WebDAV?. El problema es que WebDAV nos devuelve direcciones absolutas.
Veamos un ejemplo concreto. Supongamos un servidor web con esta configuración:
Esta configuración crea un servidor virtual WebDAV en cierta máquina, pero su directorio /Servidor2/ HTTP se mapea al directorio raíz de una segunda máquina. Por lo tanto https://webdav.XXXX/fichero1.txt es un fichero en una máquina, pero https://webdav.XXXX/Servidor2/fichero2.txt es equivalente a https://webdav2.XXXX/fichero2.txt, un fichero en el segundo servidor.
Esto funciona bien, pero tenemos alguna inconsistencia. Por ejemplo, veamos qué pasa si usamos WebDAV para pedir el listado del directorio raíz del primer servidor.
Enviamos al servidor lo siguiente:
Y la respuesta es:
Aquí vemos que la primera máquina tiene dos ficheros (fichero1.txt y fichero2.txt) y un directorio (directorio).
Veamos qué hay dentro del directorio:
La respuesta es:
Veamos ahora qué recibimos cuando accedemos al segundo servidor a través de una URL del primer servidor mapeada con mod_proxy:
Nos llega el siguiente resultado:
Vemos que el servidor que nos responde es otro diferente, como puede verse en la línea 3.
Obsérvese que hemos preguntado por el directorio Servidor2, ¡pero lo que nos está llegando son respuestas para el directorio raíz!. Dependiendo del cliente WebDAV que usemos y de lo que estemos haciendo, esta inconsistencia puede ser causa de problemas sutiles difíciles de diagnosticar.
Por ejemplo, mapear directorios WebDAV de esta manera en Kodi inserta películas en la biblioteca de vídeo que luego no se pueden reproducir.
La regla de oro, entonces, es la siguiente:
Cuando mapees servicios WebDAV tras un mod_proxy, asegúrate de que el directorio que ve el cliente WebDAV y el directorio que recibe el servidor final WebDAV son el mismo.
En este caso el cliente entra en /Servidor2/ pero el servidor 2 recibe una petición para su directorio raíz /. La solución es simple:
-
En el servidor que sirve de punto de entrada para las peticiones del cliente WebDAV cambiamos la configuración mod_proxy para que pase el directorio solicitado al segundo servidor:
-ProxyPass /Servidor2/ https://webdav2.XXXX/ -ProxyPassReverse /Servidor2/ https://webdav2.XXXX/ +ProxyPass /Servidor2/ https://webdav2.XXXX/Servidor2/ +ProxyPassReverse /Servidor2/ https://webdav2.XXXX/Servidor2/
-
En el servidor 2, debemos hacer que acepte /Servidor2/ como un directorio válido y que muestre ahí el contenido del directorio raíz. Hay varias formas de hacerlo. Tal vez la más simple sea utilizar la directiva Alias:
diff --git a/conf/httpd.conf b/conf/httpd.conf --- a/conf/httpd.conf +++ b/conf/httpd.conf @@ -1029,7 +1029,11 @@ <VirtualHost *:443> ServerName webdav2.XXXX:443 ServerAdmin jcea@jcea.es + +# Si se cambia 'DocumentRoot', cambiar también el 'Alias' +# Ver https://blog.jcea.es/20150507-proxy_webdav.html DocumentRoot /home/Servidor2/ + ErrorLog "logs/webdav2_XXXX_error.log" CustomLog "logs/webdav2_XXXX_access.log" combinedSSL @@ -1037,6 +1041,9 @@ SSLCertificateFile XXXX.crt SSLCertificateKeyFile XXXX.key +# Ver https://blog.jcea.es/20150507-proxy_webdav.html +Alias /Servidor2/ /home/Servidor2/ + <Location /> Dav on Options FollowSymLinks Indexes
Con este cambio el contenido del directorio raíz se verá también, tal cual, en el directorio /Servidor2/. Ahora la respuesta WebDAV será consistente. Pedimos:
La respuesta es:
Con este cambio Kodi ya está feliz y resuelvo, de paso, pequeños problemillas sutiles que me perseguían de vez en cuando pero que no me habían molestado lo bastante como para investigarlos. Hoy soy un poquito más feliz :).