caddy_cdn_ranges

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2026 License: MIT Imports: 18 Imported by: 0

README

caddy-cdn-ranges

Use CDN provider IP ranges as a trusted proxies source for Caddy.

This module periodically fetches IP ranges from the cdn-ranges providers list and exposes them to Caddy's trusted_proxies IP source.

Why use this module?

Trusted proxies are critical for applications behind reverse proxies or load balancers. This module automatically:

  • Fetches the latest IP ranges from major CDN and cloud providers
  • Updates them periodically to stay in sync with provider changes
  • Supports custom providers for specialized use cases
  • Filters by IPv4/IPv6 as needed
  • Handles concurrent fetches for performance

Features

  • Periodic refresh of CDN IP ranges (default: 24h).
  • Filter by provider name(s).
  • Custom provider support with JMESPath filtering and plain text handling.
  • IPv4 and/or IPv6 selection.
  • Concurrent fetching for faster updates.

Caddyfile usage

{
  servers {
    trusted_proxies {
      source cdn_ranges {
        interval 24h
        provider cloudflare cloudfront
        concurrency 5
        ipv4 true
        ipv6 true
      }
    }
  }
}

Custom provider block form:

{
  servers {
    trusted_proxies {
      source cdn_ranges {
        provider {
          cloudflare
          custom_cdn {
            ipv4_url https://example.com/ipv4
            ipv6_url https://example.com/ipv6 items
            asn_list [13335, 20940]
          }
        }
      }
    }
  }
}

Custom Provider Configuration

Define custom providers inline in your Caddyfile to fetch from arbitrary sources:

JSON Response with JMESPath

If your provider returns JSON, use JMESPath to extract the IP list:

provider {
  my_custom_cdn {
    ipv4_url https://api.example.com/ipv4.json "prefixes[].cidr"
    ipv6_url https://api.example.com/ipv6.json "prefixes[].cidr"
  }
}

JMESPath examples:

  • @ (default): Return the entire response as-is (must be an array or string)
  • items: Extract the items array from the response
  • prefixes[].cidr: Extract the cidr field from each item in the prefixes array
  • data.networks: Navigate nested objects

See JMESPath Specification for more complex queries.

Plain Text Response

If your provider returns plain text (one IP per line), simply omit the JMESPath argument:

provider {
  my_static_list {
    ipv4_url https://example.com/ipv4.txt
    ipv6_url https://example.com/ipv6.txt
  }
}

Plain text responses automatically skip empty lines and lines starting with # or //.

Using ASN Lookups

Fetch prefixes for Autonomous System Numbers (ASNs):

provider {
  my_asn_provider {
    asn_list 13335 15169 8452
  }
}
Combining Multiple Sources

A single custom provider can combine ASNs, IPv4 URLs, and IPv6 URLs:

provider {
  all_sources {
    asn_list [13335, 20940]
    ipv4_url https://api.example.com/v4 "items[].network"
    ipv6_url https://api.example.com/v6 "items[].network"
  }
}

Directive options

  • provider <name...>: One or more provider names (space-separated). If omitted, all providers are used.

    • Short form: provider cloudflare cloudfront
    • Block form: provider { cloudflare custom { ... } }
  • provider { <name> { ... } }: Define custom providers inline. Each custom provider block can set:

    • ipv4_url <url> [jmespath]: Fetch IPv4 ranges from a URL. Uses JMESPath to extract CIDR blocks from JSON. For plain text, omit JMESPath. Default JMESPath is @ (return entire response).
    • ipv6_url <url> [jmespath]: Fetch IPv6 ranges from a URL. Uses JMESPath to extract CIDR blocks from JSON. For plain text, omit JMESPath. Default JMESPath is @ (return entire response).
    • asn_list <asn...>: Fetch ranges for one or more Autonomous System Numbers. Can be space-separated or comma-separated with brackets: asn_list 13335 20940 or asn_list [13335, 20940].
  • concurrency <number>: Number of concurrent provider fetches. Default: 5.

  • ipv4 <true|false>: Enable IPv4 ranges. Default: true.

  • ipv6 <true|false>: Enable IPv6 ranges. Default: true.

  • interval <duration>: Refresh interval. Default: 24h.

Provider names

Provider names come from the cdn-ranges library. Use the provider names listed in that project (see CDN Providers).

Built-in providers include:

  • cloudflare
  • cloudfront (AWS CloudFront)
  • And more — check the cdn-ranges repository for a complete list.

Troubleshooting

Module fails to fetch ranges

Check the logs for provider errors. Common causes:

  • Network timeouts or DNS failures
  • Invalid JMESPath in custom provider configuration
  • Provider returning an unexpected content type
Incorrect IP ranges returned

Verify your custom provider configuration:

  • Test the URL in your browser to see the response format
  • Verify the JMESPath extraction by testing it at jmespath.org
  • Ensure the response contains valid CIDR blocks (e.g., 192.0.2.0/24)
Performance concerns

If fetching takes too long:

  • Increase concurrency (default: 5)
  • Increase interval to fetch less frequently
  • Reduce the number of providers being fetched

Build with xcaddy or custom image

Use xcaddy to build a Caddy binary that includes this module:

xcaddy build \
  --with github.com/sarumaj/caddy-cdn-ranges

Example Dockerfile that builds a custom Caddy image with this module:

FROM caddy:2.11-builder-alpine AS builder

WORKDIR /build

ENV GOTOOLCHAIN=go1.25.0

RUN xcaddy build \
  --with github.com/sarumaj/caddy-cdn-ranges

FROM caddy:2.11-alpine
COPY --from=builder /build/caddy /usr/bin/caddy

