IPScanner

Integrations

Traefik plugin

A middleware from the Traefik Plugin Catalog that checks each visitor before the router passes the request on.

Install

  1. 1Declare the plugin in Traefik's static configuration and restart Traefik.
  2. 2Add a Traefik site in the dashboard and copy its Site ID.
  3. 3Set IPSCANNER_API_KEY on the Traefik container.
  4. 4Add an ipscanner middleware with the Site ID and put it on a router.

A new site starts in monitor mode: it adds headers and blocks nothing until you switch it to enforce.

Overview on the Traefik plugin page, source and full examples on GitHub.

experimental:
  plugins:
    ipscanner:
      moduleName: github.com/ipscanner/ipscanner-traefik
      version: v0.1.0

Coolify, Compose, Kubernetes

  • Coolify

    Plugin flags in the proxy's command list and the key in its environment. Then the middleware in your app's container labels, appended to each router Coolify generated. Use one middleware name per app.

  • Docker Compose

    Flags on the Traefik service, the middleware in your app's labels. Other routers reuse it as ipscanner@docker.

  • Kubernetes

    A Middleware resource with the key from a Secret. Reference it from an IngressRoute, or from an Ingress with the router.middlewares annotation.

  • File provider

    The middleware in a dynamic configuration file, with the key from a mounted secret.

Without a key every request passes with X-IPScanner-Status: skipped.

- '--experimental.plugins.ipscanner.modulename=github.com/ipscanner/ipscanner-traefik'
- '--experimental.plugins.ipscanner.version=v0.1.0'

environment:
  - IPSCANNER_API_KEY=pk_live_...

Configuration

  • apiKey

    API key. Plugin options show in the Traefik dashboard, so prefer IPSCANNER_API_KEY, apiKeyFile or a urn:k8s:secret reference.

  • apiKeyFile

    File holding the API key, such as a mounted Docker or Kubernetes secret.

  • siteId

    Site ID from the dashboard. Mode and policy then come from the dashboard.

  • modedefault monitor

    monitor or enforce. With a site, only monitor has an effect: it keeps the site in monitor mode.

  • blockClassesdefault malicious_automation

    Classes blocked in enforce mode without a site: malicious_automation, ai_agent, tor, vpn, proxy, hosting, relay or none.

  • trustedProxies

    Addresses and CIDR ranges whose IP headers are trusted. private adds the private ranges, cloudflare the Cloudflare ranges.

  • ipHeadersdefault X-Forwarded-For

    Headers read from a trusted proxy, in order. Behind Cloudflare: CF-Connecting-IP.

  • timeoutdefault 1500ms

    Budget for one check. On a timeout the request passes.

  • cacheTTLdefault 10m

    How long a verdict is reused per site, IP and user agent.

  • cacheSizedefault 10000

    Verdicts kept in memory.

  • policyTTLdefault 30s

    How long the site policy is reused.

  • skipPathsdefault static assets

    Case-insensitive regex on the path. Matching requests are not checked; none checks every path.

  • blockMessagedefault Blocked by IPScanner edge guard.

    Text of the 403 page.

  • debugdefault false

    Adds X-IPScanner-Status, -Class and -Action to responses and logs one line per decision.

  • apiUrldefault https://ipscanner.io

    API base URL.

Lists take YAML lists or comma-separated values (blockClasses=tor,vpn in labels). Durations use Go syntax: 1500ms, 30s, 10m. An invalid option disables the router with an error in the Traefik log.

Client IP

The visitor is the address Traefik sees, unless that address is a trusted proxy.

  • trustedProxies

    X-Forwarded-For, or the ipHeaders list, is read only from these addresses.

  • forwardedHeaders.trustedIPs

    Traefik drops X-Forwarded-For from peers outside the entry point's trusted IPs, so set both, or read CF-Connecting-IP.

  • trustedProxies=cloudflare, ipHeaders=CF-Connecting-IP

    Behind Cloudflare with the orange cloud on, add both to the middleware.

Headers it adds

Added to the request your app receives. Incoming X-IPScanner-* headers are removed first, so a client cannot send its own verdict.

  • X-IPScanner-Statusok, error, timeout, backoff, skipped

    Whether the check ran, and if not, why.

  • X-IPScanner-Classhuman, verified_bot, ai_agent, …

    Traffic class of the visitor.

  • X-IPScanner-Actionallow, flag, block, would_flag, would_block

    What happened to the request. Monitor mode gives would_flag and would_block.

  • X-IPScanner-Network-Classresidential_clean, hosting, vpn, tor, …

    Network class of the address.

  • X-IPScanner-Anonymizedtrue, false

    The network hides where the visitor is.

  • X-IPScanner-Risk0-100

    Risk score of the address.

  • X-IPScanner-CountryDE

    Country of the address.

  • X-IPScanner-Sitesite_...

    The Site ID, when one is set.

When a check fails or is skipped, only X-IPScanner-Status is set.

Request to your app
X-IPScanner-Status: ok
X-IPScanner-Class: ai_agent
X-IPScanner-Action: would_block
X-IPScanner-Network-Class: hosting
X-IPScanner-Anonymized: true
X-IPScanner-Risk: 60
X-IPScanner-Country: US
X-IPScanner-Site: site_4fQ8nZ2kLm7xR1vT9cBw

Caching and fail open

  • Mode and per-class policy, cached 30 s. If a refresh fails, the last good policy stays for 24 hours. Changes apply without a reload.

  • Verdict cache

    One check per visitor (site, IP, user agent) per 10 minutes, in memory, up to 10,000 visitors. Kept across configuration reloads.

  • Fail open

    1.5 s for verdict and policy together. On a timeout or API error the request passes and checks pause for 30 s, or 5 minutes after a 401, 402, 403 or 429.

  • Always pass

    Verified crawlers, OPTIONS requests, private and loopback addresses, and paths on the skip list.

  • Blocked

    A 403 page with the request ID. Monitor mode never blocks.

  • Free plan

    Sites on the Free plan stay in monitor mode.

  • Cost

    2 request units per uncached visitor. Repeat requests inside the cache window are free.

What it sends

  • POST /v1/edge/checkCounts as 2 requests

    One call per uncached visitor.

  • The site policy, when a Site ID is set.

  • X-IPScanner-Source: traefik

    Marks the calls as this integration's in your traffic and usage.

  • User-Agent: ipscanner-traefik/<version>

    The version, shown on the site's page in the dashboard.

Request body

  • sitestring

    The Site ID, when one is set.

  • ipstring

    The visitor's address.

  • user_agentstring

    The visitor's User-Agent.

  • headersobject

    Accept, Accept-Language, Accept-Encoding, Sec-CH-UA* and Sec-Fetch-*, each cut to 512 bytes.

  • request_idstring

    The request's X-Request-Id or a new ID, also printed on the block page.

The edge check it makes
curl https://ipscanner.io/v1/edge/check \
  -H "Authorization: Bearer $IPSCANNER_API_KEY" \
  -H "X-IPScanner-Source: traefik" \
  -H "User-Agent: ipscanner-traefik/0.1.0" \
  -H "Content-Type: application/json" \
  -d '{
    "site": "site_4fQ8nZ2kLm7xR1vT9cBw",
    "ip": "203.0.113.7",
    "user_agent": "Mozilla/5.0",
    "headers": {
      "accept-language": "en-US"
    },
    "request_id": "9f2c41b7d03e77f2"
  }'