Traefik plugin
Bots, Tor, VPNs and proxies, checked per router with one label. It starts in monitor mode and blocks nothing until you switch.
Free, MIT licenseTested with Traefik v3.7
Entrypoint
websecure:443Router
app@dockerHost(`example.com`)Middlewares
gzip@dockeripscanner@dockerHumanAllowService
app@docker200X-IPScanner-Class: humanX-IPScanner-Action: allowAccess log
Traffic classes
Each visitor gets one class. Your service receives it as X-IPScanner-Class.
Setup
Put it in the Traefik container's environment. Every ipscanner middleware reads it.
environment:
IPSCANNER_API_KEY: pk_live_...In the static configuration, or as two CLI flags. Restart Traefik.
experimental:
plugins:
ipscanner:
moduleName: github.com/ipscanner/ipscanner-traefik
version: v0.1.0siteIdMode and policy then come from the dashboard, without a reload.
Add a site in the dashboardtraefik.http.middlewares.ipscanner.plugin.ipscanner.siteId=site_...Other routers reuse it as ipscanner@docker.
traefik.http.routers.app.middlewares=ipscannerYour stack
Same plugin, wherever Traefik reads its config.
command:
# ...the flags Coolify set
- '--experimental.plugins.ipscanner.modulename=github.com/ipscanner/ipscanner-traefik'
- '--experimental.plugins.ipscanner.version=v0.1.0'
environment:
- IPSCANNER_API_KEY=pk_live_...traefik.http.middlewares.ipscanner-myapp.plugin.ipscanner.siteId=site_...
traefik.http.routers.https-0-<uuid>.middlewares=gzip,ipscanner-myappOne middleware name per app, appended to each router Coolify generated. Behind Cloudflare, also set trustedProxies=cloudflare and ipHeaders=CF-Connecting-IP.
services:
traefik:
image: traefik:v3.7
command:
- --providers.docker=true
- --entrypoints.web.address=:80
- --experimental.plugins.ipscanner.modulename=github.com/ipscanner/ipscanner-traefik
- --experimental.plugins.ipscanner.version=v0.1.0
environment:
IPSCANNER_API_KEY: ${IPSCANNER_API_KEY}
ports: ["80:80"]
volumes: ["/var/run/docker.sock:/var/run/docker.sock:ro"]
app:
image: traefik/whoami:v1.11.0
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`example.com`)
- traefik.http.routers.app.middlewares=ipscanner
- traefik.http.middlewares.ipscanner.plugin.ipscanner.siteId=site_...Dokploy and plain Compose read the same labels.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ipscanner
spec:
plugin:
ipscanner:
apiKey: urn:k8s:secret:ipscanner:apiKey
siteId: site_...Reference it from an IngressRoute or with the router.middlewares annotation on an Ingress.
http:
middlewares:
ipscanner:
plugin:
ipscanner:
apiKeyFile: /run/secrets/ipscanner_api_key
siteId: site_...The key comes from a mounted Docker or Kubernetes secret.
Sites dashboard
Allow, flag or block each class from the dashboard. The middleware picks up a change within 30 seconds.
Policy
Options
Set them on the middleware: as labels, in YAML or on the CRD.
| Option | Default | What it does |
|---|---|---|
siteIdYour dashboard site; mode and policy come from it | Empty | Your dashboard site; mode and policy come from it |
modemonitor or enforce, when there is no siteId | monitor | monitor or enforce, when there is no siteId |
blockClassesClasses blocked in enforce mode without siteId | malicious_automation | Classes blocked in enforce mode without siteId |
trustedProxiesProxies whose IP headers are trusted: CIDRs, private, cloudflare | Empty | Proxies whose IP headers are trusted: CIDRs, private, cloudflare |
ipHeadersHeaders read from a trusted proxy, in order | X-Forwarded-For | Headers read from a trusted proxy, in order |
timeoutBudget for one check, then the request passes | 1500ms | Budget for one check, then the request passes |
cacheTTLVerdict cache per visitor | 10m | Verdict cache per visitor |
cacheSizeVisitors kept in the cache | 10000 | Visitors kept in the cache |
policyTTLHow long a fetched policy stays fresh | 30s | How long a fetched policy stays fresh |
skipPathsPath regex that skips the check | Static assets | Path regex that skips the check |
apiKeyFileFile holding the API key, for secrets | Empty | File holding the API key, for secrets |
debugAdds the headers to responses and logs each decision | false | Adds the headers to responses and logs each decision |
Questions
Add the middleware, read a week of traffic in the dashboard, then block.