Notes

  • The module reuses its fetched ranges for all requests until the next refresh.
  • If provider names are specified and none match, the module fails during provisioning.
  • Custom providers must return one of:
    • JSON (for JMESPath extraction)
    • Plain text with one CIDR block per line
  • Invalid CIDR blocks are rejected and will cause fetch failures. Ensure your data is well-formed.

License

See LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CaddyTrustedProxiesCDN

type CaddyTrustedProxiesCDN struct {
	// Interval is the duration between refreshes of the IP ranges list. Defaults to 24 hours.
	// The module fetches updated ranges from providers at this interval. Set to smaller values
	// for more frequent updates (at the cost of increased network requests) or larger values
	// to reduce update frequency.
	// Examples: "12h", "1h", "30m"
	Interval caddy.Duration `json:"interval,omitempty"`

	// Providers is a list of providers to fetch IP ranges from. Each element can be:
	//   - A string: built-in provider name (e.g., "cloudflare", "cloudfront")
	//   - A *Provider: custom provider with URL endpoints and/or ASN lookups
	//
	// Built-in providers are matched case-insensitively. If this list is empty,
	// all available built-in providers from the cdn-ranges library will be used.
	// If specified providers are not found, the module will fail during provisioning.
	//
	// Example: providers cloudflare cloudfront
	//
	// Example with custom provider:
	//
	// 	providers {
	// 		cloudflare
	// 		custom_cdn {
	// 			ipv4_url https://api.example.com/ipv4.json "prefixes[].cidr"
	// 			ipv6_url https://api.example.com/ipv6.json "prefixes[].cidr"
	// 			asn_list 13335 20940
	// 		}
	// }
	Providers []any `json:"provider,omitempty"`

	// Concurrency is the number of concurrent goroutines used to fetch IP ranges from providers.
	// Higher values speed up updates but use more resources. Defaults to 5.
	// Set to 1 for sequential fetching or increase for faster parallel updates.
	// Recommended values: 3-10 depending on provider availability and network conditions.
	Concurrency int `json:"concurrency,omitempty"`

	// IPv4 controls whether IPv4 CIDR blocks are included in the trusted proxies list.
	// If nil (not set), it defaults to true (unless IPv6 is also nil, then both default to true).
	// Set to false to exclude IPv4 ranges. Useful if you only trust IPv6 proxies.
	// Examples: true (enable IPv4), false (disable IPv4)
	IPv4 *bool `json:"ipv4,omitempty"`

	// IPv6 controls whether IPv6 CIDR blocks are included in the trusted proxies list.
	// If nil (not set), it defaults to true (unless IPv4 is also nil, then both default to true).
	// Set to false to exclude IPv6 ranges. Useful if you only trust IPv4 proxies.
	// Examples: true (enable IPv6), false (disable IPv6)
	IPv6 *bool `json:"ipv6,omitempty"`
	// contains filtered or unexported fields
}

CaddyTrustedProxiesCDN is a Caddy IP source module that automatically fetches and maintains a list of trusted proxy IP ranges from CDN and cloud providers. It periodically updates the IP ranges and makes them available to Caddy's trusted proxies configuration.

The module supports:

  • Built-in providers (Cloudflare, AWS CloudFront, Google Cloud, etc.) from the cdn-ranges library
  • Custom providers with configurable URL endpoints and JMESPath filters
  • Autonomous System Number (ASN) based IP range lookups
  • Both JSON and plain text response formats
  • Separate IPv4 and IPv6 filtering
  • Concurrent fetching for improved performance

Example Caddyfile configuration (short form):

servers {
	trusted_proxies {
		source cdn_ranges {
			interval 24h
			provider cloudflare cloudfront
			concurrency 5
			ipv4 true
			ipv6 true
		}
	}
}

Example with custom provider (block form):

servers {
	trusted_proxies {
		source cdn_ranges {
			provider {
				cloudflare
				custom_cdn {
					ipv4_url https://api.example.com/ipv4.json "prefixes[].cidr"
					ipv6_url https://api.example.com/ipv6.json "prefixes[].cidr"
					asn_list 13335 20940
				}
			}
		}
	}
}

func (CaddyTrustedProxiesCDN) CaddyModule

func (CaddyTrustedProxiesCDN) CaddyModule() caddy.ModuleInfo

func (*CaddyTrustedProxiesCDN) GetIPRanges

func (s *CaddyTrustedProxiesCDN) GetIPRanges(_ *http.Request) []netip.Prefix

func (*CaddyTrustedProxiesCDN) Provision

func (s *CaddyTrustedProxiesCDN) Provision(ctx caddy.Context) error

func (*CaddyTrustedProxiesCDN) UnmarshalCaddyfile

func (m *CaddyTrustedProxiesCDN) UnmarshalCaddyfile(d *caddyfile.Dispenser) error

type Provider

type Provider struct {
	ProviderName string      `json:"name,omitempty"`
	IPv4_URL     *PullConfig `json:"ipv4_url,omitempty"`
	IPv6_URL     *PullConfig `json:"ipv6_url,omitempty"`
	ASNList      []int       `json:"asn_list,omitempty"`
}

func (*Provider) Fetch

func (c *Provider) Fetch(ctx context.Context) ([]string, []string, error)

func (*Provider) Name

func (c *Provider) Name() string

type PullConfig

type PullConfig struct {
	URL      string `json:"url,omitempty"`
	JMESPath string `json:"xpath,omitempty"`
}

func (PullConfig) Fetch

func (u PullConfig) Fetch(ctx context.Context) ([]string, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL