hits counter
Este sitio web utiliza cookies para obtener estadísticas de navegación. Si sigue adelante, consideraremos que acepta su uso. Acepto | Más información

Docker



Docker: instalación y uso

Docker es una herramienta de virtualización muy ligera que permite correr aplicaciones y servicios utilizando contenedores. La virtualización basada en contenedores tiene una gran ventaja con respecto a los sistemas tradicionales como VMWare o Virtualbox: en los contenedores no se crea un sistema huésped completo, sino que las aplicaciones se encapsulan en módulos que comparten el mismo kérnel del sistema anfitrión y se ejecutan como procesos aislados en el espacio de usuario. Esto supone un gran ahorro de recursos: memoria, espacio de disco y uso de CPU. El hecho de que sea tan ligera implica que no requiere de un hardware potente, lo que la hace muy adecuada para su uso en una placa como la Raspberry Pi. Los contenedores son, además, sistemas autocontenidos que ya disponen de todo lo necesario (código, librerías, dependencias y ficheros de configuración) para poder funcionar en cualquier equipo.

Los creadores de esta plataforma mantienen un repositorio público en la nube, llamado Docker Hub, que contiene una enorme cantidad de imágenes de muchas de las aplicaciones y servicios más utilizados por usuarios y empresas de todo el mundo, ordenadas por categorías, sistemas operativos y arquitecturas (entre las que se encuentra ARM). Cualquiera puede crearse una cuenta (gratuita o de pago) e incluir su propio repositorio particular, haciéndolo público o privado.


Instalar Docker

Lo primero que haremos será actualizar el sistema:

sudo apt update
sudo apt upgrade

A continuación ejecutamos el script que llevará a cabo la instalación:

sudo curl -sSL https://get.docker.com | sh

Creamos el grupo docker y añadimos al mismo el usuario actual mediante la variable $USER:

sudo usermod -aG docker $USER

No hace falta reiniciar el equipo; basta con cerrar la sesión:

logout

Una vez hecho login de nuevo, y con el fin de comprobar que Docker está funcionando correctamente, ejecutamos un primer contenedor hecho ex profeso para esta finalidad: uno muy básico que simplemente muestra el típico "Hello World". Para ello usaremos esta orden:

docker run hello-world

Como podemos ver, la imagen del contenedor se busca primero localmente, y si no se encuentra (como es el caso), se descarga del repositorio Docker Hub. Después se ejecuta el contenedor, que muestra el mensaje Hello from Docker!, y a continuación es cuando se nos indica que la instalación se ha realizado correctamente.

Con los siguientes comandos conoceremos la versión de Docker que tenemos instalada y también otra información extendida (su directorio raíz, kérnel, arquitectura de la CPU, sistema operativo,...), respectivamente:

docker -v
docker info

Instalar Docker Compose

Ahora vamos a instalar Docker Compose, que es una extensión que nos permite gestionar varios contenedores a la vez, además de poder configurar de una forma más sencilla cómo se comunican entre ellos.

La instalación es muy simple:

sudo apt install docker-compose

Podemos comprobar en cualquier momento la versión instalada con este comando:

docker-compose --version

Imágenes

Ya dijimos al principio que existe un gran repositorio donde se encuentran todas las imágenes disponibles para Docker, llamado Docker Hub. De aquí es de donde se descargan las imágenes que vamos a usar en nuestro sistema.

Podemos conocer la lista de comandos disponibles para trabajar con imágenes escribiendo esto:

docker image --help

Los más usados seguramente serán los siguientes:

docker image ls                                       Muestra la lista de imágenes
docker image rm nombre | ID                  Borra una imagen
docker image pull nombre                       Descarga una imagen del repositorio
docker image prune                                 Borra todas las imágenes

Los tres primeros comandos anteriores pueden abreviarse:

docker images
docker rmi nombre | ID
docker pull nombre

Hemos de tener en cuenta que no se puede borrar una imagen si ya existe un contenedor de la misma. Es necesario borrar previamente el contenedor, ya que este no es más que una imagen que se ha lanzado y se encuentra en ejecución.

Parar borrar una imagen podemos usar su nombre o bien su ID. En este último caso no es necesario teclearlo completo (sólo los primeros caracteres, siempre que no existan varios IDs que comiencen por los mismos caracteres). Así, si tenemos dos imágenes cuyos IDs son 6567cb064a414 y 639db11237ab2, respectivamente, para eliminar la primera basta con teclear docker rmi 65.


Contenedores

