
Traefik & Pangolin Fixes
From “unknown plugin type: badger” to ACME timeouts and rate limits—this guide gets you to green logs and valid TLS quickly.
What went wrong (anonymized)
We removed real domains/IPs. Examples below use example.com
and RFC1918 ranges.
1) Badger plugin not loaded
Traefik tried to use a middleware before the plugin was declared and stored.
error="plugin: unknown plugin type: badger" … routerName=app-1@http error="plugin: unknown plugin type: badger" … routerName=app-2@http error="plugin: unknown plugin type: badger" … routerName=app-3@http
2) ACME validation failing (HTTP-01)
Multiple hostnames hit connection/timeout issues and triggered per-hostname rate limits.
Unable to obtain ACME certificate … rateLimited :: too many failed authorizations … host.example.com
… storage.example.com … console.example.com … nas.example.com
3) Private IP in certificate request
Including a LAN IP in a TLS router led ACME to reject the order.
Invalid identifiers requested :: Cannot issue for "192.168.0.50": IP address is in a reserved address block
4) Provider connectivity
Traefik couldn’t reach the Pangolin HTTP provider on pangolin:3001
due to networking.
Need this implemented for you? Hire a vetted expert today.
Prerequisites
Networking
- Public DNS A/AAAA records point to your proxy.
- Ports
80/tcp
and443/tcp
open from the internet. - Traefik and Pangolin on the same Docker network.
Files & Permissions
acme.json
exists and is0600
.- Persistent volume for plugin storage (
./plugins-storage
). - Dynamic config mounted read-only.
Architecture (overview)
Internet → [80/443] → Traefik → (Routers/Middlewares) → Services └─ DNS API (DNS-01) └─ ACME (HTTP-01/.well-known)
Fast, reliable fixes
Enable the Badger plugin
Add the plugin to static config and persist plugin storage. Example snippets:
experimental: plugins: badger: moduleName: github.com/fosrl/badger version: v1.2.0 # docker-compose (add a volume) volumes: - ./plugins-storage:/plugins-storage environment: XDG_DATA_HOME: /plugins-storage
Pick one ACME method (and test safely)
- HTTP-01: Ensure TCP/80 is open end-to-end and any CDN is “DNS only”.
- DNS-01 (Cloudflare): Use
dnsChallenge: provider: cloudflare
with a token granting Zone:Read + DNS:Edit. - Use Staging CA while iterating to avoid rate limits.
Remove private IPs from TLS routers
Keep LAN access on plain HTTP (no TLS) or behind a trusted certificate, but never request ACME for RFC1918 IPs.
Network Traefik ↔ Pangolin
Put both containers on a shared Docker network (e.g., traefik_net
) so http://pangolin:3001
resolves from Traefik.
Recommended file layout
Use a clean host path and relative volumes:
/opt/traefik/ ├─ docker-compose.yml ├─ traefik/ │ ├─ traefik.yml │ └─ dynamic_config.yml └─ letsencrypt/ └─ acme.json
Copy-ready dynamic config (safe defaults)
http: middlewares: redirect-to-https: redirectScheme: scheme: https routers: # HTTP → HTTPS for the public host only http-redirect: entryPoints: [web] rule: "Host(`host.example.com`)" middlewares: [redirect-to-https] service: noop@internal # Pangolin UI (HTTPS) pangolin-ui: entryPoints: [websecure] rule: "Host(`host.example.com`) && !PathPrefix(`/api/v1`)" service: next-service tls: certResolver: letsencrypt # Pangolin API (HTTPS) pangolin-api: entryPoints: [websecure] rule: "Host(`host.example.com`) && PathPrefix(`/api/v1`)" service: api-service tls: certResolver: letsencrypt services: next-service: loadBalancer: { servers: [ { url: "http://pangolin:3002" } ] } api-service: loadBalancer: { servers: [ { url: "http://pangolin:3000" } ] }
Extra: static config (snippet)
entryPoints: web: { address: ":80" } websecure: { address: ":443" } certificatesResolvers: letsencrypt: acme: email: admin@example.com storage: /letsencrypt/acme.json httpChallenge: { entryPoint: web } api: { dashboard: true } providers: file: { filename: /etc/traefik/dynamic.yml, watch: true } docker: { exposedByDefault: false }
Sanity checks before calling it done
Troubleshooting quick hits
- If HTTP-01 fails, curl the challenge path from the internet; any timeout means firewall/NAT/CDN.
- If DNS-01 fails, check token scopes and Cloudflare zone.
- If ACME rate-limits, pause and switch to staging until green.
- Use
docker exec traefik ls -l /plugins-storage
to confirm plugin persistence. - Check
docker network inspect
to verify Traefik ↔ service connectivity.
Quick Checklist
experimental.plugins
Badger plugin declared in ./plugins-storage
+XDG_DATA_HOME
Plugins stored via - One ACME method configured (HTTP-01 or DNS-01)
- No private IPs in any TLS router
traefik_net
Pangolin + Traefik on watch: true
for hot reloads
File provider
Useful Commands
docker network create traefik_net || true docker network connect traefik_net traefik docker network connect traefik_net pangolin docker logs -n 200 traefik curl -I http://host.example.com/.well-known/acme-challenge/testNeed a freelancer?
FAQ
How do I switch to DNS-01 safely?
CF_API_TOKEN
as an environment variable, and enable dnsChallenge
. Test on Let’s Encrypt staging before production.Why does ACME keep rate-limiting me?
Is the Badger plugin required?
unknown plugin type
errors.Can I terminate TLS at a CDN?
How do I debug provider connectivity?
nc -vz pangolin 3001
. If it fails, connect both containers to the same user-defined network.Need implementation? Use the “Hire a Freelancer” button above, or talk to a live agent on the website chat.