Este artículo explica cómo instalar Docker Engine en un contenedor Linux (LXC), basado en TurnKey Core 18.1 (Debian 12), desplegado en el servidor Proxmox VE que instalé hace unos meses.
Nota: El soporte oficial de Proxmox recomienda ejecutar Docker en máquinas virtuales, pero un contenedor Linux (LXC) permite hacerlo con menos recursos del hipervisor y con velocidades de arranque mucho más rápidas.
Actualizar Proxmox
Antes de empezar, nos aseguraremos que Proxmox esté correctamente actualizado. Se puede comprobar la versión actual mediante el comando pveversion
:
root@pve:~# pveversion
pve-manager/8.3.2/3e76eec21c4a14a7 (running kernel: 6.8.12-6-pve)
A continuación se procede a actualizar el servidor usando los comandos propios de Proxmox:
# Actualizar repositorios
pveupdate
# Actualizar paquetes de Proxmox
pveupgrade
Si al ejecutar pveupgrade
aparece un mensaje indicando que “los paquetes de GRUB no pueden actualizar el bootloader en /boot/efi/EFI/BOOT/BOOTX64.efi
” únicamente hay que cambiar la configuración de grub-efi-amd64
y volver a reinstalarlo.
A continuación se reinicia el servidor para aplicar los cambios (sobretodo si ha habido alguna actualización del kernel):
# Reiniciar para aplicar cambios
reboot -h now
Si todo funciona correctamente, el servidor debería reiniciar con la nueva versión del kernel y de la interfaz web:
root@pve:~# pveversion
pve-manager/8.3.4/65224a0f9cd294a3 (running kernel: 6.8.12-8-pve)
Descargar plantilla de TurnKey Core
Antes de poder crear un contenedor Linux (LXC) es necesario descargar la plantilla del SO que ejecutaremos en él. En este caso se utilizará TurnKey Core, una pequeña distribución basada en Debian GNU/Linux.
Se pueden actualizar y descargar plantillas LXC usando el comando pveam
tal como se muestra a continuación:
pveam update
pveam available --section turnkeylinux | grep -i "core"
pveam download local debian-12-turnkey-core_18.1-1_amd64.tar.gz
TurnKey Core 18.1 está basada en Debian 12 y fue publicada el 29 de julio de 2024 según indican sus manifest & signs.
Contenedor Linux (CT)
Instalación
A continuación se puede crear el contenedor Linux (CT en terminología Proxmox) usando la interfaz gráfica o, mejor aún, desde el CLI de Proxmox usando el comando pct create
.
root@pve:~# ./create_ct.sh
Introduce el CT ID: 701
Introduce el nombre del contenedor: dockerlxc
Privilegiado (yes/no) [no]:
¿Utilizarás Docker? (yes/no) [no]: yes
Introduce el password del usuario 'root':
Confirma el password del usuario 'root':
Introduce el tamaño del disco (GB) [8]: 10
Introduce la memoria RAM (MB) [512]: 1024
Introduce el número de cores [1]: 1
Introduce la dirección IP (192.168.1.x): 192.168.1.99
Introduce los servidores DNS (separados por espacios) [192.168.1.81 192.168.1.82]:
¿Quieres montar /datos/samba/media en el CT? (yes/no) [no]:
¿Quieres montar /backups/rsync en el CT? (yes/no) [no]:
Resumen de datos:
CT ID: 701
Nombre del contenedor: dockerlxc
Privilegiado: no
Utilizará Docker: yes
Password: [oculto]
Tamaño del disco: 10GB
Memoria RAM: 1024MB
Cores: 1
IP: 192.168.1.99
Servidores DNS: 192.168.1.81 192.168.1.82
Montar /datos/samba/media: no
Montar /backups/rsync: yes
Memoria SWAP: 512MB
Gateway: 192.168.1.1
¿Son correctos estos datos? (yes/no) [no]: yes
Ejecución
El contenedor se configura para que se ponga en marcha automáticamente al iniciarse el servidor Proxmox y se pone en marcha a continuación:
pct set 701 --onboot 1
pct start 701
Una vez puesto en marcha, se puede entrar en su shell para ver el proceso de instalacón:
- Expandir el centro de datos (Datacenter)
- Expandir el servidor (node):
pve
- Seleccionar el contenedor (container):
701 (dockerlxc)
- Pulsar el botón Console para ver la instalación
Una vez iniciado el contenedor Linux, se puede iniciar sesión:
- dockers login:
root
- Password:
********
Cuando aparezca el asistente de instalación TurnKey GNU/Linux - First boot configuration:
- Pulsar el botón Skip en la pantalla Initialize Hub Services
- Pulsar el botón Skip en la pantalla System Notifications and Critical Security Alerts
- Pulsar el botón Install en la pantalla Security updates
Si aparece el mensaje A security update to the kernel requires a reboot to go into effect
se reiniciará el LXC despues de salir del asistente.
Al finalizar la instalación de las actualizaciones de seguridad, en la TurnKey GNU/Linux Configuration Console se mostrarán las URLs de servicio, por ejemplo:
Webmin: https://192.168.1.99:12321
SSH/SFTP: root@192.168.1.99 (port 22)
En esta pantalla hay que:
- Pulsar el botón Advanced Menu
- Seleccionar la opción Quit para salir de la consola de configuración
- Pulsar el botón Yes para confirmar
Actualización
Nota: Aunque no es estrictamente necesario, se recomienda cambiar la zona horaria antes de seguir. Para ello se puede utilizar el comando dpkg-reconfigure tzdata
y seleccionar Europe/Madrid
.
Se actualizan los repositorios y los paquetes de la distribución Debian usando los siguientes comandos:
apt update
apt upgrade -y
Durante la instalación pueden aparecer pantallas relacionadas con postfix
y openssh-server
:
- En la pantalla Postfix Configuration, seleccionar la opción No configuration y pulsar el botón OK
- En la pantalla Configuring openssh-server, seleccionar la opción Keep the local version currently installed para conservar el fichero
sshd_config
y pulsar el botón OK
Nota: En este momento es recomendable reiniciar el LXC usando el comando reboot
(sobretodo si se han actualizado paquetes críticos o el kernel).
Docker Engine
Instalación
La instalación de Docker Engine se realiza desde el repositorio apt
oficial ejecutando los siguientes comandos:
# Add Docker's official GPG key:
apt update
apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
# Install latest Docker packages
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Comprobar servicio docker.service
Para comprobar que Docker se ha instalado correctamente en el LXC, se puede ejecutar el comando systemctl status docker
que muestra información acerca del servicio:
root@dockerlxc ~# systemctl status docker
* docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
Active: active (running) since Wed 2025-03-12 19:07:06 CET; 26s ago
TriggeredBy: * docker.socket
Docs: https://docs.docker.com
Main PID: 40454 (dockerd)
Tasks: 7
Memory: 20.6M
CPU: 208ms
CGroup: /system.slice/docker.service
`-40454 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Ejecutar aplicación hello-world
Para comprobar que todo funciona correctamente, se puede ejecutar el comando docker run hello-world
:
root@dockerlxc ~# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
e6590344b1a5: Pull complete
Digest: sha256:bfbb0cc14f13f9ed1ae86abc2b9f11181dc50d779807ed3a3c5e55a6936dbdd5
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
Seguridad (opcional)
A continuación se detallan algunos pasos que, aunque no son estrictamente necesarios, aumentan la seguridad del entorno:
- Creación de un usuario normal para ejecutar los contenedores Docker
- Creación de un directorio protegido para hacer copias de seguridad de los datos de los contenedores Docker
Crear un usuario normal
En mi caso, el usuario normal se llamará manel
y se creará de la siguiente manera:
useradd -m -u 1000 -U -G docker -s /bin/bash manel
cat /etc/passwd | grep -i manel
cat /etc/group | grep -i manel
passwd manel
Crear un grupo rsync
El contenedor LXC tiene montado en el directorio /mnt/rsync
el directorio /backups/rsync
de Proxmox que está ubicado en un disco diferente al utilizado para los contenedores y las máquinas virtuales.
La idea es crear un directorio específico para esta máquina en /mnt/rsync/dockerlxc
, protegido para el grupo rsync
del cual será miembro el usuario manel
creado anteriormente.
El grupo rsync
tendrá un GID relacionado con el identificador del CT mediante la siguiente fórmula: 1000 + CT ID
para evitar solapamientos entre diferentes LXC.
# 1000 + 701 = 1701
groupadd -g 1701 rsync
mkdir /mnt/rsync/dockerlxc
chown root:1701 /mnt/rsync/dockerlxc
chmod 770 /mnt/rsync/dockerlxc
usermod -aG rsync manel
cat /etc/group | grep -i manel
Instalación y configuración de sudo
El usuario manel
podrá ejecutar contenedores Docker por ser miembro del grupo docker
. Aunque este usuario puede ejecutar el comando rysnc
, a la hora de copiar ficheros de los contenedores Docker creados por root
tendrá problemas de acceso.
Para solucionarlo, hay que instalar el paquete sudo
y configurarlo para el usuario manel
pueda ejecutar sudo rsync
y copiar así cualquier ficheros protegido.
- Instalar el paquete:
apt install sudo -y
- Añadir la siguiente línea al fichero
/etc/sudoers
manel ALL=(ALL) NOPASSWD: /usr/bin/rsync
Iniciar sesión con el usuario normal
A continuación se inicia sesión con el usuario manel
para instalar un par de contenedores Docker que pueden ser de utilidad en el futuro: Portainer y Nginx Proxy Manager.
Se puede iniciar sesión mediante SSH o usar el comando su - manel
para convertirnos en el usuario normal mediante el cual se ejecutarán los contenedores Docker en esta máquina.
Instalar Nginx Proxy Manager (opcional)
Instalar Nginx Proxy Manager es una opción muy recomendable para exponer los servicios de forma fácil y segura mediante certificados SSL emitidos por Let’s Encrypt.
Como ya expliqué la instalación de Nginx Proxy Manager en Docker de forma detallada, aquí únicamente indicaré los comandos para hacerlo rápidamente:
- Crear el directorio para Nginx Proxy Manager:
mkdir -p ~/dockers/nginx-proxy-manager
- Crear el directorio para el volumen de datos de NPM:
mkdir -p ~/dockers/nginx-proxy-manager/nginx-proxy-manager_data
- Crear el directorio para el volumen de datos de Let’s Encrypt:
mkdir -p ~/dockers/nginx-proxy-manager/nginx-proxy-manager_letsencrypt
- Crear el fichero
docker-compose.yml
en el directorio~/dockers/nginx-proxy-manager
con el siguiente contenido:
services:
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:2.12.3
container_name: nginx-proxy-manager
environment:
TZ: 'Europe/Madrid'
DISABLE_IPV6: 'true'
volumes:
- /etc/localtime:/etc/localtime:ro
- ./nginx-proxy-manager_data:/data
- ./nginx-proxy-manager_letsencrypt:/etc/letsencrypt
ports:
- 80:80 # Public HTTP Port
- 443:443 # Public HTTPS Port
- 81:81 # Admin Web Port
restart: unless-stopped
networks:
default:
external: true
name: nginx
A continuación, se crea una red específica para ejecutar todos los contenedores Docker de esta máquina:
docker network create nginx
Y, finalmente, se pone en marcha el contenedor Docker:
docker compose up -d
Es necesario cambiar el usuario (admin@example.com
) y la contraseña por defecto (changeme
) accediendo al puerto 81 del contenedor LXC: http://192.168.1.99:81/.
Instalar Portainer CE (opcional)
Instalar Portainer Community Edition (CE) es una opción muy recomendable para poder administrar los contenedores Docker de una forma más sencilla.
Como ya expliqué la instalación de Portainer CE en Docker de forma detallada, aquí únicamente indicaré los comandos para hacerlo rápidamente:
- Crear el directorio para Portainer:
mkdir -p ~/dockers/portainer-ce
- Crear el directorio para el volumen de datos:
mkdir -p ~/dockers/portainer-ce/portainer-ce_data
- Crear el fichero
docker-compose.yml
en el directorio~/dockers/portainer-ce
con el siguiente contenido:
services:
portainer-ce:
image: portainer/portainer-ce:2.27.1
container_name: portainer-ce
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock
- ./portainer-ce_data:/data
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
default:
external: true
name: nginx
A continuación, se pone en marcha el contenedor Docker:
docker compose up -d
Configuración del proxy host
Para poder acceder al contenedor Docker de Portainer CE es necesario añadir un proxy host en Nginx Proxy Manager:
- Acceder a Hosts → Proxy Hosts
- Pulsar el botón
Add Proxy Host
- Configurar un nuevo proxy host:
- Details
- Domain Names:
portainer.mydomain.com
(será necesario añadirlo a nuestro DNS) - Scheme:
https
- Forward Hostname:
portainer-ce
(el nombre del Docker) - Forward Port:
9443
- Block Common Exploits: Habilitado
- Domain Names:
- SSL
- Request a new SSL certificate
- Force SSL: Habilitado
- HTTP/2 Support: Habilitado
- HSTS Enabled: Habilitado
- USE a DNS Challenge: Habilitado
- DNS Provider: Cloudflare
- Credentials File Content:
dns_cloudflare_api_token = xxxxxxxxxxxxxxxxxxxx
- Email Address for Let’s Encrypt:
nginx@mydomain.com
- I Agree to the Let’s Encrypt Terms of Service
- Pulsar el botón
Save
- Details
Si todo funciona correctamente, se creará un certificado SSL mediante certbot
y se asignará al proxy host portainer.mydomain.com
. El comando ejecutado por Nginx Proxy Manager es el siguiente:
certbot certonly \
--config '/etc/letsencrypt.ini' --work-dir "/tmp/letsencrypt-lib" --logs-dir "/tmp/letsencrypt-log" \
--cert-name 'npm-1' --agree-tos --email 'nginx@mydomain.com' \
--domains 'portainer.mydomain.com' \
--authenticator 'dns-cloudflare' --dns-cloudflare-credentials '/etc/letsencrypt/credentials/credentials-1
Para poder crear el certificado SSL, es necesario que en el panel de configurción DNS de Cloudflare se haya definido una entrada de tipo A
para portainer.mydomain.com
que apunte a la dirección IP del contenedor LXC (en este caso, 192.168.1.99
).
Si todo es correcto, se podrá acceder a https://portainer.mydomain.com/ donde aparecerá la pantalla para crear el usuario administrador inicial y su contraseña antes de poder comenzar a utilizar el entorno.
Backups mediante rsync
Finalmente, se crea el fichero ~/dockers/backup_dockers.sh
y se programa su ejecución mediante cron a la hora que se crea conveniente:
# m h dom mon dow command
30 2 * * * /home/manel/dockers/backup_dockers.sh
Historial de cambios
- 2025-03-111: Documento inicial