Como dijimos antes, un contenedor no es más que una imagen que se encuentra en ejecución realizando una tarea. Ello implica que para poder lanzar un contenedor, previamente ha de descargarse la imagen correspondiente: primero se comprueba si esta ya existe en la máquina local, y si no es así, se descarga automáticamente del repositorio.

Al igual que con las imágenes, podemos conocer la lista de comandos disponibles para trabajar con contenedores tecleando esto:

docker container --help

Los más usados en un principio son los siguientes:

docker run nombre                              Arranca un contenedor
docker run -d nombre                         Arranca un contenedor en segundo plano
docker run --name wp wordpress       Lo arranca asignándole un nombre (wp)
docker run -it ubuntu bash                  Arranca un nuevo contenedor y ejecuta comandos
docker exec -it nombre | ID bash        Ejecuta comandos en un contenedor ya arrancado
docker container rename nombre | ID nuevo_nombre               Renombra el contenedor
docker ps                                             Muestra la lista de los contenedores activos
docker ps -a                                        Muestra la lista de todos los contenedores
docker stop nombre | ID                      Detiene un contendor
docker start nombre | ID                      Inicia un contendor parado
docker restart nombre | ID                   Reinicia (stop/start) un contendor
docker rm nombre | ID                         Borra un contendor (debe estar parado)
docker pause nombre | ID                    Pausa un contendor
docker unpause nombre | ID                Reinicia un contendor pausado
docker container prune                        Borra todos los contenedores

Como en el caso de las imágenes, para referirse a un contenedor por su ID, no hace falta escribirlo entero (sólo el/los primer/os caracteres, siempre que no existan varios IDs que comiencen por los mismos).



Nginx Proxy Manager

Nginx Proxy Manager es un proxy inverso que se instala en Docker. Un proxy inverso es un servidor que se sitúa delante de uno o varios servidores web e intercepta las solicitudes de los clientes, enviándolas al servidor de destino o backend y recibiendo la respuesta de este. Se usa para proteger los servidores de destino y optimizar el tráfico de datos de las peticiones procedentes de Internet. Con un proxy inverso se consigue, entre otras cosas, el enmascaramiento del servidor final (ya que las peticiones de los clientes las recoge el proxy) o proporcionar una caché para almacenar y servir de forma rápida el contenido más demandado.

Sirve también para gestionar los servicios que estén detrás del proxy y darles cobertura HTTPS, es decir, nos permitirá tener certificados SSL en el servidor proxy para evitar tener que hacer esta configuración en cada uno de los servicios internos que queremos exponer. Nginx Proxy Manager usa internamente Let's Encrypt para solicitar, gestionar y renovar de forma automática los certificados SSL que se aplicarán en cada host.


Instalar el proxy

Antes de nada es necesaario instalar Docker en la Raspberry. La instalación estándar de Docker ya incluye el plugin para Docker Compose, que usaremos para configurar y ejecutar el contenedor.

Hecho esto, creamos un directorio en nuestro /home para Docker y un subdirectorio para el proxy que vamos a instalar, situándonos a continuación en el mismo:

mkdir -p docker/proxymanager
cd docker/proxymanager

Acto seguido creamos un fichero de Docker Compose que contendrá los datos del proxy:

nano docker-compose.yml

Dentro del mismo escribiremos un contenido lo más simplificado posible, de manera que, en lugar de usar un servidor de base de datos (como MaríaDB), usaremos SQLite, que no requiere servidor propio. No hay que olvidar que en los ficheros .yml es imprescindible respetar la indentación de las líneas:

version: '3.8'
services:
   app:
      image: 'jc21/nginx-proxy-manager:latest'
      restart: unless-stopped
      ports:
         - '80:80'
         - '81:81'
         - '443:443'
      volumes:
         - ./data:/data
         - ./letsencrypt:/etc/letsencrypt
         - /var/log:/data/logs

La última línea se ha remarcado en negrita porque es para indicar el path de los ficheros de log necesarios para incluir el proxy en Fail2ban. Si no vamos a usar este, prescindiremos de dicha línea. Los puertos 80 TCP y 443 TCP tendremos que abrirlos en el router y redireccionarlos a la IP local de la Raspberry. El puerto 81 es para acceder a la interfaz web del proxy.

Con el siguiente comando descargamos y ejecutamos el contenedor (puede tardar bastante en completar el proceso):

docker compose up -d

La interfaz web

Cuando termine, ya podemos entrar en la interfaz web del proxy inverso usando la IP de la Raspberry y el puerto 81:

http://192.168.1.33:81

Para el login inicial hay que utilizar un email (admin@example.com) y una contraseña (changeme) por defecto:

