A high-performance, production-ready Traefik middleware plugin for blocking or allowing HTTP requests based on client IP addresses with integrated caching and comprehensive error handling.
┌─────────────────────────────────────────────────┐
│ HTTP Request │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────┐
│ getClientIP() │
│ (Extract from │
│ headers/RemoteAddr)
└──────────┬──────────┘
│
▼
┌──────────────────────┐
│ checkCache() │
│ (Fast lookup O(1)) │
└──────────┬───────────┘
│
┌──────────▼───────────┐
│ Cache Hit? │
└──────────┬───────────┘
┌─────┴─────┐
Yes│ │No
▼ ▼
┌─────────┐ ┌─────────────────────┐
│ Return │ │ isWhitelisted() │
│ Cached │ │ (Check direct + net)
│ Result │ └──────────┬──────────┘
└─────────┘ │
┌─────────▼────────┐
│ Whitelist Match? │
└────────┬─────────┘
No │
▼
┌──────────────────┐
│ isBlocked() │
│ (Check direct + │
│ CIDR ranges) │
└────────┬─────────┘
│
┌──────────▼────────┐
│ Block Match? │
└────────┬─────────┘
Yes│ No
│
┌──────────▼────────┐
│ cacheResult() & │
│ Route Request │
└───────────────────┘
# Enable the plugin in your Traefik configuration# See configuration examples below
# Clone repositorygit clone https://github.com/intaacopilot/traefik-plugin-blockip. gitcd traefik-plugin-blockip# Buildgo build -o plugin. so .# Testgo test -v ./...
middlewares:blockip:plugin:blockip:# Block specific IPsblockedIPs:- "192. 168.1.100"- "203.0.113.50"# Block CIDR rangesblockedCIDRs:- "192.168.0.0/16"- "10. 0.0.0/8"# HTTP response settingsstatusCode: 403message: "Access Denied"# Performance settingscacheTTL: 300# Debug modedebug: false
middlewares:blockip-advanced:plugin:blockip:# Blocked IPs and rangesblockedIPs:- "192.168.1.100"- "192.168.1.101"- "203.0.113.50"blockedCIDRs:- "192.168.0. 0/16" # Entire subnet- "10.0. 0.0/8" # Large range- "2001:db8::/32" # IPv6 range# Whitelist (bypass blocking)whitelistIPs:- "127. 0.0.1"- "::1"- "10.0.0. 1"whitelistCIDRs:- "192.168.1.0/24" # Trusted subnet- "10.0. 0.0/16" # Trusted network- "2001:db8:1::/48" # IPv6 trusted range# Response configurationstatusCode: 403message: "Your IP has been blocked"# Cache configuration (in seconds)cacheTTL: 300 # 5 minute cache# Debug loggingdebug: true
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
blockedIPs | []string | No | [] | Individual IPs to block |
blockedCIDRs | []string | No | [] | CIDR ranges to block (IPv4 & IPv6) |
whitelistIPs | []string | No | [] | IPs to whitelist (bypass blocking) |
whitelistCIDRs | []string | No | [] | CIDR ranges to whitelist |
statusCode | int | No | 403 | HTTP status code (400-599) |
message | string | No | "Access Denied" | Response message |
cacheTTL | int | No | 300 | Cache duration in seconds |
debug | bool | No | false | Enable debug logging |
version: '3.8'services:traefik:image: traefik:v3.0command:- "--api.insecure=true"- "--providers.docker=true"- "--providers.docker.exposedbydefault=false"- "--entrypoints. web.address=:80"- "--experimental.plugins.blockip.modulename=github.com/intaacopilot/traefik-plugin-blockip"- "--experimental.plugins. blockip.version=2.0.0"ports:- "80:80"- "8080:8080"volumes:- /var/run/docker.sock:/var/run/docker.sockweb-app:image: nginx:latestlabels:- "traefik.enable=true"- "traefik.http.routers. web.rule=Host(`example. com`)"- "traefik.http.routers. web.entrypoints=web"- "traefik.http. middlewares.blockip.plugin.blockip.blockedCIDRs=192.168.0.0/16,10.0.0. 0/8"- "traefik.http. middlewares.blockip.plugin. blockip.whitelistIPs=192.168.1.1"- "traefik. http.middlewares.blockip. plugin.blockip.statusCode=403"- "traefik.http.middlewares.blockip.plugin.blockip.cacheTTL=300"- "traefik.http. middlewares.blockip.plugin. blockip.debug=true"- "traefik.http. routers.web.middlewares=blockip"
# traefik.ymlentryPoints:web:address: :80providers:file:filename: /etc/traefik/config.ymldocker: {}experimental:plugins:blockip:modulename: github.com/intaacopilot/traefik-plugin-blockipversion: 2.0.0
# config.ymlhttp:middlewares:blockip-prod:plugin:blockip:blockedCIDRs:- "192.168.0.0/16"- "10. 0.0.0/8"whitelistCIDRs:- "192.168.1.0/24"statusCode: 403message: "IP Blocked"cacheTTL: 300debug: falserouters:my-app:rule: "Host(`app.example.com`)"middlewares:- blockip-prodservice: my-serviceservices:my-service:loadBalancer:servers:- url: http://localhost:8080
apiVersion: traefik.io/v1alpha1kind: Middlewaremetadata:name: blockipspec:plugin:blockip:blockedCIDRs:- "192.168.0.0/16"- "10.0.0.0/8"whitelistIPs:- "10.0.0.1"whitelistCIDRs:- "192.168.1.0/24"statusCode: 403message: "Access Denied"cacheTTL: 300debug: false---apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: my-appannotations:traefik.ingress.kubernetes.io/router.middlewares: default-blockip@kubernetescrdspec:rules:- host: app.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: my-serviceport:number: 80
| Code | Description | Resolution |
|---|---|---|
INVALID_CONFIG | Configuration is missing or invalid | Check config structure |
NIL_HANDLER | Next handler is nil | Verify handler chain setup |
INVALID_STATUS_CODE | Status code outside 4xx-5xx range | Use 4xx or 5xx codes |
INVALID_CIDR | CIDR format is incorrect | Validate CIDR syntax |
INVALID_IP | IP format is incorrect | Validate IP format |
PARSE_ERROR | Error parsing configuration | Check config syntax |
INTERNAL_ERROR | Internal plugin error | Check debug logs |
// Invalid configuration is caught at startupif config.StatusCode < 400 || config. StatusCode >= 600 {return nil, fmt.Errorf("invalid status code: %d", config.StatusCode)}// Invalid CIDR is logged but doesn't crash pluginif err := parseCIDR(cidr); err != nil {logger. Warn("Invalid CIDR: %s", cidr)continue}// IP parsing errors are handled gracefullyif ! isValidIP(ip) {logger.Debug("Invalid IP extracted: %s", ip)return ""}
Enable debug logging for troubleshooting:
middlewares:blockip-debug:plugin:blockip:debug: true# ... other config
Output example:
[2025-11-27 10:30:45] DEBUG - [blockip] Configuration loaded successfully. Blocked IPs: 2, Blocked CIDRs: 2, Whitelist IPs: 1, Whitelist CIDRs: 1
[2025-11-27 10:30:46] DEBUG - [blockip] Incoming request from IP: 192.168.1. 100, Path: /api/users
[2025-11-27 10:30:46] DEBUG - [blockip] IP 192.168.1.100 is blocked
# Run testsgo test -v ./...# Test with coveragego test -v -cover ./...# Build and test locallygo build -o plugin. so .
debug: truecacheTTL valuecacheTTL or set to 0 to disableContributions welcome! Please submit pull requests to improve the plugin.
MIT License - See LICENSE file for details
For issues, features, or questions: