Servidor Docker con HTTPS y administración gráfica

De Apuntes
Saltar a: navegación, buscar

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.

Docker-stack.png

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

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.

Nextcloud-config.png


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.

Referencias

  1. https://hub.docker.com/