Docker-Controller-Bot

Docker-Controller-Bot

Docker app from dgongut's Repository

Overview

Bot de Telegram: Lleva el control de tus contenedores docker desde un único lugar.

Docker-Controller-Bot

Docker Pulls Docker Stars Docker Image Size Github stars Github forks Github last-commit Github last-commit

ReadMe en Español | ReadMe in English | Canal de Noticias en Telegram

Lleva el control de tus contenedores Docker desde un único lugar: tu Telegram.

Docker-Controller-Bot

¿Lo buscas en ?

NUEVO Canal de novedades en

🚀 Empieza en 5 minutos

Solo hay dos pasos: crear tu bot y arrancarlo. Todo lo demás se configura después desde el propio chat.

1. Crea tu bot en Telegram (2 min)

  1. Abre @BotFather en Telegram y envía /newbot. Sigue las instrucciones (un nombre y un username acabado en bot).
  2. BotFather te devolverá el token del bot. Guárdalo: irá en la variable TELEGRAM_TOKEN.
  3. Para conocer tu propio chat ID (lo necesitas para TELEGRAM_ADMIN), habla con @MissRose_bot y envíale /id. Te responderá con un número, ese es tu ID.
  4. (Opcional) Si vas a usar el bot dentro de un grupo, añádelo, hazlo administrador y obtén el chat ID del grupo de la misma forma; ese valor irá en TELEGRAM_GROUP.
  5. (Opcional) Si quieres ponerle el icono oficial al bot, descarga la imagen en alta resolución aquí y envíasela a @BotFather usando la opción /setuserpic.

2. Arranca el contenedor (2 min)

Copia este docker-compose.yml, rellena las 3 variables y levántalo:

services:
    docker-controller-bot:
        environment:
            - TELEGRAM_TOKEN=
            - TELEGRAM_ADMIN=
            - TZ=Europe/Madrid
            #- TELEGRAM_GROUP=
            #- TELEGRAM_THREAD=1
            #- TELEMETRY=false # Descomenta para desactivar las estadísticas anónimas
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock # NO CAMBIAR
            - /ruta/para/guardar/la/configuracion:/app/config # CAMBIAR LA PARTE IZQUIERDA
            #- ~/.ssh:/root/.ssh:ro # Solo si vas a usar hosts remotos por ssh://
            #- ~/.docker/config.json:/root/.docker/config.json # Solo si se requiere iniciar sesión en algún registro
        image: dgongut/docker-controller-bot:latest
        container_name: docker-controller-bot
        restart: always
        network_mode: host
docker compose up -d

Abre Telegram, busca tu bot y envíale /start. Verás el menú principal con botones. Ya está: /list te muestra tus contenedores.

[!WARNING] Es obligatorio mapear un volumen en /app/config: ahí se guardan los ajustes, las programaciones y la caché de actualizaciones. Sin ese volumen lo pierdes todo al recrear el contenedor.

[!NOTE] El bot envía una vez al día unas estadísticas anónimas de uso. Son opcionales: descomenta TELEMETRY=false en el compose, o desactívalas desde /settings → Estadísticas anónimas en los 10 minutos que el bot espera antes del primer envío.

🔄 ¿Vienes de la 4.x? No tienes que cambiar nada
  • Si tu docker-compose mapea /app/schedule (la ruta que se usaba hasta la 4.x) el bot lo detecta y sigue usándolo, así que actualizar no requiere cambiar nada y no perderás ni un ajuste.

  • Cuando quieras pasarlo a /app/config, es cambiar una letra de la línea del volumen:

    -  - /tu/ruta:/app/schedule
    +  - /tu/ruta:/app/config
    

    La misma parte izquierda, y no se mueve ningún fichero: los ficheros ya están en tu volumen y se llaman igual. Después, docker compose up -d para recrear el contenedor. Mientras no lo hagas, el bot te lo recuerda en su mensaje de arranque.

  • tty: true ya no hace falta. Hasta la 4.x el compose lo llevaba para que los logs del bot salieran en docker logs; desde la 5.0 la imagen los escribe al momento sin él. Puedes quitarlo, o dejarlo: no molesta.

  • CONTAINER_NAME ya no hace falta. Hasta la 4.x había que decirle al bot cómo se llamaba su propio contenedor, para que supiera no pararse ni eliminarse a sí mismo. Ahora lo averigua solo: lee su id en /proc/self/mountinfo y le pregunta a Docker cuál es. Si la tienes puesta el bot arranca igual y te avisa en el log de que puedes quitarla.

  • En el primer arranque el bot importa los valores de tus variables de entorno a settings.json y los conserva tal cual. A partir de ahí manda settings.json, y esas variables ya no se leen; el log te avisa de las que puedes borrar del docker-compose.

🔐 ¿Necesitas docker login (DockerHub, GHCR, registro privado)?

Si se requiere tener la sesión iniciada en algún registro, traslada ese login al contenedor mapeando tu ~/.docker/config.json a /root/.docker/config.json:

volumes:
    - ~/.docker/config.json:/root/.docker/config.json

