
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/tcpand443/tcpopen from the internet. - Traefik and Pangolin on the same Docker network.
Files & Permissions
acme.jsonexists 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: cloudflarewith 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-storageto confirm plugin persistence. - Check
docker network inspectto verify Traefik ↔ service connectivity.
Quick Checklist
- Badger plugin declared in
experimental.plugins - Plugins stored via
./plugins-storage+XDG_DATA_HOME - One ACME method configured (HTTP-01 or DNS-01)
- No private IPs in any TLS router
- Pangolin + Traefik on
traefik_net - File provider
watch: truefor hot reloads
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.