Inmediatamente después veremos esta ventana para introducir los datos del administrador. Debemos poner un nuevo email y pulsar en Save :

Se nos abrirá otra ventana para que cambiemos la contraseña que hemos usado antes por una nueva:

Entramos por fin en el proxy y en el Dashboard veremos esto:


Añadir hosts

Hacemos clic en Proxy Hosts (o en el menú Hosts - Proxy Host) y luego en Add Proxy Host. Aquí añadiremos nuestro primer host. Tenemos que configurar dos pestañas.

1.) Details. En la pestaña Details rellenamos los datos del mismo:

En este ejemplo hemos puesto un DDNS gratuito de Duck DNS. Debajo escribimos la IP local de la Raspberry que corre Nginx Proxy Manager, el puerto 8888 (que corresponde al servicio RPi-Monitor) y activamos Block Common Exploits. De esta forma, cuando alguien escriba la dirección nombre.duckdns.org, entrará en la interfaz web del RPi-Monitor de nuestra Raspberry y lo hará con HTTPS, gracias al certificado de Let's Encript que vamos a añadir en el siguiente punto.

En lugar de la Raspberry en la que corre el servidor proxy, podemos poner la IP de cualquier otra máquina de nuestra LAN que tenga un servicio al queramos dar acceso.

Hay que tener en cuenta que necesitaremos utilizar un dominio diferente para cada host, así que lo mejor es crear distintos subdominios en el DDNS, si lo permite. Y no debemos olvidar abrir en el router los puertos 80 y 443 TCP, redireccionándolos a la IP local de la Raspbery. En el cortafuegos (si lo tenemos instalado), por el contrario, abriremos sólo los puertos que usa cada host.

2.) SSL. En la pestaña SSL primero vamos a indicar que deseamos un nuevo certificado SSL (Request a new SSL Certificate), luego activamos Force SSL y también HTTP/2 Support, ponemos un email válido (esto es importante) y, justo debajo, aceptamos los términos del servicio de Let's Encript. Nginx Proxy Manager se encarga de la gestión de los certificados, creándolos en el mismso momento en que pulsamos el botón Save y procediendo luego a su renovación, de forma automática, antes de que caduquen.


Control de acceso a los hosts

Si algún servicio/host no tiene usuario y contraseña de acceso, podemos decirle al proxy que los solicite para poder entrar al mismo. Para ello, pinchamos en el menú Access Lists y luego en el botón Add Access List. En la pestaña Details le ponemos un nombre a esta regla de acceso y activamos Satisfy Any:

Después, en la pestaña Authorization, escribimos el usuario y la contraseña que queramos usar. Finalizamos pulsando en Save:

Para activarlo, editamos el host en el que queramos usar esta regla y, abajo, en Access List, seleccionamos la regla de acceso que acabamos de crear y guardamos la nueva configuración haciendo clic en Save:


Usando Fail2ban

Si tenemos instalado Fail2ban y queremos incluir Nginx Proxy Manager en él, además del cambio en el fichero docker-compose.yml que vimos al principio, tendremos que implementar nosotros mismos las reglas necesarias para poder usarlo. En Internet se pueden encontrar al menos un par de maneras de hacerlo: una primera (como se explica aquí) y luego una segunda, más simple y que parece funcionar mejor.

Este segundo método (extraído de aquí, pero con algunas modificaciones al final) consiste en crear un fichero de configuración específico para el servicio:

sudo nano /etc/fail2ban/filter.d/npm.conf

en el que incluiremos este contenido:

[INCLUDES]

[Definition]

failregex = ^.+ (405|404|403|401|\-) (405|404|403|401) - .+ \[Client <HOST>\] \[Length .+\] ".+" .+$

Luego editamos el fichero de configuración de Fail2ban:

sudo nano /etc/fail2ban/jail.local

y al final del mismo añadimos lo siguiente:

[npm]
enabled = true
datepattern = ^[^\[]*\[(%%d/%%b/%%Y:%%H:%%M:%%S(?: %%z)?)\]
port = https,http
bantime = 15m
findtime = 3m
maxretry = 5
chain = DOCKER-USER
logpath = /var/log/proxy-host-?_access.log

Ya sólo tenemos que reiniciar Fail2ban para que incluya el nuevo servicio que acabamos de configurar:

sudo service fail2ban restart



Servidor VPN WireGuard

Una VPN (Virtual Private Network, Red Privada Virtual) es un sistema que nos permitirá conectarnos a la Raspberry Pi desde cualquier lugar de Internet de una manera segura, mediante una conexión cifrada, y tener acceso a toda nuestra red local igual que si estuviéramos en casa. De hecho, una VPN es como una extensión de nuestra red local, pero realizada a través de una red pública (Internet en este caso). Una vez conectados desde el exterior al servidor VPN, nuestro dispositivo pasará a formar parte de la red doméstica y usará el router de nuestra casa para movernos por Internet, siendo por ello el encargado de asignarnos la IP pública correspondiente. Además, cuando nos conectamos a la VPN, todo el tráfico entre el cliente y el servidor (es decir, los datos generados por cualquier servicio o aplicación que usemos) viajarán con un cifrado de alta seguridad, por lo que nadie podrá ver su contenido aunque estemos usando una wifi pública y haya algún hácker espiando el tráfico de datos que circula por ella.

Vamos a instalar un servidor VPN del tipo WireGuard, ya que actualmente se ha convertido en el más usado debido a que es rápido y poco pesado; además es fácil de configurar y ofrece una seguridad igual o superior a OpenVPN, la otra alternativa disponible. Aunque, como decimos, no es difícil de instalar y configurar manualmente, resulta aún mucho más fácil hacerlo mediante Docker, y en especial si utilizamos la imagen de WireGuard Easy.


Requisitos previos

Antes de comenzar con la instalación, tenemos que asegurarnos de haber hecho estos cuatro pasos:

  1. 1.) Asignarle a la Raspberry Pi una IP estática, tal y como se detalla en este apartado de nuestra web.
  2. 2.) Crear un DNS dinámico o nombre de dominio virtual para poder acceder al servidor VPN desde Internet, algo que podemos hacer de la forma que explicamos en este otro apartado.
  3. 3.) Instalar Docker en la Raspberry. La instalación estándar del mismo ya incluye el plugin para Docker Compose, que usaremos para configurar y ejecutar el contenedor.
  4. 4.) Abrir el puerto 51820/udp en el router y redireccionarlo a la IP local de la Raspberry, y también en el cortafuegos ufw, si lo tenemos instalado (sudo ufw allow 51820/udp).

Instalación

Comenzaremos creando un subdirectorio para la configuración e instalación del servidor VPN y nos situaremos en él:

sudo mkdir -p /opt/stacks/wireguard
cd /opt/stacks/wireguard

A continuación creamos el fichero de Docker Compose que contendrá los datos del servicio:

sudo nano compose.yml

Dentro del mismo copiaremos el siguiente contenido, sin olvidar que en los ficheros .yml es imprescindible respetar la indentación de las líneas:

version: "3.8"
services:
   wg-easy:
      container_name: wg-easy
      image: ghcr.io/wg-easy/wg-easy
      environment:
         - PASSWORD=contraseña
         - WG_HOST=middns.no-ip.net
         - LANG=es
      volumes:
         - ./config:/etc/wireguard
         - /lib/modules:/lib/modules
      ports:
         - "51820:51820/udp"
         - "51821:51821/tcp"
      restart: unless-stopped
      cap_add:
         - NET_ADMIN
         - SYS_MODULE
      sysctls:
         - net.ipv4.ip_forward=1
         - net.ipv4.conf.all.src_valid_mark=1

En PASSWORD pondremos una contraseña para acceder a la interfaz web que veremos más adelante y en WG_HOST, el nombre del dominio DDNS que creamos en el segundo paso de los REQUISITOS PREVIOS.

Hecho lo anterior, ya solo nos queda ejecutar el siguiente comando con el que descargaremos la imagen y la pondremos en funcionamiento:

docker compose up -d

Interfaz web

Para gestionar los usuarios/clientes usaremos una interfaz web que nos hará muy fácil la tarea. Entramos en ella con la IP local de la Raspberry y el puerto 51821 que indicamos en el fichero anterior:

http://192.168.1.33:51821

Para el login inicial hay que utilizar la contraseña que también pusimos en el fichero .yml que creamos antes:

Después podremos añadir un nuevo cliente:

Le damos un nombre:

que nos aparecerá en la siguiente ventana. En ella podremos activar/desactivar el cliente, escanear un código QR para para importarlo a un dispositivo móvil, descargarlo en un fichero (para pasarlo a un PC o un portátil) y eliminarlo:


Instalar los clientes e importar los usuarios