✨ ¿Qué puede hacer?

  • 📦 Contenedores: listar, arrancar, parar, reiniciar y eliminar. Con selección múltiple en /run, /stop y /restart.
  • 🧩 Compose: detecta tus proyectos y los agrupa (proyecto → contenedores).
  • 📊 Diagnóstico: logs en el chat o como fichero, exec dentro del contenedor, puertos e info detallada.
  • 🔄 Actualizaciones: te avisa si hay imagen nueva, actualiza uno o todos, cambia de tag (rollback) y auto-actualiza con labels.
  • ⏰ Automatización: tareas programadas con cron + silencio temporal con /mute + limpieza con /prune.
  • 🖥️ Multi-host y ajustes: varios servidores desde un solo bot y todo configurable con /settings, sin reiniciar.
📋 Ver lista completa de funciones
  • ✅ Listar contenedores
  • ✅ Arrancar, parar y eliminar contenedores
  • ✅ Selección múltiple en /run, /stop y /restart: el menú se queda abierto y se va actualizando para encadenar varios contenedores
  • ✅ Soporte para proyectos Docker Compose con navegación jerárquica (proyecto → contenedores)
  • ✅ Obtener los logs tanto de manera directa como a través de fichero
  • ✅ Extraer el docker-compose de tus contenedores
  • ✅ Notificaciones cuando un contenedor se cae o se inicia
  • ✅ Notificaciones cuando un contenedor tiene una actualización pendiente
  • ✅ Actualizaciones de los contenedores
  • ✅ Cambiar el tag (rollback o actualización)
  • ✅ Limpia el sistema, eliminando contenedores, imágenes y otros objetos no utilizados
  • ✅ Ejecuta comandos dentro de contenedores
  • ✅ Visualiza puertos usados por contenedores, comprueba si un puerto concreto está libre y genera puertos aleatorios disponibles
  • ✅ Muestra información detallada de un contenedor o de un proyecto Compose completo
  • ✅ Programación de tareas con expresiones cron: run, stop, restart, exec, prune y mute
  • ✅ Varios hosts Docker desde un solo bot, por ssh://, tcp:// o TLS: se añaden desde el propio chat, y con un único host todo se ve exactamente igual que siempre
  • ✅ Se identifica a sí mismo sin ayuda: no hay que decirle cómo se llama su contenedor para que sepa no pararse ni eliminarse
  • ✅ Ajustes editables desde el propio bot con /settings, sin tocar el docker-compose ni reiniciar
  • ✅ Menú principal por botones en /start, agrupado en categorías; los comandos escritos siguen funcionando igual
  • ✅ Silencia las notificaciones de forma temporal
  • ✅ Imagen multiarquitectura (amd64, arm64, armv7…) compatible con Raspberry Pi, NAS y servidores estándar
  • ✅ Soporte de idiomas (Spanish, English, Dutch, German, Russian, Galician, Italian, Catalan)

📋 Comandos

Casi todos funcionan de dos formas: escribe el comando solo (/run) y el bot te muestra un menú con botones, o pásale el nombre directamente (/run nginx) para actuar sin menús.

/start abre el menú principal, con todo agrupado por categorías (Contenedores, Diagnóstico, Actualizaciones, Sistema, Automatización, Ajustes y Acerca de). Pulsar un botón hace exactamente lo mismo que escribir el comando a secas.

Comando Descripción
/start Menú principal con botones, agrupados por tipo de acción
/list Listado completo de contenedores, agrupados por host si tienes varios
/run /stop /restart Arranca / detiene / reinicia un contenedor o un proyecto Compose entero
/delete Elimina un contenedor o un proyecto Compose entero
/exec Ejecuta un comando dentro de un contenedor
/logs /logfile Logs en mensaje o como fichero
/checkupdate Comprueba si un contenedor tiene actualización
/updateall Actualiza todos los contenedores, de todos los hosts a la vez
/changetag Cambia el tag de la imagen (rollback o salto de versión)
/compose Extrae el docker-compose de un contenedor o proyecto
/info Muestra información detallada de un contenedor o de un proyecto
/ports Lista puertos usados, comprueba uno concreto o genera uno libre
/prune Limpia contenedores, imágenes, redes o volúmenes no usados
/mute <minutos> Silencia las notificaciones durante X minutos
/schedule Menú para crear, editar y borrar tareas programadas
/settings Ajustes del bot: idioma, columnas, comprobación de actualizaciones, canal de notificaciones y hosts de Docker
/version /donate /donors Versión actual / donar / lista de donantes
🧩 Mis contenedores son de docker compose, ¿cómo se ven?

Si tus contenedores fueron creados con docker compose, el bot los reconoce automáticamente como un proyecto y los presenta agrupados.

En comandos como /run, /stop, /restart, /delete, /info o /compose verás primero la lista de proyectos y, al pulsar uno, sus contenedores. En /run y /stop solo se ofrecen los servicios sobre los que la acción tiene sentido (parados y arrancados respectivamente), igual que ya indicaba el contador del botón del proyecto. Las acciones de inicio, parada, reinicio y borrado se pueden aplicar al proyecto entero o a un contenedor individual.

⏰ Automatizar tareas con /schedule

Desde /schedule puedes crear tareas que se ejecuten en cron.

  • Acciones soportadas: run, stop, restart, exec, prune y mute.
  • Acepta expresiones cron estándar (0 */4 * * *) y atajos: @yearly, @monthly, @weekly, @daily, @hourly y @reboot.
  • Si tienes varios hosts, el bot te pregunta en cuál se ejecuta la tarea, y el host aparece en el resumen y en el listado. mute es la excepción: silencia las notificaciones del propio bot, así que no pertenece a ninguna máquina.
  • Las programaciones se persisten en /app/config (recuerda mapear ese volumen).
⚙️ Configuración avanzada y /settings

Aquí solo quedan las variables que el bot necesita antes de poder leer sus propios ajustes: cómo llegar a Telegram y quién puede hablarle. La regla es sencilla: si ponerla mal te puede dejar sin acceso al bot, va en el docker-compose, porque lo que impide que el chat funcione no se puede arreglar desde el chat.

CLAVE OBLIGATORIO VALOR
TELEGRAM_TOKEN ✅ Token del bot
TELEGRAM_ADMIN ✅ ChatId del administrador (se puede obtener hablándole al bot Rose escribiendo /id). Admite múltiples administradores separados por comas. Por ejemplo 12345,54431,55944
TELEGRAM_GROUP ❌ ChatId del grupo. Si este bot va a formar parte de un grupo, es necesario especificar el chatId de dicho grupo. Es necesario que el bot sea administrador del grupo
TELEGRAM_THREAD ❌ Thread del tema dentro de un supergrupo; valor numérico (2,3,4..). Por defecto 1. Se utiliza en conjunción con la variable TELEGRAM_GROUP
TZ ✅ Timezone (Por ejemplo Europe/Madrid)
TELEMETRY ❌ false para desactivar las estadísticas anónimas sin pasar por /settings. Lo normal es desactivarlas desde /settings; esto es para quien prefiera dejarlo fijado en el compose

Todo lo demás se configura desde el propio bot y se guarda en settings.json, dentro del volumen mapeado:

AJUSTE VALOR
Idioma ES / EN / NL / DE / RU / GL / IT / CAT. Por defecto ES
Columnas de botones Número de columnas en las listas de contenedores. Por defecto 2
Mensajes ampliados Muestra más mensajes de información. Por defecto desactivado
Selección múltiple En /run, /stop y /restart el menú se queda abierto para actuar sobre varios contenedores seguidos. Por defecto activado
Comprobar actualizaciones Por defecto activado
Intervalo de comprobación Horas entre comprobaciones. Acepta decimales. Por defecto 4
Contenedores parados Si comprueba también las actualizaciones de los contenedores detenidos. Por defecto activado
Canal de notificaciones Canal donde se publicarán exclusivamente los cambios de estado de los contenedores (arranque, parada, creación y actualizaciones automáticas). La gestión se sigue haciendo desde el chat privado con el bot o desde TELEGRAM_GROUP. El bot comprueba que puede publicar ahí antes de guardarlo
Hosts de Docker Las máquinas que gestiona el bot. Se añaden, se prueban, se renombran y se quitan desde aquí. Ver desplegable de hosts remotos
Estadísticas anónimas Una vez al día envía cifras anónimas de uso. Por defecto activado. Ver Estadísticas anónimas

Los cambios hechos desde /settings se aplican al momento, sin reiniciar el contenedor.

🖥️ ¿Tienes más de un servidor? Gestiona varios hosts Docker

A partir de la 5.0.0 el bot puede gestionar varios hosts Docker. Se definen en los ajustes, no en variables de entorno, así que se añaden desde el propio bot sin tocar el docker-compose.

Con un solo host —el caso normal— nada de esto aparece: el bot se ve exactamente igual que en la 4.x.

Cómo conectar con un host remoto

Hay dos formas, y para la mayoría de la gente la primera es la respuesta:

Forma Qué necesita Cuándo
ssh://usuario@maquina Nada en el host remoto salvo su sshd de siempre La recomendada. Si ya entras por ssh a esa máquina, ya está medio hecho
tcp://maquina:2375 Un socket proxy en la máquina remota Si tus máquinas ya están en una red privada (Tailscale, WireGuard, una VLAN aislada)

⚠️ Aviso: tcp:// sin TLS no tiene autenticación de ningún tipo: cualquiera que alcance ese puerto controla el Docker de esa máquina por completo, con permisos equivalentes a root. Solo dentro de una red en la que confíes, nunca expuesto a internet.

ℹ️ Nota: Docker también admite tcp:// cifrado con TLS. Es bastante más trabajo y con ssh:// disponible no le veo la necesidad, pero si tu caso lo pide está explicado en la FAQ, en «Quiero usar tcp:// pero cifrado con TLS».

La prueba que lo decide

Antes de configurar nada en el bot, comprueba desde una terminal de la máquina donde corre el bot:

ssh usuario@maquina docker version

Si eso te devuelve las versiones de cliente y servidor, ssh://usuario@maquina va a funcionar. Si falla, el mensaje te dice exactamente qué arreglar y no hace falta tocar el bot para nada.

El motivo es que el bot no habla un protocolo propio: abre una sesión ssh y ejecuta docker system dial-stdio en la máquina remota. Así que lo único que hace falta allí es que el usuario tenga el binario docker en su PATH y permiso sobre el socket.

Lo que ves Qué falta
Permission denied (publickey) La clave no está autorizada. Repite el ssh-copy-id
command not found: docker El docker no está en el PATH de ese usuario
permission denied ... /var/run/docker.sock El usuario no está en el grupo docker
Host key verification failed Falta la máquina en known_hosts
🔑 Paso a paso con ssh:// (recomendado)

❗ Importante — una sola clave vale para todos tus servidores. No generes una por máquina: creas la clave una vez y la autorizas en cada máquina que quieras añadir. Abajo cada paso lleva marcado si es una vez o por cada máquina, para que no lo repitas de más.

1. Habilita SSH en la máquina remota. (por cada máquina) En un Linux normal ya está. En un NAS suele ser un interruptor en su panel (ver más abajo).

2. Genera una clave sin passphrase (una vez, y ya no se vuelve a tocar), en la máquina donde corre el bot. Sin passphrase porque no va a haber nadie para teclearla:

ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519

3. Autorízala en la máquina remota. (por cada máquina) Este es el único paso que se repite de verdad:

ssh-copy-id -i ~/.ssh/id_ed25519.pub usuario@maquina

Para el segundo servidor, y el tercero, es esta misma orden apuntando a la máquina nueva:

ssh-copy-id -i ~/.ssh/id_ed25519.pub root@unraid
ssh-copy-id -i ~/.ssh/id_ed25519.pub admin@synology

4. Conéctate una vez a mano (por cada máquina), desde la máquina donde corre el bot, para que la huella de la remota quede en tu known_hosts. Aprovecha para hacer la prueba de arriba:

ssh usuario@maquina docker version

❗ Importante: los pasos 2, 3 y 4 se hacen en la máquina del bot, no dentro del contenedor. El bot no puede aceptar una huella nueva por ti: no hay terminal donde responder «yes», y el .ssh se mapea en solo lectura, así que no puede escribir en known_hosts. Si la máquina remota no está ya en tu known_hosts, el bot dirá que no responde con un Host key verification failed.

5. Da acceso al socket al usuario remoto (por cada máquina), si el paso 4 se quejó de permisos:

sudo usermod -aG docker usuario   # y vuelve a entrar por ssh

6. Mapea tu .ssh al contenedor (una vez) y reinicia el bot:

volumes:
    - /var/run/docker.sock:/var/run/docker.sock # NO CAMBIAR
    - /ruta/para/guardar/la/configuracion:/app/config
    - ~/.ssh:/root/.ssh:ro # Solo si vas a usar hosts ssh://

El bot corre como root dentro del contenedor, así que lee /root/.ssh. Tiene que ser el .ssh del usuario con el que hiciste el ssh-copy-id: ahí están la clave privada y el known_hosts que el paso 4 rellenó. En solo lectura a propósito, porque el bot no necesita escribir nada ahí.

La conexión la abre el cliente ssh del sistema, no una implementación propia, así que se respeta tu ~/.ssh/config entero: alias de host, puertos, IdentityFile, User. Si en tu config tienes un Host nas, la URL puede ser simplemente ssh://nas.

7. Añade el host en el bot. Ya no hace falta tocar el docker-compose otra vez: abre /settings, entra en 🖥️ Hosts de Docker, pulsa ➕ Añadir host y mándale el host en un solo mensaje, con el nombre que quieras darle delante:

nas ssh://usuario@nas

El nombre es opcional; si no lo pones, el bot lo saca de la URL. Antes de guardarlo prueba la conexión, así que si algo falla te lo dice en el momento y no lo guarda:

Lo que responde el bot Qué pasa
✅ Host nas añadido Ya está. Sus contenedores aparecen en /list desde ese instante
❌ No he podido conectar Trae el motivo debajo. Es el mismo que te daría la prueba del paso 4
❌ No sé conectarme a... La URL no empieza por ssh://, tcp:// o unix://
❌ ya está registrado Esa máquina ya está añadida; añadirla dos veces duplicaría sus contenedores

Después, pulsando el host en esa misma pantalla puedes 🔄 Probar de nuevo, ✏️ Renombrar, ⏸️ Pausar host o 🗑️ Quitar host. El 🟢, el 🔴 y el ⏸️ de la lista te dicen de un vistazo cuál responde y cuál está en pausa.

⏸️ Pausar es para la máquina que no está disponible ahora mismo pero que vas a recuperar: deja de listarse, de comprobarse y de aparecer en los menús, y sus programaciones se saltan en vez de deshabilitarse. No se pierde nada —ni la URL, ni el nombre, ni las tareas— y el mismo botón la reanuda. El host local no se puede pausar, porque el bot corre en él.

🗂️ Tengo varios servidores, ¿repito todo?

No: repites el paso 3 apuntando a cada máquina y listo. Una sola clave autoriza en todas las que quieras, y es lo que yo haría en una red doméstica: menos ficheros que gestionar y menos sitios donde equivocarse.

Comprueba cada una antes de añadirla al bot:

ssh root@unraid docker version
ssh admin@synology docker version
Prefiero una clave distinta por servidor

Merece la pena si quieres que una clave comprometida no abra todas tus máquinas, o si alguna es de otra persona y prefieres poder revocarla por separado. Generas una por máquina:

ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_unraid   -C "dcb-unraid"
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_synology -C "dcb-synology"

ssh-copy-id -i ~/.ssh/id_unraid.pub   root@unraid
ssh-copy-id -i ~/.ssh/id_synology.pub admin@synology

Y le dices a ssh cuál usar con cada una, en ~/.ssh/config:

Host unraid
    HostName unraid.lan
    User root
    IdentityFile ~/.ssh/id_unraid

Host synology
    HostName 192.168.1.20
    User admin
    Port 2222
    IdentityFile ~/.ssh/id_synology

