Servidor Docker con HTTPS y administración gráfica
Con contenedores Docker es posible desplegar toda una infraestructura, en producción, de una manera sencilla. Esto gracias a las imágenes de contenedores que están disponibles[1] y las facilidades que aporta Docker Compose para un despliegue complejo.
Es necesario tener previamente instalados Docker y Docker Compose, así como tener conocimientos básicos en estas herramientas y en el intérprete de comandos.
A continuación se describe una solución, para hacer un despliegue con las siguientes características:
- Contenedor con proxy reverso, que actúa como intermediario entre los demás contenedores y las peticiones desde Internet. Este es el único contenedor con puertos expuestos. Todo el tráfico desde y hacia el exterior pasa por aquí, lo que facilita configurar una conexión cifrada HTTPS, pues se hace una única vez.
- Comunicación entre los contenedores y el proxy reverso utilizando la red privada de Docker. De manera que no es necesario exponer puertos, ni configurar certificados para HTTPS.
- Redes aisladas para cada servicio, esto para aumentar la seguridad.
- Contenedor Portainer, un gestor de contenedores con interfaz web, muy sencillo y completo.
- Uno o más contenedores, con servicios como un Wordpress, Drupal, Nextcloud, etc. Al final del artículo se describen algunos ejemplos.
Los pasos y las configuraciones detalladas son suficientes para desplegar esta infraestructura. Sin embargo, se recomienda encarecidamente estudiar y entender el uso de estas herramientas, por un lado para comprender y configurar su entorno sin contratiempos, y por otro lado para saber como adaptar la solución a su necesidad específica.
Configuración base
En la solución se incluyen varios servicios. El proxy-reverso es esencial, el portainer no es obligatorio pero si muy útil y los demás son a modo de ejemplo, sustituya por los servicios que desea desplegar.
Archivo docker-compose.yml
version: "2.4"
services:
# Proxy reverso nginx + HTTPS con Let's Encrypt (obligatorio)
proxy:
image: linuxserver/swag
container_name: proxy
environment:
- PUID=1000
- PGID=1000
# Configuracion de Let's Encrypt
- URL=sitio.ucr.ac.cr
- VALIDATION=http
- EMAIL=juanito.perez@ucr.ac.cr
- DHLEVEL=4096
ports:
# Solo el proxy tiene puertos expuestos,
# los demas contenedores salen por aqui.
- "80:80"
- "443:443"
volumes:
- "proxyconfig:/config"
networks:
# La comunicacion con los contenedores es por
# redes individuales, para proporcionar aislamiento
- portainer-net
- website-net
restart: always
# Gestor de contenedores via interfaz web (recomendado)
portainer:
image: portainer/portainer
container_name: portainer
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "portainerdata:/data"
networks:
- portainer-net
restart: always
# Defina aqui los servicios adicionales
website:
image: php:apache
container_name: website
volumes:
- websitevolume:/var/www/html
networks:
- website-net
websitedb:
image: mariadb:latest
container_name: websitedb
volumes:
- websitedbvolume:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "h4ckm3"
MYSQL_USER: 'userdb'
MYSQL_PASSWORD: 'us3r'
MYSQL_DATABASE: 'webdb'
networks:
- website-net
# Redes y volumenes utilizados por los servicios
volumes:
proxyconfig:
portainerdata:
websitevolume:
websitedbvolume:
networks:
portainer-net:
website-net:
Una vez editado el archivo, guárdelo y, en el mismo directorio donde se encuentra, ejecute:
docker-compose up -d
docker-compose logs -f
Realice esta acción cada vez que actualice el archivo.
El segundo comando le mostrará los logs, o bitácoras, donde podrá monitorear el proceso. Presione Control+C
para salir.
Configuración del proxy
El proxy es el intermediario entre Internet y los contenedores. Este contenedor utiliza la imagen linuxserver/swag, que es una excelente solución que incluye seguridad, certificados Let's Encrypt y actualizaciones regulares.
La primera tarea que realizará, será solicitar los certificados a Let's Encrypt, para poder comunicarse al exterior de manera segura, sobre protocolo HTTPS. Tome nota que esta tarea puede demorar un poco. Este proceso es automático y utilizará los datos de las respectivas variables de entorno, del archivo docker-compose.yml. Los certificados son libres, gratuitos y se renuevan de manera automática, por lo que no necesitará pasos adicionales en el futuro.
Cada vez que añada un nuevo servicio, deberá editar el archivo de configuración del proxy, para indicar a cuál servicio dirigir una petición. Por ejemplo, cuando un usuario escriba la dirección sitio.ucr.ac.cr/web, el proxy redirigirá la petición al contenedor website.
En Docker la dirección de un contenedor es típicamente su nombre, no se acostumbra usar su número IP. Continuando con el ejemplo, para indicar la dirección del contenedor website, puerto 80, se escribe: "website:80".
La imagen utilizada para este proxy tiene instalados los editores vi y nano. Puede utilizar cualquiera de estos para modificar los archivos de configuración.
Teniendo lo anterior claro, ingrese al contenedor ejecutando:
docker-compose exec proxy bash
- Esta sintaxis se explica en el artículo Docker, aplicaciones en cualquier parte.
- Si configura Portainer, podrá acceder a la línea de comandos de cualquier contenedor desde la interfaz web.
En el contenedor edite el archivo:
/config/nginx/site-confs/default
El primer server block del archivo de configuración, el que escucha en el puerto 80, redirige todo el tráfico HTTP a HTTPS. El segundo server block, el que escucha en el puerto 443, es el que se debe modificar cada vez que se configure un nuevo contenedor con salida a Internet.
Antes de continuar, se debe configurar el server_name en ambos bloques, indicando el nombre del dominio al que está respondiendo el servidor, así:
server {
listen 80 default_server;
. . .
server_name sitio.ucr.ac.cr;
. . .
}
server {
listen 443 ssl http2 default_server;
. . .
server_name sitio.ucr.ac.cr;
. . .
}
Ahora, por cada redirección que se necesite, se debe añadir un location al bloque que escucha en el puerto 443. Por ejemplo para que la petición sitio.ucr.ac.cr/web sea redirigida al contenedor llamado "website", al puerto 80, debería hacerse de la siguiente forma:
server {
listen 80 default_server;
. . .
}
server {
listen 443 ssl http2 default_server;
. . .
location /web/ {
proxy_pass http://website:80/;
include /config/nginx/proxy.conf;
}
. . .
}
La configuración incluida, del archivo /config/nginx/proxy.conf, contiene los típicos parámetros para un proxy.
O bien, si se quiere hacer redirección de la raíz del dominio, se agregarían estas líneas:
location / {
proxy_pass http://website:80/;
include /config/nginx/proxy.conf;
}
De esta manera, cuando se reciba la petición sitio.ucr.ac.cr, quién responderá será el contenedor website.
Cuando se haya terminado de editar el archivo, se sale del contenedor y se reinicia para aplicar los cambios. Repita esto cada vez que actualice el archivo.
exit
docker-compose restart proxy
Nota: cada vez que actualice la configuración del proxy, reinícielo de esta manera, no lo haga desde la interfaz de Portainer.
Configuración de portainer
Portainer es un gestor de contenedores. La administración se hace a través de una amigable y poderosa interfaz web. Se instala como un contenedor más, tal como se aprecia en el archivo docker-compose.yml.
Para poder acceder este contenedor, es necesario configurar dos redirecciones en el proxy:
location /portainer/ {
proxy_pass http://portainer:9000/;
include /config/nginx/proxy.conf;
}
location /portainer/api/websocket/ {
proxy_pass http://portainer:9000/api/websocket/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
Una vez configurado el proxy. Ingrese a la dirección: https://sitio.ucr.ac.cr/portainer.
Si todo está correctamente configurado, se le pedirá que defina el nombre de usuario de la cuenta administrativa y una contraseña. Una vez realizado este paso, se le preguntará a qué tipo de ambiente conectarse. Este es un escenario standalone, así que escoja la opción Local y presione Connect.
Ejemplos de configuración de servicios
A continuación se muestran algunos ejemplos. Estos pueden ser añadidos a su solución o bien ser tomados como ejemplo para implementar un nuevo servicio. Se asume que ya se cuenta con una configuración base, la cuál se ampliará con las siguientes configuraciones.
Wordpress
Wordpress es un sistema gestor de contenidos. Es el CMS más utilizado en Internet, con el respaldo de una enorme comunidad.
Archivo docker-compose.yml
Modifique el archivo docker-compose.yml para añadir los siguientes servicios, volúmenes y redes.
services:
# Agregue la red wordpress-net al servicio proxy
proxy:
. . .
networks:
. . .
wordpress-net
# Agregue los servicios relacionados a Wordpress
wordpress:
image: wordpress:latest
container_name: wordpress
volumes:
- wordpressdata:/var/www/html
environment:
WORDPRESS_DB_HOST: wordpressdb:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: j+Uw*KT-r4f
networks:
- wordpress-net
restart: always
wordpressdb:
image: mysql:5.7
container_name: wordpressdb
volumes:
- wordpressdb:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: Zu!zX?9Y.vs
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: j+Uw*KT-r4f
networks:
- wordpress-net
restart: always
# Agregue los nuevos volúmenes y redes a las respectivas secciones:
volumes:
. . .
wordpressdata:
wordpressdb:
networks:
. . .
wordpress-net:
Recuerde ejecutar docker-compose up -d
cada vez que actualice el archivo.
Configure el proxy añadiendo el siguiente location:
location /wordpress/ {
proxy_pass http://wordpress:80/;
include /config/nginx/proxy.conf;
}
Recuerde reiniciar el contenedor con docker-compose restart proxy
cada vez que modifique su configuración.
Configuración
Una vez actualizados los respectivos archivos de configuración, ingrese a sitio.ucr.ac.cr/wordpress.
Se le mostrará el script de instalación. Seleccione idioma, escriba el título del sitio, defina un usuario administrador, indique una dirección de correo-e y presione "Install Wordpress".
Nextcloud
Nextcloud es un servicio de alojamiento de archivos, de una forma similar a la que lo hace Dropbox, con la ventaja de que es de código abierto y su funcionalidad puede ser extendida con una serie de plugins.
Dockerfile
La imagen de Nextcloud no cuenta con el editor vi o nano, los cuáles son muy útiles para modificar los archivos de configuración del contenedor. Es posible instalarlos con la herramienta apt una vez desplegado el contenedor, sin embargo estos cambios se pierden cada vez que se actualiza. La solución es compilar una imagen personalizada, definiendo la configuración en un archivo Dockerfile. Esto con Docker Compose, como es de esperar, se hace de forma automática, solo se requiere añadir la configuración necesaria.
En el directorio donde se encuentra el archivo docker-compose.yml, cree un subdirectorio llamado nextcloud:
mkdir nextcloud
Cree y edite el archivo:
nextcloud/Dockerfile
Agregando las siguientes líneas:
FROM nextcloud:latest
RUN apt update && apt install -y vi nano
Archivo docker-compose.yml
Modifique el archivo docker-compose.yml para añadir los siguientes servicios, volúmenes y redes.
services:
# Agregue la red nextcloud-net al servicio proxy
proxy:
. . .
networks:
. . .
nextcloud-net
# Agregue los servicios relacionados al Nextcloud
nextcloud:
build:
context: ./nextcloud
container_name: nextcloud
volumes:
- nextclouddata:/var/www/html
networks:
- nextcloud-net
restart: always
nextclouddb:
image: mariadb:latest
container_name: nextclouddb
volumes:
- nextclouddb:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: Q5L&E6!Umi
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: hd?YhN.h4e
networks:
- nextcloud-net
restart: always
# Agregue los nuevos volúmenes y redes a las respectivas secciones:
volumes:
. . .
nextclouddata:
nextclouddb:
networks:
. . .
nextcloud-net:
Nótese que en este caso, en lugar de añadir la opción image para el servicio nextcloud, se añadió la opción build, indicando la ruta al directorio con el archivo Dockerfile.
Recuerde ejecutar docker-compose up -d
cada vez que actualice el archivo.
Configure el proxy añadiendo el siguiente location:
location /nextcloud/ {
proxy_pass http://nextcloud:80/;
include /config/nginx/proxy.conf;
}
Recuerde reiniciar el contenedor con docker-compose restart proxy
cada vez que modifique su configuración.
Configuración
Ingrese al contenedor nextcloud:
docker-compose exec nextcloud bash
Con el editor de su preferencia modifique el archivo:
/var/www/html/config/config.php
Añada esta configuración:
<?php
$CONFIG = array (
. . .
'trusted_domains' =>
array (
0 => 'sitio.ucr.ac.cr',
),
'trusted_proxies' =>
array (
0 => 'proxy',
),
. . .
'overwrite.cli.url' => 'http://sitio.ucr.ac.cr/nextcloud',
'overwritewebroot' => '/nextcloud',
'overwriteprotocol' => 'https',
. . .
);
Ingrese a la dirección sitio.ucr.ac.cr/nextcloud.
En Create an admin account, defina:
- Nombre de usuario administrador
- Una contraseña fuerte
Extienda Storage & Database.
En Data folder deje la dirección sugerida: /var/www/html/data. Esta ruta se encuentra dentro del volumen persistente.
En Configure the database, seleccione MySQL/MariaDB y configure así:
- Database user: nextcloud
- Database password: El indicado en la variable de entorno MYSQL_PASSWORD
- Database name: nextcloud
- Database host: nextclouddb:3306
Presione Finish setup y configure según su necesidad.
Descargue el cliente de Nextcloud desde nextcloud.com. Autentíquese indicando la dirección del servidor: sitio.ucr.ac.cr/nextcloud.