CF_SINGLE_REDIRECT fixes

This commit is contained in:
Thomas Limoncelli 2025-12-04 15:46:29 -05:00
parent e05667e5ac
commit 7460d164e0
No known key found for this signature in database
5 changed files with 31 additions and 36 deletions

View file

@ -12,14 +12,14 @@ parameter_types:
--- ---
{% hint style="warning" %} {% hint style="warning" %}
WARNING: Cloudflare is removing this feature and replacing it with a new **WARNING:** Cloudflare is removing this feature and replacing it with a new
feature called "Dynamic Single Redirect". DNSControl will automatically feature called "Dynamic Single Redirect". DNSControl will automatically
generate "Dynamic Single Redirects" for a limited number of use cases. See generate "Dynamic Single Redirects" for a limited number of use cases. See
[`CLOUDFLAREAPI`](../../provider/cloudflareapi.md) for details. [`CLOUDFLAREAPI`](../../provider/cloudflareapi.md) for details.
{% endhint %} {% endhint %}
`CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to `CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page
generate a HTTP 301 permanent redirect. Rules) to generate a HTTP 301 permanent redirect.
If _any_ `CF_REDIRECT` or [`CF_TEMP_REDIRECT`](CF_TEMP_REDIRECT.md) functions are used then If _any_ `CF_REDIRECT` or [`CF_TEMP_REDIRECT`](CF_TEMP_REDIRECT.md) functions are used then
`dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain. `dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain.

View file

@ -16,30 +16,42 @@ parameter_types:
--- ---
`CF_SINGLE_REDIRECT` is a Cloudflare-specific feature for creating HTTP redirects. 301, 302, 303, 307, 308 are supported. `CF_SINGLE_REDIRECT` is a Cloudflare-specific feature for creating HTTP redirects. 301, 302, 303, 307, 308 are supported.
Typically one uses 302 (temporary) or (less likely) 301 (permanent). Typically one uses 302 (temporary) or 301 (permanent).
This feature manages dynamic "Single Redirects". (Single Redirects can be This feature manages dynamic "Single Redirects". (Single Redirects can be
static or dynamic but DNSControl only maintains dynamic redirects). static or dynamic but DNSControl only maintains dynamic redirects).
DNSControl will delete any "single redirects" it doesn't recognize (i.e. ones created via the web UI) so please be careful.
Cloudflare documentation: <https://developers.cloudflare.com/rules/url-forwarding/single-redirects/> Cloudflare documentation: <https://developers.cloudflare.com/rules/url-forwarding/single-redirects/>
{% code title="dnsconfig.js" %} {% code title="dnsconfig.js" %}
```javascript ```javascript
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
CF_SINGLE_REDIRECT("name", 302, "when", "then"),
CF_SINGLE_REDIRECT('redirect www.example.com', 302, 'http.host eq "www.example.com"', 'concat("https://otherplace.com", http.request.uri.path)'), CF_SINGLE_REDIRECT('redirect www.example.com', 302, 'http.host eq "www.example.com"', 'concat("https://otherplace.com", http.request.uri.path)'),
CF_SINGLE_REDIRECT('redirect yyy.example.com', 302, 'http.host eq "yyy.example.com"', 'concat("https://survey.stackoverflow.co", "")'), CF_SINGLE_REDIRECT('redirect yyy.example.com', 302, 'http.host eq "yyy.example.com"', 'concat("https://survey.stackoverflow.co", "")'),
CF_TEMP_REDIRECT("*example.com/*", "https://contests.otherexample.com/$2"),
); );
``` ```
{% endcode %} {% endcode %}
The fields are: The fields are:
* name: The name (basically a comment, but it must be unique) * name: The name (basically a comment)
* code: Any of 301, 302, 303, 307, 308. May be a number or string. * code: Any of 301, 302, 303, 307, 308. May be a number or string.
* when: What Cloudflare sometimes calls the "rule expression". * when: What Cloudflare sometimes calls the "rule expression".
* then: The replacement expression. * then: The replacement expression.
{% hint style="info" %} DNSControl does not currently choose the order of the rules. New rules are
**NOTE**: The features [`CF_REDIRECT`](CF_REDIRECT.md) and [`CF_TEMP_REDIRECT`](CF_TEMP_REDIRECT.md) generate `CF_SINGLE_REDIRECT` if enabled in [`CLOUDFLAREAPI`](../../provider/cloudflareapi.md). added to the end of the list. Use Cloudflare's dashboard to re-order the rule,
{% endhint %} DNSControl should not change them. (In the future we hope to add a feature
where the order the rules appear in dnsconfig.js is maintained in the
dashboard.)
## `CF_REDIRECT` and `CF_TEMP_REDIRECT`
`CF_REDIRECT` and `CF_TEMP_REDIRECT` used to manage Cloudflare Page Rules.
However that feature is going away. To help with the migration, DNSControl now
translates those commands into CF_SINGLE_REDIRECT equivalents. The conversion
process is a transpiler that only understands certain formats. Please submit
a Github issue if you find something it can't handle.

View file

@ -12,7 +12,7 @@ parameter_types:
--- ---
{% hint style="warning" %} {% hint style="warning" %}
**WARNING**: Cloudflare is removing this feature and replacing it with a new **WARNING:** Cloudflare is removing this feature and replacing it with a new
feature called "Dynamic Single Redirect". DNSControl will automatically feature called "Dynamic Single Redirect". DNSControl will automatically
generate "Dynamic Single Redirects" for a limited number of use cases. See generate "Dynamic Single Redirects" for a limited number of use cases. See
[`CLOUDFLAREAPI`](../../provider/cloudflareapi.md) for details. [`CLOUDFLAREAPI`](../../provider/cloudflareapi.md) for details.
@ -21,9 +21,9 @@ generate "Dynamic Single Redirects" for a limited number of use cases. See
`CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page `CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page
Rules) to generate a HTTP 302 temporary redirect. Rules) to generate a HTTP 302 temporary redirect.
If _any_ [`CF_REDIRECT`](CF_REDIRECT.md) or `CF_TEMP_REDIRECT` functions are used then If _any_ [`CF_REDIRECT`](CF_REDIRECT.md) or `CF_TEMP_REDIRECT functions are used then
`dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain. `dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain.
Page Rule types other than "Forwarding URL will be left alone. Page Rule types other than "Forwarding URL" will be left alone.
{% hint style="warning" %} {% hint style="warning" %}
**WARNING**: Cloudflare does not currently fully document the Page Rules API and **WARNING**: Cloudflare does not currently fully document the Page Rules API and
@ -33,10 +33,13 @@ backups and manually verifying `dnscontrol preview` output before running
managed by DNSControl and those that aren't. managed by DNSControl and those that aren't.
{% endhint %} {% endhint %}
This example redirects the bare (aka apex, or naked) domain to www:
{% code title="dnsconfig.js" %} {% code title="dnsconfig.js" %}
```javascript ```javascript
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
CF_TEMP_REDIRECT("example.example.com/*", "https://otherplace.yourdomain.com/$1"), CF_TEMP_REDIRECT("example.com/*", "https://www.example.com/$1"),
); );
``` ```
{% endcode %} {% endcode %}

View file

@ -379,7 +379,7 @@ func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr cfsingler
return fmt.Errorf("failed fetching redirect rule list cloudflare: %w", err) return fmt.Errorf("failed fetching redirect rule list cloudflare: %w", err)
} }
newSingleRedirect.Rules = newSingleRedirectRules newSingleRedirect.Rules = newSingleRedirectRules
newSingleRedirect.Rules = append(newSingleRedirect.Rules, rules.Rules...) newSingleRedirect.Rules = append(rules.Rules, newSingleRedirect.Rules...)
_, err = c.cfClient.UpdateEntrypointRuleset(context.Background(), cloudflare.ZoneIdentifier(domainID), newSingleRedirect) _, err = c.cfClient.UpdateEntrypointRuleset(context.Background(), cloudflare.ZoneIdentifier(domainID), newSingleRedirect)

View file

@ -2,7 +2,6 @@ package cfsingleredirect
import ( import (
"fmt" "fmt"
"sync"
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags" "github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
@ -67,9 +66,8 @@ func FromArgs_helper(dcn *domaintags.DomainNameVarieties, rec *models.RecordConf
return err return err
} }
// Create the old-school name with a count prefix. // Create a rule name:
incRedirCount(dcn.UniqueName) name := fmt.Sprintf("%03d,%s,%s", code, prWhen, prThen)
name := fmt.Sprintf("%03d,%03d,%s,%s", getRedirCount(dcn.UniqueName), code, prWhen, prThen)
sr := SingleRedirectConfig{} sr := SingleRedirectConfig{}
rec.Type = sr.Name() // This record is now a CLOUDFLAREAPI_SINGLE_REDIRECT rec.Type = sr.Name() // This record is now a CLOUDFLAREAPI_SINGLE_REDIRECT
@ -80,21 +78,3 @@ func FromArgs_helper(dcn *domaintags.DomainNameVarieties, rec *models.RecordConf
return nil return nil
} }
// The legacy system prepended a count to the name to coordinate ordering.
var redirCount = map[string]int{}
var redirCountMutex = sync.RWMutex{}
func incRedirCount(name string) {
redirCountMutex.Lock()
defer redirCountMutex.Unlock()
redirCount[name]++
}
func getRedirCount(name string) int {
redirCountMutex.Lock()
defer redirCountMutex.Unlock()
return redirCount[name]
}