Eso tiene dos ventajas más allá de las claves. La primera es que las URLs se quedan en ssh://unraid y ssh://synology a secas: el usuario, el puerto y la clave los pone la config. La segunda es que ssh unraid docker version sigue siendo la prueba, así que lo que verificas en la terminal es exactamente lo que va a hacer el bot.

ℹ️ Nota: el fichero ~/.ssh/config también se mapea al contenedor, porque ya estás mapeando el directorio entero. No hace falta añadir nada al docker-compose.

🔌 Prefiero tcp:// con socket proxy

Si tus máquinas ya están en una red privada, esta es la vía más corta: en lugar de exponer el socket entero, se expone un proxy que solo deja pasar lo que le indiques. En la máquina remota:

services:
    docker-socket-proxy:
        image: tecnativa/docker-socket-proxy
        container_name: docker-socket-proxy
        environment:
            - CONTAINERS=1
            - IMAGES=1
            - NETWORKS=1
            - VOLUMES=1
            - POST=1 # necesario para arrancar, parar y actualizar
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock:ro
        ports:
            - 2375:2375
        labels:
            - "DCB-Ignore-Check-Updates" # El bot llega a esta máquina A TRAVÉS del proxy no debe actualizarlo
        restart: unless-stopped

⚠️ Aviso: no actualices nunca este proxy desde el bot. El update pararía el proxy a mitad de la operación y se quedaría sin conexión para terminarla ni para deshacerla: el host quedaría en 🔴 y habría que rearrancarlo a mano por SSH (docker start docker-socket-proxy). Actualízalo siempre desde la propia máquina remota.

La URL para el bot es entonces tcp://maquina:2375. Compruébalo antes desde la máquina del bot:

docker -H tcp://maquina:2375 version

Si responde, añádelo en el bot igual que uno por ssh —/settings → 🖥️ Hosts de Docker → ➕ Añadir host— mandándole nas tcp://maquina:2375.

⚠️ Aviso: esto no lleva TLS ni autenticación: el proxy acota qué se puede hacer, no quién puede hacerlo. Publica el puerto solo en una red en la que confíes —Tailscale, WireGuard, una VLAN aislada—, nunca en internet. Si necesitas exponerlo fuera, usa TLS (ver FAQ).

💾 Synology, UnRAID y otros NAS

Ninguno expone el puerto de Docker por defecto, y es lo correcto: hacerlo sin TLS sería dejar la máquina abierta. Así que la vía es ssh:// en los dos casos.

UnRAID suele ser el fácil: el SSH viene habilitado, se entra como root y el docker está en el PATH. Normalmente basta con:

ssh root@unraid docker version

Si eso responde, tu URL es ssh://root@unraid.

Synology es el incómodo, y cuánto depende de tu versión de DSM:

  1. Habilita SSH en Panel de control → Terminal y SNMP → Activar servicio SSH.
  2. Prueba ssh tu_usuario@synology docker version.

Los dos tropiezos habituales son que el docker de Container Manager no está en el PATH de una sesión ssh, y que el socket es de root y tu usuario administrador no lo alcanza. En DSM moderno el login directo como root está deshabilitado, así que si te topas con eso la salida práctica es un contenedor socket proxy en el propio Synology, que además te deja limitar qué puede hacer el bot.

En mi caso no conseguí dejarlo fino por SSH en Synology, así que opté por levantar el docker-socket-proxy en el propio Synology y conectarlo con tcp://...:2375 sin TLS, dentro de la red local de confianza (ver desplegable de tcp:// de arriba). Es la opción que me funciona en el día a día.

💡 Consejo: si tienes tus máquinas en una red privada tipo Tailscale o WireGuard, tcp:// a secas sobre esa red te evita tanto los certificados como el ssh, porque el cifrado y la autenticación los pone la malla. Es lo más cómodo cuando ya la tienes montada.

Las credenciales nunca se guardan en los ajustes

En settings.json solo va la URL y, para TLS, las rutas de los certificados. Ni claves ni contraseñas: el material sensible son ficheros que tú mapeas, y así ningún mensaje de Telegram acaba llevándolo dentro.

🏷️ Funciones extra con labels en otros contenedores
  • Añadiendo la etiqueta DCB-Ignore-Check-Updates a un contenedor, no se comprobarán actualizaciones para él.
  • Añadiendo la etiqueta DCB-Auto-Update a un contenedor, se actualizará automáticamente sin preguntar.

Ver ejemplo completo en la FAQ: «He visto que se pueden añadir labels…».

📊 Estadísticas anónimas

Desde la 5.0.0 el bot envía una vez al día unas cifras anónimas para saber cuánta gente lo usa, en cuántos hosts y qué funciones se usan más. Así sé dónde poner el esfuerzo. Las estadísticas son públicas: stats.dgongut.com/docker-controller-bot.

Son opcionales. Vienen activadas por defecto y se desactivan de dos formas:

  • Desde el bot: /settings → Estadísticas anónimas. Al desactivarlas se borra también el identificador de la instalación.
  • Desde el compose: TELEMETRY=false.

Nada se envía hasta que el bot lleva al menos 10 minutos en marcha, así que da tiempo de sobra a desactivarlas desde /settings antes del primer envío.

Qué se envía y qué no

