Skip to main content

Cloudflare Setup

This guide covers configuring the ELLIO Traefik Middleware Plugin for services deployed behind Cloudflare. Cloudflare acts as a proxy, so proper IP extraction configuration is crucial for accurate IP-based filtering.

Overview

When your Traefik instance is behind Cloudflare:

  • Client IPs are forwarded in the CF-Connecting-IP header
  • Cloudflare IPs appear as the direct connection source
  • Trusted proxy configuration is essential to prevent IP spoofing
  • Real client IPs must be extracted from Cloudflare headers

Prerequisites

  • Cloudflare account with your domain configured
  • Traefik instance running behind Cloudflare proxy
  • Bootstrap token from your custom EDL configured for "Traefik Middleware"

Step 1: Configure Cloudflare-Specific Settings

The key to Cloudflare integration is using the CF-Connecting-IP header and trusting Cloudflare's IP ranges.

Static Configuration

# traefik.yml
api:
dashboard: true

entryPoints:
web:
address: :80
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: :443

providers:
docker:
endpoint: unix:///var/run/docker.sock
exposedByDefault: false
file:
filename: /etc/traefik/dynamic.yml
watch: true

# ELLIO Plugin
experimental:
plugins:
ellio:
moduleName: "github.com/ELLIO-Technology/ELLIO-Traefik-Middleware-Plugin"
version: "v1.0.1"

log:
level: INFO

accessLog: {}

# Cloudflare SSL/TLS configuration
certificatesResolvers:
cloudflare:
acme:
dnsChallenge:
provider: cloudflare
# Use DNS challenge with Cloudflare

Dynamic Configuration for Cloudflare

Keep the list complete, accurate, and Cloudflare-only

trustedProxies is the set of upstream IPs Traefik trusts to set CF-Connecting-IP. Two failure modes to avoid:

  • List too narrow / out of date. If a real Cloudflare edge isn't in the list, Traefik won't trust the header it sends - your middleware sees the Cloudflare edge IP as the client and real-client filtering breaks for every request through that range.
  • List too broad, or origin reachable directly. Any IP you trust here can claim any client address via CF-Connecting-IP. Don't add ranges that aren't actually Cloudflare. Just as importantly, lock down the origin so requests can only arrive through Cloudflare - otherwise a direct connection that happens to come from any address can spoof the client IP through this header.

The ranges below were correct at the time of writing. Treat Cloudflare's published IP lists as the source of truth and refresh them on a schedule - ideally fetch the published files at deploy time and generate this config from them.

# dynamic.yml
http:
middlewares:
# ELLIO EDL Middleware - Cloudflare Configuration
ellio-cloudflare:
plugin:
ellio:
bootstrapToken: "YOUR_ELLIO_BOOTSTRAP_TOKEN"
logLevel: "info"
ipStrategy: "custom"
trustedHeader: "CF-Connecting-IP"
trustedProxies:
# Cloudflare IPv4 ranges
- "173.245.48.0/20"
- "103.21.244.0/22"
- "103.22.200.0/22"
- "103.31.4.0/22"
- "141.101.64.0/18"
- "108.162.192.0/18"
- "190.93.240.0/20"
- "188.114.96.0/20"
- "197.234.240.0/22"
- "198.41.128.0/17"
- "162.158.0.0/15"
- "104.16.0.0/13"
- "104.24.0.0/14"
- "172.64.0.0/13"
- "131.0.72.0/22"
# Cloudflare IPv6 ranges
- "2400:cb00::/32"
- "2606:4700::/32"
- "2803:f800::/32"
- "2405:b500::/32"
- "2405:8100::/32"
- "2a06:98c0::/29"
- "2c0f:f248::/32"

routers:
# Protected application behind Cloudflare
protected-app:
rule: "Host(`app.example.com`)"
service: my-app
middlewares:
- ellio-cloudflare
entryPoints:
- websecure
tls:
certResolver: cloudflare

# Dashboard with Cloudflare protection
api:
rule: "Host(`traefik.example.com`)"
service: api@internal
middlewares:
- ellio-cloudflare
entryPoints:
- websecure
tls:
certResolver: cloudflare

services:
my-app:
loadBalancer:
servers:
- url: "http://backend:8080"

Step 2: Complete Cloudflare Docker Compose Setup

docker-compose.yml
# docker-compose.yml

services:
traefik:
image: traefik:v3.2
container_name: traefik-cloudflare
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./dynamic.yml:/etc/traefik/dynamic.yml:ro
- ./letsencrypt:/letsencrypt
environment:
- CLOUDFLARE_EMAIL=${CLOUDFLARE_EMAIL}
- CLOUDFLARE_API_KEY=${CLOUDFLARE_API_KEY}
networks:
- web
labels:
- "traefik.enable=true"
# Dashboard with ELLIO protection
- "traefik.http.routers.api.rule=Host(`${TRAEFIK_DOMAIN}`)"
- "traefik.http.routers.api.middlewares=ellio-cloudflare@file"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=cloudflare"

# Example backend service
backend:
image: traefik/whoami
container_name: backend-app
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`${APP_DOMAIN}`)"
- "traefik.http.routers.app.middlewares=ellio-cloudflare@file,cloudflare-headers@file"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=cloudflare"

networks:
web:
driver: bridge