DEV Community

Cover image for Your redirect rule says Active and nothing happens
301ST
301ST

Posted on Originally published at 301.sh

Your redirect rule says Active and nothing happens

The rule is in the list. Its toggle says Active. You open the URL and the old page loads, exactly as before. Nothing in the dashboard suggests a problem, because nothing in the dashboard is wrong: Active means the rule was saved and is eligible to run. It says nothing about whether a request ever reached it.

That gap is the whole diagnosis. Four questions close it, in this order, and each one is answered by a single request rather than by another look at the configuration. We ran every check in this article against a live free-plan zone on 17 August 2026, including the ones whose answer is "the rule does not fire" — those are the useful ones. If you are still choosing a method, the comparison of every way to redirect on Cloudflare is the map; this is what to do when the method you picked appears to do nothing.

Question one: does the request reach your zone at all

Every other explanation assumes Cloudflare saw the request. Check that first, and check it with a rule rather than with a header, because a rule is the thing whose absence you are diagnosing.

Add a temporary redirect rule on a path that nothing on your site serves, matching exactly, and point it anywhere:

(http.request.uri.path eq "/zone-probe-9f3")
Enter fullscreen mode Exit fullscreen mode

Then ask for it:

curl -sI "https://your-domain/zone-probe-9f3" | head -1
Enter fullscreen mode Exit fullscreen mode

A 302 means your zone terminated that request and your rules run. A 404 from your own application, or anything else your origin would say, means they do not — and no amount of editing the redirect rule will change that. On our zone the probe went from 404 before the rule to 302 about three seconds after it was created, and back to 404 after it was deleted, though the deletion took longer to reach every edge server than the creation did. A first response is not evidence in either direction; ask twice.

If the probe stays negative, there are three ways to be outside your own zone, and they look identical from the dashboard.

The record is not proxied. Cloudflare states the requirement plainly:

Single Redirects and Bulk Redirects require that you proxy the DNS records of your domain (or subdomain) through Cloudflare.

A grey cloud means DNS only: visitors get your origin's address and connect to it directly. There is a warning for this, but it is narrow. The dashboard raises This rule may not apply to your traffic only when your expression names a hostname that has no proxied record. A rule written as http.request.uri.path eq "/" names no hostname, so it saves in silence.

The zone never activated. If the nameservers at the registrar were never switched, the zone sits pending and everything you configured is real but not live. That failure has its own signature and its own article on silent redirect failures.

Your host is on Cloudflare too. This is the one that fools people, because everything on your side looks right. If your hostname is onboarded to a platform that uses Cloudflare for SaaS, the arrangement Cloudflare calls Orange-to-Orange decides whose rules run, and it has exact conditions: the record must be a CNAME to the provider's target, it must be proxied in your zone, and the two zones must be in different accounts. When that holds, your zone is first in line and your rules do run. When it does not hold — an A record to the provider's address, or no zone of your own — the provider's zone is the only one applying settings, and your redirect rule is a note in a file nobody reads. There is no flag to check: Cloudflare's documentation says outright that no API field or zone setting reports whether Orange-to-Orange is active.

Two traps around this check. https://your-domain/cdn-cgi/trace proves you are behind a Cloudflare, not behind yours, so it cannot settle the question — and we confirmed the flip side, that a redirect rule matching /cdn-cgi/trace does not fire at all, leaving that endpoint honest. And zone analytics showing traffic proves the hostname resolves somewhere in your account's view, not that this request was evaluated by your ruleset.

The dashboard's own confirmation is Cloudflare Trace, in beta and on every plan. It simulates a request and lists the configurations that matched, in evaluation order. Its input has the hint built in: the URL "must include a hostname that belongs to your account". If Trace will not accept the hostname, the answer to question one is no. Note that Trace runs against your configuration, not against live traffic, so it cannot see the routing problem itself — only the probe request can. The API route for it exists, but it is scoped separately; a token that can create and delete redirect rules got Authentication error from it.

Question two: does the rule match what you are actually sending

This is where most of the time goes, and where one behaviour accounts for more of it than everything else combined.

A wildcard pattern is compared against the entire URL, query string included. Cloudflare's operator documentation says so in an example: a request to https://sub.example.com/folder2/page.html?s=value does not match *.example.com/*/page.html because "http.request.full_uri includes the query string and its full value does not match". Stated as a rule you can act on: a wildcard pattern that does not end in * will never match a request that carries a query string. Which is exactly what happens when you test the rule by adding ?v=2 to defeat your browser cache. The cache-buster defeats the rule instead, the page loads normally, and you conclude the rule is broken.

Here is that pair, measured, along with the rest of the matching behaviour worth knowing:

Rule Request Result
wildcard https://301.sh/rule-probe/*.html /rule-probe/x.html 302
same rule /rule-probe/x.html?v=2 404, no redirect
same rule /rule-probe/deep/x.html 302* crosses slashes
same rule /rule-probe/x.HTML 302wildcard ignores case
http.request.uri.path eq "/Rule-Probe-Case" /Rule-Probe-Case 302
same rule /rule-probe-case 404, eq is case-sensitive
http.request.uri.path eq "/rule-probe-slash" /rule-probe-slash/ 404, the slash is part of the path

The case row is worth a second look, because the two interfaces disagree. The wildcard operator is case-insensitive by documentation and by measurement; strict wildcard is the case-sensitive variant. But eq on a path compares strings, so a rule typed with capitals from a design document quietly matches nothing that visitors send.

Bulk Redirects have a different matching algorithm, and the difference cuts the other way. A bulk redirect matches on scheme, hostname and path only — the query string takes no part in matching at all, so the cache-buster that kills a wildcard rule is irrelevant here. What substitutes for it is defaults: Subpath matching and Include subdomains are both off unless you turned them on, so /blog does not cover /blog/post, and example.com does not cover www.example.com. And a list on its own does nothing. Cloudflare checks the redirects of each list "that is enabled by a Bulk Redirect Rule" — uploading a list and never creating the rule that switches it on is a complete, silent no-op.

Question three: did something answer before your rule got its turn

Rules products run in a fixed order, and a redirect is a terminating action. Cloudflare puts it without hedging:

for terminating actions (Block, Redirect, or one of the challenge actions), rule evaluation will stop and the action will be executed immediately

Three consequences, one of which we measured. Two redirect rules matching the same request: the first one wins, always — we deployed a pair pointing at different targets, and the answer carried the target of the first. Single Redirects run before Bulk Redirects in the product order, so when both have a rule for a URL, the Single Redirect is the one that answers. And Page Rules, if you still have them, lose to all of it: the modern rules products "take precedence over Page Rules". An old forwarding Page Rule is not what is fighting your new rule. It is what runs when your new rule does not match — which produces the more confusing symptom of a redirect happening to somewhere you did not configure.

The same phase order is why a redirect cannot be counted at the edge that issues it, which is its own article.

Question four: did it fire while you looked at a cached answer

A redirect that works is easy to hide. A 301 is a permanent redirect, and Cloudflare's rules send it without a Cache-Control header, so a browser may cache it heuristically and keep sending you to the old target long after the rule changed. The reverse also holds: a browser that once got a 200 for that URL can go on serving it from cache while the edge is redirecting everyone else. Test with curl -sI, which caches nothing, before you test with a browser tab.

And when you do reach for a cache-buster, remember question two: appending ?v=2 changes whether a wildcard rule matches. The standard advice for making a browser fetch fresh is the standard way to make this particular test lie. Use a private window, a different browser, or curl — not a query parameter.

When the redirect was never Cloudflare's to run

One case belongs outside the tree. If the redirect lives at your origin — a rewrite in .htaccess, a framework route — then Cloudflare has no rule to fire and nothing to trace. It forwards whatever the origin says, and the origin can be inconsistent in ways that are invisible from the dashboard. A report in July described exactly that: the same URL answering 301 when proxied through one Cloudflare datacenter and 200 when proxied through another, with the origin returning a clean 301 on a direct request every time. Whatever the cause, the fix is structural. A redirect expressed as an edge rule answers before the origin is contacted, so it cannot vary with what the origin decides to do that second.

Where this gets untidy

A rule whose target equals its source produces a loop, and Cloudflare does not stop it. We pointed a rule at its own path and followed the chain: six hops in, still redirecting to itself. A browser calls that too many redirects; a monitoring check may call it a 302 and pass.

Free zones get 10 Single Redirect rules, and the quota is per zone. Hitting it fails at creation rather than at runtime, so it is not a cause of this symptom — but it is a reason people put logic into one wildcard rule, where the query-string behaviour above starts to bite. The full quota table sits in the article on redirect limits.

Trace does not evaluate inactive rules, which is correct and occasionally misleading: a rule switched off looks the same in Trace results as a rule that did not match. And Trace reflects configuration, so a request that never reaches your zone traces perfectly while failing in production. That is why question one comes first and is answered with a real request.

What this costs across a portfolio

For one domain, this is a ten-minute job. Two curl calls and a temporary rule tell you which of the four questions is the wrong one, and the fix follows from the answer.

The arithmetic changes when the same question has to be asked of two hundred domains that nobody opened this month, because none of these failures announce themselves. A rule that stopped matching after a platform migration looks exactly like a rule that works, from the inside. That is the case for asking every domain the same question on a schedule — the loop from the audit script if you like scripts, and 301.st if you would rather the portfolio be watched continuously and tell you when a row changes. For a handful of domains, the script and a cron entry are genuinely enough.

Top comments (0)