Documentos de Académico
Documentos de Profesional
Documentos de Cultura
con docker
Una vez que hemos empezado a «dockerizar» aplicaciones, y antes de saltar al siguiente
nivel (kubernetes por ejemplo) nos encontramos con la necesidad de pasar a produccion las
aplicaciones que vamos desarrollando y, quizá, utilizar un gestor como Kubernetes nos
haga más complicado utilizar https. Hay dos soluciones principales que he utilizado para
distintos servicios y que os voy a comentar muy brevemente aquí: usar apache como proxy
inverso instalado en la máquina host o utilizar un docker con el proxy inverso en nginx.
Para los dos casos vamos a suponer que tenemos un contenedor docker con una aplicación
web que tenemos expuesto en el puerto 8080 (por ejemplo).
Llegados a este paso debemos crear un archivo de configuración para la aplicación web y
dejarlo en /etc/apache2/sites-available/misitio.conf algo como esto:
1
2 <VirtualHost *:80>
3 ServerName www.misitio.com
4
5 ServerAdmin info@la-demo.com
6 DocumentRoot /var/www/html
7
<Directory /var/www/html>
8 Options FollowSymLinks
9 AllowOverride All
10 Require all granted
11 </Directory>
12</VirtualHost>
13
Lo relevante es el nombre del sitio y un directorio para las páginas, que no vamos a utilizar,
pero que tiene que existir para las validaciones posteriores. En este caso estoy usando
también el módulo itk para que se ejecute con un usuario sin privilegos. Posteriormente a
esto ejecutamos:
Con esto ya tendremos el servicio apache levantado y respondiendo a peticiones, por lo que
podemos solicitar el certificado (recuerda que el dns del servicio debe apuntar a la dirección
IP del servidor).
1sudo certbot
Esto nos preguntará qué dominios queremos proteger y si todo ha ido bien nos generará un
archivo midominio-le-ssl.conf que contendrá ya los enlaces a los certificados y
configuración asociada. Con lo que ya podrías acceder a https://www.midominio.com
Ahora queda la parte en la que «conectamos» este servidor con nuestro docker que,
recordemos, está corriendo en el puerto 8080, para ello modificaremos el archivo de
configuración que nos ha creado certbot ejecutamos.
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/guacamole/
ProxyPassReverse / http://127.0.0.1:8080/guacamole/
1
https-portal:
2 image: steveltn/https-portal:1
3 depends_on:
4 - miservicio
5 ports:
- 80:80
6 - 443:443
7 restart: always
8 volumes:
9 - ./ssl_certs:/var/lib/https-portal
10 environment:
DOMAINS: 'www.midonio.com -> http://miservicio:8080
11#production'
12
Cada uno de los dos métodos tiene sus pros y sus contras (hacerlo en kubernetes es otra
historia y no aplica ninguno de estos métodos), pero básicamente si queremos exponer más
de un contenedor (en distintos docker-compose) la única manera es usar el proxy inverso
nativo, si todo lo que queréis servir por https está en un solo docker-compose el segundo
método es mucho más cómodo.
Por lo tanto, para empezar, vamos activar los módulos que necesitamos:
En nuestro servidor interno hemos creado un virtual host para servir una página estática,
index.html, con este contenido:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Probando proxy inverso con Apache2</title>
</head>
<body>
<h1>Probando proxy inverso con Apache2</h1>
<img src="img.jpg"/>
<img src="/img.jpg"/>
<br/>
<a href="http://10.0.0.6/carpeta/index.html">Enlace tipo
1</a><br/>
<a href="/carpeta/index.html">Enlace tipo 2</a><br/>
<a href="carpeta/index.html">Enlace tipo 3</a>
</body>
<Location "/web/">
ProxyPass "http://interno.example.org/"
</Location>
Evidentemente debe funcionar la resolución de nombre para que el proxy pueda acceder al
servidor interno.
Como vemos una imagen no se ha cargado, además no todos los enlaces funcionan, pero
antés vamos a solucionar el problema de las redirecciones.
Cuando creamos una redirección en un servidor web y el cliente intenta acceder al recurso,
el servidor manda una respuesta con código de estado 301 o 302, e indica la URL de la
nueva ubicación del recurso en una cabecera HTTP llamada Location.
La configuración quedaría:
<Location "/web/">
ProxyPass "http://interno.example.org/"
ProxyPassReverse "http://interno.example.org/"
</Location>
La página que servimos a través del proxy que se guarda en el servidor interno puede tener
declarada rutas, por ejemplo en imágenes o enlaces. Nos podemos encontrar con diferentes
tipos de rutas:
Si tenemos una ruta relativa, el cliente la va a poder seguir sin problema cuando accede a
través del proxy, pero si tenemos una ruta como la segunda no lo va a poder hacer, porque
en el DocumentRoot del proxy no existe este recurso. Al acceder al segundo enlace:
Para solucionar este problema debemos reescribir el HTML para cambiar la referencia del
enlace. Para ello necesitamos activar un nuevo módulo:
# a2enmod proxy_html
Como vemos hemos configurado un proxy para HTML, que será responsable de reescribir
todos las rutas que contiene el HYML, utilizando la directiva ProxyHTMLURLMap:
Es importante no poner la barra final, cuando se encuentra una ruta que coincide con el
primer patrón se reescribe con el segundo, esta regla reescribe las ruta del tipo de la primera
opción que hemos visto anteriormente. Para arreglar la rutas de la segunda opción,
utilizamos dentro de la sección Location:
ProxyHTMLURLMap / /web/
Acabamos de configurar un proxy que examina y reescribe el HTML de nuestro sitio web,
pero evidentemente existe más contenido en nuestro sitio que no es HTML y no debería ser
procesado por proxy_html. Esto se soluciona verificando la cabecera del contenido y
rechazando todos los contenidos que no tengan el tipo MIME adecuado.
Content-Type: text/html
Content-Encoding: gzip
Este contenido no debería pasar por el analizador de proxy_html. Para solucionar esto
podemos negarnos a admitir la compresión. La eliminación de cualquier cabecera de
petición Accept-Encoding hace el trabajo. Para ello podemos utilizar la directiva
RequestHeader del módulos headers, por lo tanto activamos el módulo:
# a2enmod headers
Una situación similar surge en el caso del contenido encriptado (https). En este caso,
usando el módulo ssl y un certificado en el proxy, de modo que la sesión segura real se
encuentre entre el navegador y el proxy, no al servidor interno.