All apps · 0 apps
Docker-Controller-Bot
Docker app from dgongut's Repository
Overview
Readme
View on GitHubDocker-Controller-Bot
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.

🚀 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)
- Abre @BotFather en Telegram y envía
/newbot. Sigue las instrucciones (un nombre y un username acabado enbot). - BotFather te devolverá el token del bot. Guárdalo: irá en la variable
TELEGRAM_TOKEN. - 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. - (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. - (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=falseen 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/configLa 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 -dpara recrear el contenedor. Mientras no lo hagas, el bot te lo recuerda en su mensaje de arranque.tty: trueya no hace falta. Hasta la 4.x el compose lo llevaba para que los logs del bot salieran endocker logs; desde la 5.0 la imagen los escribe al momento sin él. Puedes quitarlo, o dejarlo: no molesta.CONTAINER_NAMEya 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/mountinfoy 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.jsony los conserva tal cual. A partir de ahí mandasettings.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,/stopy/restart. - 🧩 Compose: detecta tus proyectos y los agrupa (proyecto → contenedores).
- 📊 Diagnóstico: logs en el chat o como fichero,
execdentro 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,/stopy/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,pruneymute. - Acepta expresiones cron estándar (
0 */4 * * *) y atajos:@yearly,@monthly,@weekly,@daily,@hourlyy@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.
mutees 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 conssh://disponible no le veo la necesidad, pero si tu caso lo pide está explicado en la FAQ, en «Quiero usartcp://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
.sshse mapea en solo lectura, así que no puede escribir enknown_hosts. Si la máquina remota no está ya en tuknown_hosts, el bot dirá que no responde con unHost 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/configtambié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:
- Habilita SSH en Panel de control → Terminal y SNMP → Activar servicio SSH.
- 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-Updatesa un contenedor, no se comprobarán actualizaciones para él. - Añadiendo la etiqueta
DCB-Auto-Updatea 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
- Traducción al neerlandés: ManCaveMedia
- Traducción al alemán: shedowe19
- Traducción al ruso: leyalton
- Traducción al gallego: monfero
- Traducción al italiano: zichichi
- Traducción al catalán: flancky
- Pruebas del Docker Login: garanda
- Readme en inglés: phampyk
❓ 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 antiguaorg.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, como2026.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-UpdatesDCB-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.jsona 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
- Abre VS Code.
- Ve a la extensión de la barra lateral y busca "Docker" y "Python".
- Instala ambas extensiones desde el Marketplace.
Establecer Puntos de Parada (Breakpoints)
- Abre el archivo de código que deseas depurar.
- 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
- Ve al menú
Runy seleccionaStart Debuggingo presionaF5. - VS Code arrancará el
docker-compose.debug.yamly comenzará la depuración. - La ventana de depuración se abrirá en la parte inferior, mostrando las variables, la pila de llamadas y la consola de depuración.

Conclusión de la Depuración
- Para detener la sesión de depuración, ve a
Run > Stop Debuggingo presionaShift+F5
Categories
Download Statistics
Total Downloads Over Time
Related apps
Explore more like this
Explore allDetails
dgongut/docker-controller-botRuntime arguments
- Network
bridge- Shell
sh- Privileged
- false
- Extra Params
--tty
Template configuration
This is the Telegram Token of the bot
This is the Telegram Chat-ID of the admin user
This is the Telegram Chat-ID of the group (DELETE IF NOT USED)
- Target
- TELEGRAM_GROUP
- Default
- abc
Put here the same name you give to the container
- Default
- Docker-Controller-Bot
This is the topic id of a supergroup (if it is). (DELETE IF NOT USED)
- Target
- TELEGRAM_THREAD
- Default
- 1
- Value
- 1
Delay time in hours between check updates
- Default
- 4
- Value
- 4
Set to 1 if you want to check for updates.
- Default
- 0
- Value
- 0
This is needed
- Target
- /var/run/docker.sock
- Default
- /var/run/docker.sock
- Value
- /var/run/docker.sock
Number of button columns in Telegram messages
- Default
- 2
- Value
- 2