Cómo arreglar plugin integrity check failed en Traefik (Badger v1.8.0 de Pangolin, Sablier)
Índice de contenidos
- Puntos clave
- ¿Qué significa el error plugin integrity check failed en Traefik?
- Qué plugins y versiones fallan hoy
- ¿Por qué el catálogo de Traefik rechaza su propio zip?
- Por qué funciona en un servidor y falla en otro
- Arreglo 1: fija en Traefik el hash del zip que descargas
- ¿Es seguro fijar el hash de un zip que el catálogo rechaza?
- Arreglo 2: vuelve a Badger v1.7.0 en Pangolin
- Arreglo 3: carga el plugin como plugin local
- Cómo comprobar que el plugin vuelve a funcionar
- Qué hacer cuando Traefik corrija el catálogo
- Preguntas frecuentes
- ¿Se arregla actualizando o bajando la versión de Traefik?
- ¿Por qué Traefik desactiva todos mis plugins y no solo el roto?
- ¿Me afecta si persisto /plugins-storage en un volumen?
- Conclusión
- Fuentes
Traefik muestra plugin integrity check failed porque su catálogo de plugins sirve un zip distinto del que valida: dos compilaciones de Go comprimen el mismo código de forma diferente. Le pasa a Badger v1.8.0 de Pangolin y a Sablier v1.3.1. Fija en tu configuración el hash del zip descargado o vuelve a la versión anterior.
El error plugin integrity check failed no viene de tu configuración ni del plugin: el catálogo de Traefik sirve un zip y valida el hash de otro. Los dos zips llevan el mismo código, pero uno se comprimió con Go 1.26 y el otro con Go 1.27. Se arregla añadiendo hash: con el SHA-256 del zip que te llega, después de comprobar su contenido contra la base de sumas de Go, o volviendo a la versión anterior del plugin. Lo reproduje el 27 de octubre de 2026 con Traefik 3.7.16, Badger v1.8.0 (el plugin de Pangolin) y Sablier v1.3.1, en Linux arm64 con Docker 29.5.2. Tienes la versión en inglés de esta guía.
Puntos clave
- Traefik descarga el zip de
plugins.traefik.io, calcula su SHA-256 y pregunta al catálogo si es válido; el catálogo responde 404 y Traefik desactiva todos los plugins. - Badger v1.8.0 se sirve con el hash
1337d349…y el catálogo solo acepta60f02559…, que es el zip deproxy.golang.org; los 18 ficheros de dentro son idénticos byte a byte. - La caché de Cloudflare guarda la respuesta de validación durante 3600 s sin mirar el hash enviado, y por eso el mismo plugin carga en un servidor y falla en otro.
- La clave
hashexiste desde Traefik v3.5.3: con ella Traefik compara el hash en tu máquina y no consulta al catálogo. - En Pangolin, quedarte en Badger v1.7.0 también lo resuelve; solo pierdes las redirecciones permanentes de Pangolin 1.25.
¿Qué significa el error plugin integrity check failed en Traefik?
Significa que el catálogo de plugins de Traefik no reconoce el zip que acaba de servirte. Traefik descarga el plugin al arrancar y envía su SHA-256 al punto /public/validate; si la respuesta no es 200, deja de cargar todos los plugins, no solo el afectado. Este es el registro que obtuve con Sablier v1.3.1:
INF Loading plugins... plugins=["sablier"]
ERR Plugins are disabled because an error has occurred.
error="unable to set up plugins environment: unable to install
plugin sablier: unable to check archive integrity of the plugin
github.com/sablierapp/sablier-traefik-plugin: plugin integrity
check failed" plugins=["sablier"]
En tu terminal cada entrada sale en una línea; aquí la he partido para que quepa. Con Badger v1.8.0 el texto es el mismo con github.com/fosrl/badger, según el registro publicado en la incidencia 14115 de Traefik. Justo después aparece un segundo error por cada router que usa el middleware, y ese es el que ves en el panel de Traefik:
ERR error="invalid middleware \"ondemand@file\" configuration:
invalid middleware type or middleware does not exist"
entryPointName=web routerName=whoami@file
El router queda en estado disabled y la ruta responde 404. Si el middleware es Badger, todos los recursos que Pangolin publica detrás de Traefik dejan de responder a la vez.
Qué plugins y versiones fallan hoy
El fallo afecta a versiones de plugins publicadas después de que proxy.golang.org pasara a Go 1.27, sea cual sea tu versión de Traefik. El 27 de octubre de 2026, entre las 09:13 y las 09:18 UTC, descargué seis versiones del catálogo y calculé su hash. Después lo comparé con el zip de proxy.golang.org y pregunté al catálogo por el hash servido:
| Plugin y versión | Hash servido | Hash del proxy de Go | Validación del servido |
|---|---|---|---|
fosrl/badger v1.8.0 |
1337d349… |
60f02559… |
404, falla |
sablierapp/sablier-traefik-plugin v1.3.1 |
c819d45f… |
6f33a870… |
404, falla |
andrewkroh/google-oidc-auth-middleware v0.4.0 |
f33d4264… |
b6b848c5… |
404, falla |
DIE-Bonn/MatomoTracking v1.2.0 |
68b86912… |
539f858c… |
200 desde el origen |
maxlerebourg/crowdsec-bouncer-traefik-plugin v1.8.1 |
1c63fab0… |
854eb7a9… |
200 desde la caché |
crazygolem/traefik-subsonic-basicauth v0.2.1 |
aceed5ec… |
aceed5ec… |
200, coinciden |
Que los dos hashes sean distintos no basta para que falle: MatomoTracking ya valida porque el catálogo corrigió el hash que guarda. El caso del bouncer de CrowdSec no es concluyente, porque la respuesta venía de la caché.
El problema llegó a Pangolin el 21 de octubre. Su guía de actualización pide subir la versión de Badger en config/traefik/traefik_config.yml a la última de GitHub, que desde ese día es la v1.8.0. El instalador de Pangolin 1.25.3, en cambio, sigue escribiendo la v1.7.0: lo comprobé en las opciones de compilación del binario para arm64. Si montaste Pangolin con la guía de instalación de Pangolin y no tocaste esa línea, no te afecta.
¿Por qué el catálogo de Traefik rechaza su propio zip?
Porque el catálogo guarda el hash de una compilación del zip y sirve otra. Un módulo de Go se empaqueta con zip.CreateFromVCS, y Go 1.27 comprime con un deflate distinto al de Go 1.26: mismos ficheros, mismas fechas, distinto tamaño comprimido. Andrew Kroh, autor del plugin de OIDC, lo resumió así en la incidencia 13845 de Traefik: "the Go 1.27 toolchain produces different deflate output than Go 1.26, and the catalog builds the archive it serves with one toolchain while the hash it validates against matches the other".
Lo comprobé con Badger v1.8.0. Descomprimí los dos zips y diff -r no encontró ninguna diferencia en sus 18 ficheros. Lo único que cambia es el tamaño comprimido: 33 136 bytes el del catálogo y 33 442 bytes el del proxy de Go.
Por qué funciona en un servidor y falla en otro
La segunda pieza es la caché de Cloudflare delante de plugins.traefik.io. La respuesta de /public/validate lleva cache-control: max-age=3600, y la clave de caché no incluye la cabecera X-Plugin-Hash que envía Traefik. Lo vi en directo: tras una petición con el hash del proxy que devolvió 200, el nodo de Londres respondió 200 con cf-cache-status: HIT a cualquier hash, incluido uno de 64 ceros. A las 10:14 UTC esa respuesta seguía en caché con age: 3673, y mi Traefik cargó Badger v1.8.0 sin hash y sin error.
Por eso el mismo docker compose up carga Badger en un VPS y falla en tu servidor de casa dos minutos después, como cuenta un usuario en la incidencia 38 de Badger. Depende de qué respuesta tenga guardada el nodo de Cloudflare que te toca. Esperar o reiniciar no es un arreglo: Pangolin no guarda /plugins-storage en un volumen, y cada contenedor nuevo vuelve a descargar y a validar.
Arreglo 1: fija en Traefik el hash del zip que descargas
La clave hash del plugin hace que Traefik compare el SHA-256 en tu máquina y se salte la llamada a /public/validate. Lo vi en el código de pkg/plugins/manager.go de la v3.7.16 y existe desde Traefik v3.5.3. Primero descarga el zip igual que lo hace Traefik y calcula su hash:
M=github.com/fosrl/badger
curl -sSo badger.zip https://plugins.traefik.io/public/download/$M/v1.8.0
sha256sum badger.zip
El resultado fue 1337d3490a9eda1d20207d881cee37e40991d74443bdcfa61182c5416678b7e8, el mismo que publicó otro usuario desde dos nodos de Cloudflare distintos. Antes de fiarte de él, verifica el contenido como se explica en la sección siguiente. Después añade la línea hash al plugin en config/traefik/traefik_config.yml:
experimental:
plugins:
badger:
moduleName: github.com/fosrl/badger
version: v1.8.0
hash: 1337d3490a9eda1d20207d881cee37e40991d74443bdcfa61182c5416678b7e8
Recrea el contenedor de Traefik para que relea la configuración estática y mira el registro. Con el hash fijado, Badger v1.8.0 y Sablier v1.3.1 cargaron sin errores:
$ docker compose up -d --force-recreate traefik
$ docker logs traefik 2>&1 | grep -i plugin
INF Loading plugins... plugins=["badger"]
INF Plugins loaded. plugins=["badger"]
Si pones el hash del proxy de Go (60f02559…) en vez del servido, Traefik no arranca el plugin y te dice exactamente qué recibió: invalid hash for plugin github.com/fosrl/badger, expected 60f02559…, got 1337d349…. Ese mensaje confirma que la comparación es real y te da el hash correcto.
¿Es seguro fijar el hash de un zip que el catálogo rechaza?
Es seguro si compruebas que el contenido coincide con la versión publicada del módulo, y eso no depende del catálogo de Traefik. La base de sumas de Go, sum.golang.org, guarda un hash h1: del contenido de cada versión, calculado sobre los ficheros y no sobre la compresión. Este script de Python calcula ese mismo h1: a partir del zip:
import sys, zipfile, hashlib, base64
z = zipfile.ZipFile(sys.argv[1])
lines = [
f"{hashlib.sha256(z.read(n)).hexdigest()} {n}\n"
for n in sorted(z.namelist()) if not n.endswith("/")
]
digest = hashlib.sha256("".join(lines).encode()).digest()
print("h1:" + base64.b64encode(digest).decode())
Guárdalo como h1.py y compara su salida con la entrada de la base de sumas de Go:
$ python3 h1.py badger.zip
h1:HiHK8coR8OGurUoGipAhmQIasyvmOi5lbfL6kOPaA84=
$ curl -s https://sum.golang.org/lookup/$M@v1.8.0 | sed -n 2p
github.com/fosrl/badger v1.8.0 h1:HiHK8coR8OGurUoGipAhmQIasyvmOi5lbfL6kOPaA84=
Los dos valores coinciden, así que el zip que sirve el catálogo contiene exactamente el código que Go registró para la v1.8.0. Con Sablier v1.3.1 obtuve también la misma suma por los dos lados. Si en tu caso no coinciden, no fijes ese hash y pasa al arreglo 2.
Arreglo 2: vuelve a Badger v1.7.0 en Pangolin
Volver a la versión anterior es lo que recomienda el propio equipo de Pangolin mientras Traefik corrige el catálogo. Las notas de Badger v1.8.0 lo dicen sin rodeos: "Badger v1.8.0 is currently broken, so please stay on v1.7.0". Cambia la versión en config/traefik/traefik_config.yml, sin línea hash:
experimental:
plugins:
badger:
moduleName: github.com/fosrl/badger
version: v1.7.0
Tras recrear Traefik, el registro mostró Plugins loaded. y el zip descargado de la v1.7.0 tenía el hash 4eb41cc6…. La única novedad de la v1.8.0 es el soporte de redirecciones permanentes: según las notas de Pangolin 1.25, las redirecciones normales funcionan con la v1.7.0. Con Sablier, la versión equivalente es la v1.3.0, que cargó sin errores junto a Badger v1.7.0 en mi prueba.
Arreglo 3: carga el plugin como plugin local
Un plugin local no pasa por el catálogo, así que no hay descarga ni validación. Es la opción que más trabajo pide y la que menos depende de terceros: copia el código fuente del plugin en el contenedor y decláralo en experimental.localPlugins. Traefik busca el código en /plugins-local/src/ seguido del nombre del módulo:
mkdir -p plugins-local/src/github.com/fosrl
unzip -q badger.zip -d /tmp/badger
cp -r "/tmp/badger/github.com/fosrl/badger@v1.8.0" \
plugins-local/src/github.com/fosrl/badger
Monta ese directorio en el servicio de Traefik con ./plugins-local:/plugins-local:ro y sustituye el bloque plugins por este:
experimental:
localPlugins:
badger:
moduleName: github.com/fosrl/badger
El nombre badger se mantiene, así que los middlewares que Pangolin genera como badger siguen encontrándolo. En mi prueba el registro mostró Plugins loaded. y la interfaz de programación (API) de Traefik devolvió el middleware con estado enabled. El precio es que las actualizaciones pasan a ser manuales.
Cómo comprobar que el plugin vuelve a funcionar
El registro con Plugins loaded. es la primera señal, y la confirmación está en el estado de los routers. El instalador de Pangolin deja activa la API de Traefik en el puerto 8080 del contenedor, así que puedes consultarla con wget desde dentro:
docker exec traefik wget -qO- \
http://localhost:8080/api/http/routers/whoami@file \
| grep -o '"status":"[a-z]*"'
Cambia whoami@file por el nombre de uno de tus routers; la lista completa está en /api/http/routers.
Con el plugin roto, el router devolvía disabled y la ruta, 404. Con cualquiera de los tres arreglos, el router y su middleware devolvieron "status":"enabled". En el laboratorio la ruta respondió después 500, porque no había un Pangolin ni un servidor de Sablier detrás. En una instalación real, Badger consulta en ese punto a la API de Pangolin para decidir si deja pasar la petición.
Qué hacer cuando Traefik corrija el catálogo
Quita la línea hash en cuanto el catálogo valide el zip que sirve. Un mantenedor de Traefik escribió en la incidencia 13845 el 26 de octubre que es su prioridad y que estará resuelto antes del fin de semana. Si la corrección consiste en servir el zip de Go 1.27, el hash que fijaste dejará de coincidir y verás invalid hash for plugin … expected 1337d349…, got 60f02559….
Para saber si ya está corregido, pregunta al catálogo por el hash que te sirve:
H=$(sha256sum badger.zip | cut -c1-64)
curl -s -D - -o /dev/null -H "X-Plugin-Hash: $H" \
https://plugins.traefik.io/public/validate/$M/v1.8.0 \
| grep -iE '^HTTP|cf-cache-status'
Un 404 significa que sigue roto. Un 200 solo es fiable si cf-cache-status no dice HIT, por la caché que ignora el hash. Esto ya pasó en agosto con Badger v1.6.0 a v1.7.0, en la incidencia 13771, y Traefik lo resolvió el 27 de agosto.
Preguntas frecuentes
¿Se arregla actualizando o bajando la versión de Traefik?
No. La validación ocurre en el servidor del catálogo, y Traefik 3.7.16, la última del 20 de octubre, falla igual que la 3.7.12 de los primeros informes. Traefik v2.11 hace la misma comprobación y además no tiene la clave hash, así que allí solo sirven los arreglos 2 y 3.
¿Por qué Traefik desactiva todos mis plugins y no solo el roto?
Porque prepara el entorno de plugins de una vez y cualquier fallo lo anula entero. En mi prueba, con Badger v1.7.0 (que valida) y Sablier v1.3.1 (que no) en la misma configuración, el registro dijo Plugins are disabled para los dos. Cada router que use cualquiera de ellos queda en disabled.
¿Me afecta si persisto /plugins-storage en un volumen?
Sí. Con el zip ya guardado, Traefik envía su hash al descargar y, si el catálogo responde 304, vuelve a llamar a /public/validate. Solo la clave hash o un plugin local evitan esa consulta.
Conclusión
plugin integrity check failed es un fallo del catálogo de Traefik, no de tu Pangolin ni de tu Sablier: el zip que sirve y el hash que valida salen de dos compiladores de Go. Si necesitas la versión nueva, verifica el zip contra sum.golang.org y fija su hash con la clave hash. Si no, vuelve a Badger v1.7.0 o a Sablier v1.3.0 y espera a la corrección. Si aún no tienes un proxy inverso, la guía para instalar Traefik con Docker Compose parte de cero.
Fuentes: [1] Traefik, incidencia 13845 sobre el catálogo de plugins[1], [2] Traefik, incidencia 14115 sobre Badger v1.8.0[2], [3] Badger, notas de la versión v1.8.0[3], [4] Badger, incidencia 38[4], [5] Traefik, código de pkg/plugins/manager.go en v3.7.16[5], [6] Traefik, opciones de configuración estática[6], [7] Pangolin, cómo actualizar[7], [8] Base de sumas de Go, entrada de Badger v1.8.0[8], [9] Traefik, incidencia 13771 de agosto[9].
Fuentes
- Traefik, incidencia 13845 sobre el catálogo de plugins
- Traefik, incidencia 14115 sobre Badger v1.8.0
- Badger, notas de la versión v1.8.0
- Badger, incidencia 38
- Traefik, código de pkg/plugins/manager.go en v3.7.16
- Traefik, opciones de configuración estática
- Pangolin, cómo actualizar
- Base de sumas de Go, entrada de Badger v1.8.0
- Traefik, incidencia 13771 de agosto
Código fuente
Accede a todo el código fuente de este artículo en GitHub.
Ver en GitHub