Documentation Index

Fetch the complete documentation index at: https://docs.darwinium.com/llms.txt

Use this file to discover all available pages before exploring further.

Working with multi-chained redirects

Prev Next

Applies to: CloudFront, Cloudflare and Akamai edge deployments
Config file: journeys.yaml (build target configuration)
Audience: Customers running Darwinium behind additional proxies, or with their own edge workers, where requests pass through more than one hop before reaching the origin.

When Darwinium runs at your CDN edge, it inspects and (for proxy steps) forwards each request on toward your origin. In a simple deployment that is a single hop. But real-world edge topologies are rarely a single hop:

  • You may sit another reverse proxy or CDN in front of the CDN that Darwinium is deployed on (e.g. browser → your reverse proxy → CloudFront).
  • Darwinium itself introduces an internal redirect loopback when it proxies a request, so a single logical request can traverse the edge more than once.
  • You may already run your own edge workers (Lambda@Edge, CloudFront Functions, Cloudflare Workers, Akamai EdgeWorkers) that must keep running alongside Darwinium.

Two journeys.yaml settings exist to make Darwinium behave correctly in these multi-hop, "multi-chained redirect" topologies:

Setting What it controls
trusted_proxy_count How Darwinium resolves the true client IP from X-Forwarded-For when trusted proxies sit in front of it.
customer_worker_mode How Darwinium relocates and preserves your own edge workers when it inserts its redirect path.

Example target using both:

- name: cloudfront
  type: cloudfront
  enabled: true
  trusted_proxy_count: 2
  customer_worker_mode: origin_to_redirect_path

Background: how a request chains through the edge

Before tuning either setting, it helps to see the hops a request actually takes. Below is a Darwinium proxy step deployment on CloudFront (the most chained of the three CDNs, because Lambda@Edge splits each request into a viewer-request and an origin-request phase).

Multi-chained redirect flow on CloudFront: the client request enters the CloudFront edge, passes through Darwinium's viewer-request worker then origin-request worker, loops back through the internal /dwn_redirect path, fetches your origin, and returns an enriched response to the client.

The internal /dwn_redirect<path> loopback (step 3) is the "redirect" in multi-chained redirects. It is how Darwinium re-enters the edge to fetch your origin in a controlled way. This is the default behaviour (fetch_origin_directly: false) and is where customer_worker_mode becomes relevant — because your origin workers need to travel to the right place in this chain.

Every proxy hop that forwards the request also appends the caller's IP to X-Forwarded-For, which is where trusted_proxy_count becomes relevant.


trusted_proxy_count

What it does

X-Forwarded-For (XFF) is a comma-separated list that grows left-to-right as a request passes through proxies:

X-Forwarded-For: <original-client>, <proxy-1>, <proxy-2>, ..., <proxy-N>

The leftmost entry claims to be the original client — but that end of the list is client-controlled and can be spoofed. A browser can send whatever it likes as the first entry. Only the entries appended by proxies you actually control can be trusted.

trusted_proxy_count tells Darwinium how many trusted proxies sit in front of it, so it can walk in from the right (trusted) end of the list and pick out the genuine client IP rather than a spoofable one.

How trusted_proxy_count resolves the true client IP: given X-Forwarded-For with a spoofable client entry followed by two trusted proxy entries, trusted_proxy_count = 2 makes Darwinium walk in from the right and select the second-from-right entry as the true client IP.

The rule: with trusted_proxy_count = N, Darwinium treats the Nth entry counting from the right (1-based) as the true client IP.

  • N = 1 → rightmost entry (the address that connected directly to the CDN edge).
  • N = 2 → second-from-right, and so on.

Set N to the number of trusted proxy hops that exist between the real client and the point where Darwinium reads the header. In practice that means: count the reverse proxies / CDNs you have placed in front of the CDN that Darwinium is deployed on.

Default

If omitted, trusted_proxy_count defaults to 0. With 0, Darwinium does not derive the client IP from X-Forwarded-For; it uses the CDN-native client IP instead (see per-CDN behaviour below). For the majority of deployments — where the client connects straight to the CDN with no proxy in front — 0 is correct and you do not need to set this at all.

When to set it

Set trusted_proxy_count when you have deliberately placed one or more proxies in front of the CDN, e.g.:

browser ──► your reverse proxy ──► CloudFront (Darwinium) ──► origin
            └──────── 1 trusted proxy in front ────────┘

trusted_proxy_count: 1
browser ──► WAF/proxy A ──► WAF/proxy B ──► CloudFront (Darwinium) ──► origin
            └───────────── 2 trusted proxies ─────────────┘

trusted_proxy_count: 2

You only count the proxies you add. Darwinium automatically accounts for its own internal hops at the edge (including the CloudFront viewer-request → origin-request transition). You do not need to add to the count for Darwinium's own redirect loopback.