Qué se envía: cuántos hosts y contenedores hay (los contenedores, por tramos), qué ajustes están activados, la versión del bot y de Docker, la arquitectura, y cuántas veces al día se ha usado cada comando y cada botón. En /settings → Estadísticas anónimas → Qué se envía puedes ver el envío exacto que saldría ahora mismo. La lista completa, campo a campo, está en la página de privacidad. El servidor descarta cualquier dato que no esté en ella.

Qué no se envía nunca: nombres de contenedores, imágenes, hosts o proyectos, direcciones, IDs de Telegram, rutas ni nada de lo que escribes. Tu IP no se guarda.

El código es abierto: el cliente que envía los datos y el servidor que los recibe.

Tampoco se envía nada si la configuración no está en un volumen, porque sin él cada vez que se recreara el contenedor contaría como una instalación nueva.

Agradecimientos

❓ Preguntas Frecuentes (FAQ)

Pulsa cada pregunta para ver la respuesta.

🧭 ¿Puede el bot decirme de qué versión a qué versión se actualiza una imagen?

Sí, siempre que la imagen lo diga. El aviso de actualización, la lista de /updateall, la comparativa antes de confirmar y el resumen final muestran el salto de versión, por ejemplo 1.43.3 → 1.43.4. /info también enseña la versión de cada contenedor y la actualización pendiente.

De dónde la saca. No del tag, porque latest puede apuntar a cualquier cosa, sino de la propia imagen y sin peticiones extra:

  • La etiqueta estándar org.opencontainers.image.version (o la antigua org.label-schema.version), que llevan la mayoría de imágenes modernas, como las de linuxserver.
  • En las imágenes oficiales de Docker (nginx, postgres, redis…), que no llevan esa etiqueta, su variable de entorno con la versión: NGINX_VERSION, PG_VERSION…

Si la imagen no declara su versión, la actualización se detecta igual, porque el bot compara la imagen local con la del registro, pero no puede ponerle números: verás la fecha y el identificador (digest) de cada imagen.

Además:

  • Si sube el primer número (1.x → 2.0), la comparativa avisa de que puede traer cambios incompatibles. Las versiones con fecha, como 2026.10.1, no cuentan como salto mayor.
  • Si la imagen indica su repositorio de GitHub (etiqueta org.opencontainers.image.source), la comparativa enlaza a las novedades de esa versión, o a la lista de versiones si no encuentra su página.
🛠️ He visto que se pueden añadir labels para controlar ciertas cosas de los contenedores, ¿cómo lo hago?

Efectivamente, actualmente hay dos etiquetas (labels) que puedes añadir a los contenedores para controlarlos:

  • DCB-Ignore-Check-Updates
  • DCB-Auto-Update

Para añadirlas a un contenedor, basta con editar el archivo docker-compose.yml y agregarlas bajo la clave labels.
A continuación se muestra un ejemplo con Home Assistant:

services:
  homeassistant:
    image: lscr.io/linuxserver/homeassistant:latest
    container_name: homeassistant
    network_mode: host
    environment:
      - PUID=1026
      - PGID=100
      - TZ=Etc/Madrid
    volumes:
      - /volume2/docker/homeassistant/config:/config
      - /volume2/temp/ha:/tmp
    labels:
      - "DCB-Auto-Update"
    restart: unless-stopped
🧩 He creado mis contenedores con docker-compose y aparecen agrupados, ¿puedo gestionar uno solo?

Sí. Cuando entras en un proyecto verás cada contenedor por separado con su estado y podrás actuar sobre él individualmente, igual que sobre los contenedores standalone.

Las acciones globales (arrancar, parar, reiniciar o eliminar el proyecto entero) están disponibles como un botón adicional dentro del menú del proyecto.

📢 Si configuro el canal de notificaciones, ¿se duplican las notificaciones?

No. Cuando se define ese canal, los avisos de cambio de estado de los contenedores (arranque, parada, caída y actualizaciones automáticas) van solo a ese canal y dejan de aparecer en el chat principal.

El resto de mensajes (resultados de comandos, menús interactivos, avisos de actualización disponible con sus botones, etc.) nunca van a ese canal: el bot siempre responde en el sitio desde el que le hablas, sea el chat privado o el grupo/tema configurado en TELEGRAM_GROUP y TELEGRAM_THREAD.

🖥️ Tengo varios hosts, ¿cómo sé en qué máquina está cada contenedor?

El bot te lo dice él, y solo cuando hace falta.

Con un solo host el nivel de host no aparece en ningún sitio: /list y todos los menús se ven exactamente igual que antes de que existieran los hosts. No hay nada que aprender ni nada que cambie.

En cuanto tienes dos o más, aparece donde importa: /list agrupa los contenedores por máquina con una cabecera, cada mensaje de acción dice de qué host habla, y los menús de /run, /stop, /logs… te preguntan primero el host —salvo que solo uno tenga algo que ofrecer, en cuyo caso se salta la pregunta y va directo—.

Si dos máquinas tienen un contenedor con el mismo nombre y escribes /logs nginx, el bot no adivina: te pregunta en cuál de las dos.

🔌 Un host aparece en 🔴 rojo, ¿qué hago?

Entra en /settings → 🖥️ Hosts de Docker y púlsalo: la pantalla del host te dice el motivo exacto del fallo, y tienes un 🔄 Probar de nuevo para reintentar sin salir de ahí.

