Soy de esas personas que tiene 40 containers corriendo en producción y cada vez que veo un “new image available” me da pereza actualizar. No porque sea difícil, sino porque son 40. Y algunos necesitan recrear el stack completo. Y otros dependen de otros. Y siempre hay uno que se rompe al actualizar.
Watchtower resolvió este problema por mi. Ahora mis containers se actualizan solos, de noche, sin que yo toque nada. Y cuando algo se rompe (porque siempre se rompe algo), tengo rollback automático.
Te cuento cómo lo monté, qué errores cometí y cómo configurarlo para que no te despiertes con el homelab roto.
Qué es Watchtower y por qué lo uso#
Watchtower es un container que vigila tus otros containers. Cada X horas (tú decides), comprueba si hay nuevas imágenes disponibles en Docker Hub o tu registry privado. Si las hay, hace pull, para el container viejo, levanta el nuevo con la misma configuración, y borra la imagen antigua.
Todo automático. Sin tocar nada.
Lo uso porque:
- Me ahorro trabajo manual - Antes dedicaba 30 minutos cada domingo a actualizar todo. Ahora dedico 0.
- Seguridad - Los parches de seguridad se aplican automáticamente. No tengo que acordarme.
- Consistencia - Todos mis servidores tienen la misma lógica de actualización. No hay “este lo actualicé la semana pasada” vs “este lleva 3 meses sin tocar”.
- Rollback automático - Si el nuevo container no arranca, Watchtower vuelve a la imagen anterior. Me ha salvado varias veces.
La primera vez que lo probé fue en un servidor de pruebas con 5 containers. Funcionó tan bien que ahora lo tengo en todos mis nodos. Incluido producción.
Instalación básica (la que todos usan)#
La mayoría de guías te dicen que ejecutes esto:
| |
Y funciona. Pero es una mala idea.
Por qué? Porque va a actualizar TODOS tus containers. Incluidos los que no quieres que se actualicen (bases de datos, por ejemplo). Y lo va a hacer cada 24 horas, sin preguntarte.
Yo lo hice así la primera vez. A las 3 de la mañana se actualizó mi PostgreSQL y rompió la compatibilidad con n8n. Me desperté sin automatizaciones funcionando. No fue divertido.
Mi configuración real (con docker-compose)#
Así es como lo tengo montado ahora:
| |
Punto por punto:
WATCHTOWER_SCHEDULE - Cron expression para definir cuándo se ejecuta. Yo lo tengo a las 4:00 AM porque es cuando menos tráfico hay en mi homelab. Si algo se rompe, lo veo por la mañana.
WATCHTOWER_LABEL_ENABLE - Esta es la clave. Solo actualiza containers que tengan el label com.centurylinklabs.watchtower.enable=true. Así controlo exactamente qué se actualiza.
WATCHTOWER_CLEANUP - Borra las imágenes antiguas después de actualizar. Si no, tu disco se llena de imágenes viejas.
WATCHTOWER_NOTIFICATIONS - Envío notificaciones a Discord cada vez que hay una actualización. Así sé qué cambió sin tener que revisar logs.
WATCHTOWER_ROLLING_RESTART - Si el nuevo container falla el health check, vuelve a la imagen anterior. Esto es oro puro.
Cómo marcar qué containers se actualizan#
Este es el truco. En cada container que quiero que Watchtower actualice, añado este label:
| |
Y listo. Watchtower solo tocará ese container.
Los containers que NO tienen ese label (bases de datos, por ejemplo) quedan intactos. Yo los actualizo manualmente cuando sé que no voy a romper nada.
Mi regla personal:
- Actualización automática: servicios stateless (Plex, Jellyfin, servicios web, reverse proxies)
- Actualización manual: bases de datos, servicios con estado crítico (PostgreSQL, Redis, n8n)
- Nunca actualizar: containers legacy que funcionan y no quiero tocar
Notificaciones (saber qué pasó sin mirar logs)#
Watchtower puede enviar notificaciones a un montón de servicios. Yo uso Discord porque ya lo tengo abierto 24/7.
Configuración:
- Crea un webhook en tu servidor de Discord (Server Settings > Integrations > Webhooks)
- Copia la URL (algo como
https://discord.com/api/webhooks/123456/token) - Conviértela al formato Shoutrrr:
| |
Ejemplo real (datos falsos):
| |
Se pone en la variable WATCHTOWER_NOTIFICATION_URL.
Ahora cada vez que Watchtower actualiza algo, recibes un mensaje así:
| |
Si algo falla:
| |
Tranquilidad mental.
Estrategias de actualización (cómo NO romper todo)#
Después de usar Watchtower en producción durante 8 meses, estas son las estrategias que me funcionan:
1. Actualizar por oleadas#
No actualices todo a la vez. Divide tus containers en grupos:
- Oleada 1 (lunes 4 AM): servicios no críticos (Plex, Jellyfin, wikis)
- Oleada 2 (miércoles 4 AM): servicios importantes pero con fallback (reverse proxies, dashboards)
- Oleada 3 (nunca): bases de datos y servicios críticos (manual)
Cómo? Tengo 3 instancias de Watchtower con schedules diferentes y labels diferentes:
| |
Y en cada container:
| |
Así si la oleada 1 rompe algo, tengo 2 días para arreglarlo antes de que toque servicios críticos.
2. Health checks obligatorios#
Watchtower solo puede hacer rollback si el container tiene health check. Si no lo tiene, asume que está bien aunque esté roto.
Ejemplo de health check para un servicio web:
| |
Si después de actualizar el health check falla 3 veces, Watchtower vuelve a la imagen anterior. Automático.
3. Monitoring post-actualización#
Tengo un script que corre 10 minutos después de cada actualización de Watchtower. Comprueba que todos los servicios responden correctamente.
| |
Lo ejecuto con cron 10 minutos después de la ventana de actualización:
10 4 * * * /home/user/scripts/check-services.sh4. Registries privados (para containers custom)#
Si tienes containers propios en un registry privado (Gitea, Harbor, etc), Watchtower también puede actualizarlos.
Necesitas pasar las credenciales:
| |
O mejor, usando Docker secrets:
| |
Yo tengo varios containers propios en mi Gitea. Cada vez que hago push a main, GitHub Actions buildea la imagen, la sube al registry, y Watchtower la actualiza en producción. CI/CD casero.
Errores que cometí (para que no los cometas tú)#
Error 1: Actualizar bases de datos sin snapshot#
La primera vez que activé Watchtower dejé que actualizara mi PostgreSQL. La nueva versión cambió el formato de datos. Rollback imposible. Tuve que restaurar desde backup de hace 2 días.
Solución: Las bases de datos NUNCA van con Watchtower. Se actualizan manualmente después de hacer snapshot del volumen.
Error 2: No configurar health checks#
Actualicé Vaultwarden. El nuevo container arrancó pero no respondía en el puerto esperado (cambió de 80 a 8080). Watchtower pensó que estaba bien porque el proceso arrancó. Pasé 2 horas sin acceso a mis contraseñas.
Solución: Health checks en TODOS los containers que actualiza Watchtower. Sin excepciones.
Error 3: Actualizar todo a la vez#
Un lunes actualicé 40 containers simultáneamente. Traefik se actualizó, cambió el formato de configuración, y todos los demás servicios quedaron inaccesibles. Tardé 6 horas en arreglar todo.
Solución: Actualizar por oleadas. Empezar por lo menos crítico. Esperar 48h antes de tocar lo importante.
Error 4: No leer changelogs#
Actualicé Immich automáticamente de v1.94 a v1.95. La nueva versión requería migración manual de base de datos. Watchtower no puede hacer eso. El servicio quedó roto hasta que ejecuté el script de migración.
Solución: Para servicios con datos críticos, añadir un paso manual. Watchtower actualiza la imagen, pero tengo un checklist en Notion de “cosas que revisar después de actualizar X”.
Error 5: Timeout demasiado corto#
Configuré WATCHTOWER_TIMEOUT=30. Algunos de mis containers tardan más de 30 segundos en arrancar (Nextcloud, por ejemplo). Watchtower pensaba que habían fallado y hacía rollback innecesario.
Solución: WATCHTOWER_TIMEOUT=300 (5 minutos). Si un container tarda más de 5 minutos en arrancar, probablemente hay un problema real.
Configuración avanzada (solo si lo necesitas)#
Actualizar solo tags específicos#
Por defecto Watchtower actualiza a latest. Pero si quieres más control:
| |
Watchtower solo actualizará si hay un nuevo v1.95.x. No saltará a v1.96.0 sin que tú cambies el tag explícitamente.
Yo uso esto para servicios críticos. Prefiero actualizar major versions manualmente.
Actualizar grupos de containers juntos#
Algunos stacks necesitan actualizarse todos a la vez (Immich tiene server, machine-learning, web, etc).
| |
Watchtower esperará a que todos estén disponibles antes de actualizar.
Dry run (ver qué se actualizaría sin actualizar)#
Útil para testing:
| |
Te dice qué containers tienen actualizaciones disponibles pero no hace nada.
Alternativas a Watchtower#
Watchtower no es la única opción. Otras que probé:
Diun - Solo notifica de nuevas imágenes, no actualiza. Bueno si quieres control total pero te da pereza revisar manualmente Docker Hub.
Ouroboros - Como Watchtower pero con menos features. Lo usé antes de Watchtower. Funciona bien pero el proyecto está menos activo.
Renovate - Para actualizar archivos docker-compose.yml en Git. Genial si usas GitOps. Yo lo uso en paralelo con Watchtower: Renovate propone cambios, yo los reviso, hago merge, Watchtower aplica.
Pulumi/Terraform - Overkill para homelab pero si ya usas IaC tiene sentido. Yo no llegué a ese nivel todavía.
Conclusión: automatiza lo aburrido#
Actualizar containers manualmente es trabajo de mono. Es repetitivo, no aporta valor, y siempre se te olvida alguno.
Watchtower no es perfecto. Vas a tener que ajustar configuración. Te va a romper algo en algún momento. Pero incluso con esos problemas, me ahorra fácil 2 horas al mes.
Configuración que recomiendo para empezar:
- Instala Watchtower con
WATCHTOWER_LABEL_ENABLE=true - Añade el label solo a 2-3 containers no críticos
- Configura notificaciones a Discord/Telegram/donde sea
- Espera 1 semana
- Si no se rompió nada, añade más containers
En 2-3 semanas tendrás un sistema de actualización que funciona sin pensar en él.
Y cuando veas el mensaje “Watchtower: Updated 8 containers” a las 4 de la mañana mientras duermes, vas a sonreír.
Yo lo hice.