Getting the number wrong

Misconfiguration Result
Too high (count exceeds the real number of trusted proxies) Darwinium walks too far left into the client-controlled part of the list. If the list is shorter than the count, client-IP extraction is abandoned entirely (no IP resolved). If it reaches a spoofable position, the "client IP" becomes attacker-controlled.
Too low Darwinium stops too close to the edge and resolves the client IP to one of your own proxy/infrastructure addresses instead of the real visitor — collapsing IP-based signals and velocities.

Because a wrong value silently degrades every IP-derived signal (geo, ASN, IP velocities, connection risk), validate it after configuring — see Verifying.

Validation

trusted_proxy_count must be a non-negative integer. A non-numeric value fails the journey load. There is no upper bound enforced, so an unrealistically large value will not be rejected — it will simply produce the "too high" behaviour above.


How each CDN supplies the client IP

trusted_proxy_count only participates in the X-Forwarded-For code path. Each CDN has a different notion of "the client IP", which changes when — and whether — trusted_proxy_count applies.

CDN Header Darwinium trusts for the client IP Does trusted_proxy_count apply?
CloudFront X-Forwarded-For (with the AWS-provided client IP as the seed) Yes — this is the main place it matters. Darwinium also auto-adjusts for its own viewer-request → origin-request hop, so you count only your own proxies.
Cloudflare CF-Connecting-IP No for the primary IP — CF-Connecting-IP is authoritative and X-Forwarded-For is bypassed for client-IP resolution.
Akamai (& Linode) True-Client-IP (configurable; defaults to True-Client-IP) No for the primary IP — the client IP arrives in True-Client-IP via a header extraction rule.

Practical guidance:

  • CloudFront — this is the deployment type where trusted_proxy_count does real work. If you have proxies in front of CloudFront, set it to the number of those proxies. Darwinium already compensates for CloudFront's own viewer-request → origin-request hop internally, so exclude that from your count.

  • Cloudflare — the trusted, edge-populated CF-Connecting-IP header is used for the client IP, so X-Forwarded-For (and therefore trusted_proxy_count) does not drive primary client-IP resolution. Cloudflare's CF-Connecting-IPv6 is deliberately not trusted as the client IP (it can be spoofed when Cloudflare's Pseudo-IPv4 feature is disabled); Darwinium records only that it was present.

  • Akamai — the real client IP is delivered in True-Client-IP by an Akamai header rule (this is the default header; it is configurable on Linode-backed deployments). As with Cloudflare, X-Forwarded-For is not the primary source, so trusted_proxy_count is not the lever here — ensure your Akamai property is configured to send True-Client-IP (see Akamai Deployment).

If you front Cloudflare or Akamai with your own extra proxy, the correct client IP still arrives in CF-Connecting-IP / True-Client-IP respectively (those headers are set by the CDN edge to the address that connected to it). Chained-proxy client-IP correction via trusted_proxy_count is a CloudFront/X-Forwarded-For concern.


customer_worker_mode

What it does

Darwinium becomes the primary worker invoked on a route, but it is designed to never stop your existing edge functions from running (see the "We already have edge functions in place" entry in CDN Deployment Q&A). customer_worker_mode controls where your own workers are attached once Darwinium inserts its redirect path into the request chain.

This setting is primarily relevant to CloudFront (Lambda@Edge / CloudFront Functions), where Darwinium's redirect loopback creates the internal /dwn_redirect<path> route that your origin workers may need to move onto.

The three modes

Value Meaning
no No customer worker is attached to the Darwinium route. Use this only when there are no pre-existing workers to preserve, or you explicitly manage them yourself.
direct_binding Your existing origin workers are bound directly alongside Darwinium's origin-request handler, on the same (real) path. This is the default for most deployments and preserves your workers in place.
origin_to_redirect_path Your origin-request / origin-response workers are relocated onto Darwinium's internal /dwn_redirect<path>, so they run at the correct point in the multi-chained redirect flow rather than on the real path. Use this when the redirect loopback would otherwise cause your origin workers to run at the wrong hop.

Default

If customer_worker_mode is omitted from a target, it defaults to direct_binding.

Note: an unrecognised value does not fail the load — it silently falls back to direct_binding. Always confirm the deployed mode after changing this setting (the value is echoed in the deployment logs) so a typo doesn't leave you on the default unexpectedly.

Choosing a mode

Decision tree for customer_worker_mode: if you have no workers to preserve, use no; if you do and they run correctly on the real origin path alongside Darwinium, use direct_binding; if they must instead run at the redirect / origin-fetch hop, use origin_to_redirect_path.

The visual difference in where your worker ends up — with direct_binding it stays on the real path alongside Darwinium, and with origin_to_redirect_path it is relocated onto the internal /dwn_redirect path:

Worker placement comparison: under direct_binding, YOUR origin worker runs on the real /checkout path alongside the Darwinium origin-request worker; under origin_to_redirect_path, it is moved off the real path and relocated onto the internal /dwn_redirect/checkout path where it runs at the redirect hop.

Constraint: origin_to_redirect_path requires the redirect loopback

origin_to_redirect_path cannot be combined with fetch_origin_directly: true. When fetch_origin_directly is enabled, Darwinium fetches your origin directly and no /dwn_redirect path exists to relocate your workers onto, so the combination is rejected at journey load with an error. If you need origin_to_redirect_path, leave fetch_origin_directly at its default (false).

fetch_origin_directly origin_to_redirect_path allowed?
false (default — redirect loopback in use) ✅ Yes
true (origin fetched directly, no loopback) ❌ No — journey load fails

Per-CDN notes

  • CloudFront — full support for all three modes as described above; this is where the setting does its work, because Lambda@Edge functions are cloned/relocated across the real path and the /dwn_redirect path during deploy, and restored on undeploy.
  • Cloudflare — pre-existing Workers are preserved as a service binding on Darwinium's worker (see CDN Deployment Q&A), a different mechanism from CloudFront's path relocation. Keep the default unless directed otherwise by Darwinium support.
  • Akamai — EdgeWorker preservation is handled through the Akamai property/rule configuration (see Akamai Deployment); this CloudFront-oriented mode setting is not the primary lever on Akamai.

Putting it together: worked examples

1. Plain CloudFront, client connects directly (most common)

browser ──► CloudFront (Darwinium) ──► origin
- name: cloudfront
  type: cloudfront
  enabled: true
  # trusted_proxy_count omitted -> 0 (client IP from CloudFront/XFF edge, no extra proxies)
  # customer_worker_mode omitted -> direct_binding (your workers preserved in place)

2. CloudFront behind one reverse proxy, with your own origin workers on the redirect path

browser ──► your reverse proxy ──► CloudFront (Darwinium) ──► origin
            └─── 1 trusted proxy ───┘
- name: cloudfront
  type: cloudfront
  enabled: true
  trusted_proxy_count: 1              # one proxy you placed in front of CloudFront
  customer_worker_mode: origin_to_redirect_path

3. CloudFront behind two proxies (as in the header example)

browser ──► proxy A ──► proxy B ──► CloudFront (Darwinium) ──► origin
            └────── 2 trusted proxies ──────┘
- name: cloudfront
  type: cloudfront
  enabled: true
  trusted_proxy_count: 2
  customer_worker_mode: origin_to_redirect_path

4. Cloudflare (client IP already correct via CF-Connecting-IP)

- name: cloudflare
  type: cloudflare
  enabled: true
  # trusted_proxy_count not needed - CF-Connecting-IP is authoritative
  # existing Workers preserved via service binding

Verifying your configuration

After deploying, confirm the client IP is resolving to the real visitor and not a proxy:

  1. Send a test request through the full chain (all your front proxies + the CDN), from a known source IP.
  2. In the Darwinium Portal, open the resulting journey/event and inspect the resolved client IP / connection signals.
  3. Confirm:
    • The client IP matches your real test source, not one of your proxy or CDN infrastructure addresses (→ trusted_proxy_count too low if it shows a proxy).
    • The IP is present and stable (→ trusted_proxy_count too high if it is missing or nonsensical).
  4. Confirm any of your own edge workers still execute (check their side effects / logs). If they don't fire, revisit customer_worker_mode.
  5. Check the deployment logs — the applied customer worker mode is echoed there, so you can confirm the mode that actually deployed (guarding against a silent fallback from a typo).

See also Deployment Confirmation and Troubleshooting Deployments.


Quick reference

Setting Values Default Applies to Notes
trusted_proxy_count non-negative integer 0 CloudFront / any X-Forwarded-For chain Number of trusted proxies you place in front of the CDN. Not used for the primary IP on Cloudflare (CF-Connecting-IP) or Akamai (True-Client-IP). Darwinium auto-compensates for its own internal edge hops.
customer_worker_mode no, direct_binding, origin_to_redirect_path direct_binding Primarily CloudFront origin_to_redirect_path requires fetch_origin_directly: false. Unrecognised values silently fall back to direct_binding.
type cloudfront, cloudfront_npm, cloudflare, akamai, aws_outpost cloudflare Selects the CDN deployment target.
fetch_origin_directly true / false false CloudFront false keeps the /dwn_redirect loopback (required for origin_to_redirect_path).

Related: CloudFront Deployment, Cloudflare Deployment, Akamai Deployment, CDN Deployment Q&A, Edge Integration Technical Design → Overview.