Necesitamos instalar las aplicaciones clientes en todos aquellos dispositivos (PCs, portátiles, smartphones o tabletas digitales) desde los que queramos acceder al servidor. Para el sistema Android podemos usar varias apps, como por ejemplo la oficial o bien esta otra. Para iOS también está disponible la app oficial. Y en el caso de macOS y Windows, podremos descargar los clientes desde la web de WireGuard. Además, disponemos de información sobre cómo instalar y configurar los clientes para los distintos sistemas operativos en este sitio.

Como hemos visto en la última captura correspondiente a la interfaz web, la foma más cómoda de importar los usuarios a un dispositivo móvil es mediante un código QR que luego se puede escanear desde la app móvil (tanto en Android como en iOS), de manera que la importación de los datos de conexión es un proceso completamente automático.

En el caso de hacerlo desde un PC o un portátil, sólo tenemos que descargar el fichero desde la interfaz web y luego importarlo desde el cliente que hemos instalado previamente.


Actualizar el contenedor

Cuando haya una nueva versión del contenedor WireGuard Easy en su GitHub, podremos actualizar fácilmente siguiendo estos tres sencillos pasos:

Nos situamos en el subdirectorio donde creamos el fichero de Docker Compose:

cd /opt/stacks/wireguard

Descargamos la nueva versión:

docker compose pull

Y reinstalamos el contenedor:

docker compose up -d

WireGuard + Pi-hole

Pi-hole también puede, naturalmente, instalarse mediante Docker, como se muestra en su repositorio oficial de Docker Hub. Pero si deseamos que ambos servicios trabajen juntos, podemos hacerlo como se indica en el propio GitHub de WireGuard Easy.




CasaOS Home Server

CasaOS es un proyecto para crear un Home Server basado completamente en Docker. Funciona a través de una interfaz web con un aspecto simple, limpio y elegante desde la que pueden realizarse todas la tareas de instalación y gestión de contenedores. Posee una tienda de aplicaciones a la que se pueden añadir otras nuevas y si algún contenedor no se encuentra en ninguna de ellas, se puede instalar desde cualquier repositorio, como Docker Hub.


Instalación

CasaOS está disponible para distintas distribuciones de Linux, incluyendo Raspberry Pi OS, como se indica en su GitHub. La instalación es sumamente sencilla; tan sólo tenemos que ejecutar este script:

curl -fsSL https://get.casaos.io | sudo bash

El proceso de instalación incluye Docker, Docker Compose y todo lo necesario para el posterior uso y gestión de contenedores. Al final se nos indicará la IP local desde la que podemos entrar en su interfaz web y también la manera de desinstalarlo, en caso de que no sea de nuestro agrado:

casaos-uninstall

Copiamos la IP indicada (que es la de la propia Raspberry) en el navegador de cualquier dispositivo de nuestra LAN y lo primero que se nos pedirá es que creemos una cuenta escribiendo un nombre de usuario y su contraseña:

Hecho lo anterior, entraremos en la interfaz web de CasaOS:



Cuando aparezca una nueva versión del sistema, podremos actualizar haciendo una pequeña modificación en el script de instalación; simplemente añadiremos /update/vX.X.X al final de la URL, donde las X representan el número de la nueva versión. Por ejemplo:

curl -fsSL https://get.casaos.io/update/v0.4.8 | sudo bash


Configuración

Arriba, a la izquierda, tenemos varios iconos. El primero es para cerrar la sesión. El segundo nos permite realizar determinados ajustes en el sistema:

Y mediante el tercero podremos iniciar una sesión de SSH en la Raspberry, escribiendo nuestras credenciales, sin necesidad de salir de CasaOS:

Además, en la parte inferior de la primera columna, en Ajustes de Widget >, podremos hacer que se muestren o no los distintos widgets que aparecen en dicha columna.


Aplicaciones

Haciendo clic en el icono de la App Store entraremos en la tienda de aplicaciones, desde donde podremos instalar una buena cantidad de apps. Podemos aumentar fácilmente su número yendo al listado de tiendas de su GitHub. En el enlace GitHub Repo de cada una se puede ver la lista de aplicaciones que contiene:

Si nos interesa el contenido, copiamos la URL que incluye el fichero ZIP de la tienda (el Source link que se muestra en la imagen anterior); entramos en la App Store de CasaOS y la pegamoso en Añadir fuente:

Si aun así necesitamos una aplicación que no se encuentra en ninguna de esas fuentes (o una versión más actualizada), podemos pinchar arriba, en Instalación personalizada, e instalar una imagen Docker o importarla (haciendo clic en el icono de la parte superior) como Docker Compose o como Docker CLI:


Por último, añadir que los contenedores con las distintas aplicaciones que instalemos se situarán en la ruta /DATA/AppData.