Lo importante es que una máquina caída no rompe el resto: /list sigue funcionando y muestra los hosts que sí responden, marcando el que no. Los comandos y las comprobaciones de actualización se saltan el que está fuera.

Para diagnosticarlo, la prueba de siempre desde la máquina del bot vale más que cualquier menú:

ssh usuario@maquina docker version

El mensaje que te dé ahí es el mismo que te está dando el bot, pero con todo el detalle. Las causas habituales están en la tabla de La prueba que lo decide (desplegable 🖥️ de arriba).

🔐 Quiero usar tcp:// pero cifrado con TLS, ¿se puede?

Se puede, sí, y aquí tienes el procedimiento. Pero antes lo honesto: es bastante avanzado y yo no lo considero necesario.

TLS resuelve un problema concreto: cruzar una red en la que no confías. Si tus máquinas están en tu casa, ssh:// te da exactamente la misma protección —cifrado y autenticación por clave— sin generar ni un certificado, y reutilizando el ssh que ya tienes montado. Y si necesitas llegar desde fuera, montar Tailscale o WireGuard es menos trabajo que un PKI y te sirve para todo lo demás de tu red, no solo para esto.

Dicho eso: si tu caso lo pide de verdad, o simplemente te apetece, funciona perfectamente. Ten en cuenta que es el único camino que no se puede añadir desde el bot y hay que escribir el host a mano en settings.json, como se ve en el paso 5.

Todo lo de abajo va en la máquina remota, salvo donde diga lo contrario.

1. Genera la CA y los certificados. Sustituye maquina.local por el nombre o IP con el que el bot va a llamarla:

openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem

openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=maquina.local" -sha256 -new -key server-key.pem -out server.csr
echo "subjectAltName = DNS:maquina.local,IP:192.168.1.50" > extfile.cnf
echo "extendedKeyUsage = serverAuth" >> extfile.cnf
openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem   -CAcreateserial -out server-cert.pem -extfile extfile.cnf

openssl genrsa -out key.pem 4096
openssl req -subj "/CN=client" -new -key key.pem -out client.csr
echo "extendedKeyUsage = clientAuth" > extfile-client.cnf
openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem   -CAcreateserial -out cert.pem -extfile extfile-client.cnf

2. Configura el daemon en /etc/docker/daemon.json:

{
  "tlsverify": true,
  "tlscacert": "/etc/docker/certs/ca.pem",
  "tlscert": "/etc/docker/certs/server-cert.pem",
  "tlskey": "/etc/docker/certs/server-key.pem",
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"]
}

En systemd hay que quitar el -H que trae la unidad, o dockerd se queja de que el host está definido dos veces:

sudo mkdir -p /etc/systemd/system/docker.service.d
printf '[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
' |   sudo tee /etc/systemd/system/docker.service.d/override.conf
sudo systemctl daemon-reload && sudo systemctl restart docker

3. Copia ca.pem, cert.pem y key.pem a la máquina del bot y mapéalos:

volumes:
    - /ruta/a/los/certs:/certs:ro

4. Comprueba antes de configurar el bot:

docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem   -H tcp://maquina.local:2376 version

5. Declara el host a mano. Esta es la única vía que no se puede añadir desde /settings: la pantalla de añadir host solo pide una URL, y un host con TLS necesita además las rutas de los tres certificados. Se escribe en settings.json, dentro del volumen que mapeaste, en la lista hosts:

{
    "id": "h_tls1",
    "alias": "maquina",
    "url": "tcp://maquina.local:2376",
    "local": false,
    "tls": {
        "ca": "/certs/ca.pem",
        "cert": "/certs/cert.pem",
        "key": "/certs/key.pem",
        "verify": true
    }
}

Las rutas son las de dentro del contenedor, o sea la parte derecha del volumen del paso 3. El id lo eliges tú y da igual cuál sea, siempre que no se repita: solo tiene que ser estable, porque es lo que atan las programaciones y la caché de actualizaciones.

❗ Importante: editar settings.json a mano requiere reiniciar el contenedor: el bot lo lee al arrancar y lo mantiene en memoria. Después del reinicio el host aparece en /settings → 🖥️ Hosts de Docker como cualquier otro, y ya se puede probar, renombrar y quitar desde ahí.

💬 ¿Desde dónde puedo manejar el bot?

Desde el chat privado con el bot y desde el grupo (o el tema concreto del supergrupo) que hayas configurado en TELEGRAM_GROUP y TELEGRAM_THREAD.

El bot contesta siempre donde le has escrito: si lanzas /list en el privado, la lista aparece en el privado; si lo lanzas en el tema del grupo, aparece en ese tema. El canal de notificaciones solo recibe las alertas de cambio de estado.

Cualquier otro chat se ignora: si el bot está metido en otro grupo, ahí no responde ni ejecuta nada, aunque quien escriba sea administrador. Ser administrador no basta, el chat también tiene que ser el privado del propio administrador o TELEGRAM_GROUP.

🔄 ¿Cómo actualizo el propio bot?

Igual que cualquier otro contenedor: desde /checkupdate docker-controller-bot o desde /updateall.

Internamente el bot lanza un contenedor auxiliar (UPDATER-Docker-Controler-Bot) que se encarga de descargar la nueva imagen, sustituirla y volver a levantar el bot, evitando que el propio bot se quede sin proceso a mitad de la actualización.

Si le añades la label DCB-Auto-Update a su docker-compose.yml, se actualizará solo en cuanto detecte una nueva versión.


🧑‍💻 Solo para desarrolladores

Ejecución con código local

Para su ejecución en local y probar nuevos cambios de código, se necesita renombrar el fichero .env-example a .env con los valores necesarios para su ejecución. Es necesario establecer un TELEGRAM_TOKEN y un TELEGRAM_ADMIN correctos y diferentes al de la ejecución normal.

La estructura de carpetas debe quedar:

docker-controller-bot/
    ├── .env
    ├── .gitignore
    ├── LICENSE
    ├── requirements.txt
    ├── README.md
    ├── Dockerfile_local
    ├── docker-compose.debug.yaml
    ├── docker-controller-bot.py   # punto de entrada: importa y arranca
    ├── core.py                    # el núcleo: DockerManager, monitores, teclados, UI
    ├── commands.py                # un `cmd_*` por comando
    ├── callbacks.py               # un `cb_*` por botón
    ├── callback_registry.py       # el decorador `@callback` y el parseo
    ├── host_registry.py           # los hosts Docker y su caché de clientes
    ├── store.py                   # settings.json, estado y cachés
    ├── migration.py               # migraciones de arranque (4.x → 5.0)
    ├── config.py                  # variables de arranque y constantes
    ├── i18n.py                    # carga de idiomas y `get_text`
    ├── own_container.py           # se identifica a sí mismo sin que se lo digan
    ├── docker_update.py
    ├── docker_compose_manager.py
    ├── compose_generator.py
    ├── port_manager.py
    ├── schedule_manager.py
    ├── message_queue.py
    ├── logger.py
    ├── tests
    │   ├── run_all.py
    │   └── ...
    └── locale
        ├── en.json
        ├── es.json
        ├── de.json
        ├── ru.json
        ├── gl.json
        ├── nl.json
        ├── cat.json
        └── it.json

Para levantarlo habría que ejecutar en esa ruta: docker compose -f docker-compose.debug.yaml up -d --build --force-recreate Para detenerlo y eliminarlo: docker compose down --rmi

Para probar nuevos cambios bastaría con guardar. Los cambios se refrescan en caliente.

Los tests

python3 tests/run_all.py

No necesitan Docker: el SDK va sustituido y los ajustes se escriben en un directorio temporal, así que se pueden lanzar en cualquier sitio. Pasan un rato comprobando cosas que solo se ven en tiempo de ejecución —nombres que un módulo no define, claves de idioma que nada renderiza, botones que llevarían un id sin su host, marcado que se ha ido de un idioma— así que si tocas código, lánzalos antes de proponer el cambio.

Se puede filtrar por módulo: python3 tests/run_all.py test_hosts.

Depuración con VS Code

Abre la carpeta del repositorio en Visual Studio Code necesitaras las siguientes extensiones instaladas en VS Code:

Instalación de las extensiones

  1. Abre VS Code.
  2. Ve a la extensión de la barra lateral y busca "Docker" y "Python".
  3. Instala ambas extensiones desde el Marketplace.

Establecer Puntos de Parada (Breakpoints)

  1. Abre el archivo de código que deseas depurar.
  2. Haz clic en el margen izquierdo junto a la línea de código donde quieras establecer un punto de parada. Aparecerá un punto rojo indicando el breakpoint.

Iniciar la Depuración

  1. Ve al menú Run y selecciona Start Debugging o presiona F5.
  2. VS Code arrancará el docker-compose.debug.yaml y comenzará la depuración.
  3. La ventana de depuración se abrirá en la parte inferior, mostrando las variables, la pila de llamadas y la consola de depuración.

Depuracion

Conclusión de la Depuración

  • Para detener la sesión de depuración, ve a Run > Stop Debugging o presiona Shift+F5

Download Statistics

2,820,333
Total Downloads
187,653
This Month
150,595
Avg / Month

Total Downloads Over Time

Loading chart...

Related apps

Explore more like this

Explore all

Details

Repository
dgongut/docker-controller-bot
Last Updated2026-10-09
First Seen2024-02-10

Runtime arguments

Network
bridge
Shell
sh
Privileged
false
Extra Params
--tty

Template configuration

TELEGRAM_TOKENVariable

This is the Telegram Token of the bot

TELEGRAM_ADMINVariable

This is the Telegram Chat-ID of the admin user

TELEGRAM_GROUP (DELETE IF NOT USED)Variable

This is the Telegram Chat-ID of the group (DELETE IF NOT USED)

Target
TELEGRAM_GROUP
Default
abc
CONTAINER_NAMEVariable

Put here the same name you give to the container

Default
Docker-Controller-Bot
TELEGRAM_THREAD (DELETE IF NOT USED)Variable

This is the topic id of a supergroup (if it is). (DELETE IF NOT USED)

Target
TELEGRAM_THREAD
Default
1
Value
1
CHECK_UPDATE_EVERY_HOURSVariable

Delay time in hours between check updates

Default
4
Value
4
CHECK_UPDATESVariable

Set to 1 if you want to check for updates.

Default
0
Value
0
docker.sockPathrw

This is needed

Target
/var/run/docker.sock
Default
/var/run/docker.sock
Value
/var/run/docker.sock
BUTTON_COLUMNSVariable

Number of button columns in Telegram messages

Default
2
Value
2