Repository: favonia/cloudflare-ddns
Pull request #947 (2024-09-27 02:43:18)

fix(config): change `local:` to `local.iface:`
#713 @tchar

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/947?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.77%. Comparing base [(`9307c28`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/9307c2897e6c3079fb1ae5043be6bf9e42a2f7f1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) to head [(`84474b3`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/84474b3228fe365a297ca0c4d77ecb5d05d08fef?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main     #947   +/-   ##
=======================================
  Coverage   95.77%   95.77%           
=======================================
  Files          62       62           
  Lines        2817     2817           
=======================================
  Hits         2698     2698           
  Misses        107      107           
  Partials       12       12           
```

| [Flag](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/947/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/947/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | `95.77% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/947?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).


Patch:
diff --git a/README.markdown b/README.markdown
index 0be5195..5bd2dfe 100644
--- a/README.markdown
+++ b/README.markdown
@@ -274,14 +274,14 @@ _(Click to expand the following items.)_
 <details>
 <summary>📍 DNS domains and WAF lists to update</summary>
 
-> You need to specify at least one thing in `DOMAINS`, `IP4_DOMAINS`, `IP6_DOMAINS`, or 🧪 `WAF_LISTS` (since 1.14.0) for the updater to update.
+> You need to specify at least one thing in `DOMAINS`, `IP4_DOMAINS`, `IP6_DOMAINS`, or 🧪 `WAF_LISTS` (since version 1.14.0) for the updater to update.
 
-| Name                          | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
-| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `DOMAINS`                     | Comma-separated fully qualified domain names or wildcard domain names that the updater should manage for both `A` and `AAAA` records. Listing a domain in `DOMAINS` is equivalent to listing the same domain in both `IP4_DOMAINS` and `IP6_DOMAINS`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
-| `IP4_DOMAINS`                 | Comma-separated fully qualified domain names or wildcard domain names that the updater should manage for `A` records                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
-| `IP6_DOMAINS`                 | Comma-separated fully qualified domain names or wildcard domain names that the updater should manage for `AAAA` records                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
-| 🧪 `WAF_LISTS` (since 1.14.0) | 🧪 Comma-separated references of [WAF lists](https://developers.cloudflare.com/waf/tools/lists/custom-lists/) the updater should manage. A list reference is written in the format `<account-id>/<list-name>` where `account-id` is your account ID and `list-name` is the list name; it should look like `0123456789abcdef0123456789abcdef/mylist`. If the referenced WAF list does not exist, the updater will try to create it. 💡 See [how to find your account ID](https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/). 🧪 This feature to manipulate WAF lists is experimental (introduced in 1.14.0). Please [open a GitHub issue](https://github.com/favonia/cloudflare-ddns/issues/new) to provide feedback. Thanks! |
+| Name                                  | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `DOMAINS`                             | Comma-separated fully qualified domain names or wildcard domain names that the updater should manage for both `A` and `AAAA` records. Listing a domain in `DOMAINS` is equivalent to listing the same domain in both `IP4_DOMAINS` and `IP6_DOMAINS`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+| `IP4_DOMAINS`                         | Comma-separated fully qualified domain names or wildcard domain names that the updater should manage for `A` records                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
+| `IP6_DOMAINS`                         | Comma-separated fully qualified domain names or wildcard domain names that the updater should manage for `AAAA` records                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+| 🧪 `WAF_LISTS` (since version 1.14.0) | 🧪 Comma-separated references of [WAF lists](https://developers.cloudflare.com/waf/tools/lists/custom-lists/) the updater should manage. A list reference is written in the format `<account-id>/<list-name>` where `account-id` is your account ID and `list-name` is the list name; it should look like `0123456789abcdef0123456789abcdef/mylist`. If the referenced WAF list does not exist, the updater will try to create it. 💡 See [how to find your account ID](https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/). 🧪 This feature to manipulate WAF lists is experimental (introduced in version 1.14.0). Please [open a GitHub issue](https://github.com/favonia/cloudflare-ddns/issues/new) to provide feedback. Thanks! |
 
 > 🃏🤖 **Wildcard domains** (`*.example.org`) represent all subdomains that _would not exist otherwise._ Therefore, if you have another subdomain entry `sub.example.org`, the wildcard domain is independent of it, because it only represents the _other_ subdomains which do not have their own entries. Also, you can only have one layer of `*`---`*.*.example.org` would not work.
 
@@ -297,23 +297,23 @@ _(Click to expand the following items.)_
 <details>
 <summary>🔍 IP address providers</summary>
 
-| Name           | Meaning                                                                                                                                                                                                                                                                 | Default Value      |
-| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
-| `IP4_PROVIDER` | This specifies how to detect the current IPv4 address. Available providers include `cloudflare.doh`, `cloudflare.trace`, `local`, `local:<iface>`, `url:<URL>`, and `none`. The special `none` provider disables IPv4 completely. See below for a detailed explanation. | `cloudflare.trace` |
-| `IP6_PROVIDER` | This specifies how to detect the current IPv6 address. Available providers include `cloudflare.doh`, `cloudflare.trace`, `local`, `local:<iface>`, `url:<URL>`, and `none`. The special `none` provider disables IPv6 completely. See below for a detailed explanation. | `cloudflare.trace` |
+| Name           | Meaning                                                                                                                                                                                                                                                                       | Default Value      |
+| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
+| `IP4_PROVIDER` | This specifies how to detect the current IPv4 address. Available providers include `cloudflare.doh`, `cloudflare.trace`, `local`, `local.iface:<iface>`, `url:<URL>`, and `none`. The special `none` provider disables IPv4 completely. See below for a detailed explanation. | `cloudflare.trace` |
+| `IP6_PROVIDER` | This specifies how to detect the current IPv6 address. Available providers include `cloudflare.doh`, `cloudflare.trace`, `local`, `local.iface:<iface>`, `url:<URL>`, and `none`. The special `none` provider disables IPv6 completely. See below for a detailed explanation. | `cloudflare.trace` |
 
 > 👉 The option `IP4_PROVIDER` governs `A`-type DNS records and IPv4 addresses in WAF lists, while the option `IP6_PROVIDER` governs `AAAA`-type DNS records and IPv6 addresses in WAF lists. The two options act independently of each other. You can specify different address providers for IPv4 and IPv6.
 
 > 📡 Available IP address providers:
 >
-> | Provider Name                     | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
-> | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-> | `cloudflare.doh`                  | Get the IP address by querying `whoami.cloudflare.` against [Cloudflare via DNS-over-HTTPS](https://developers.cloudflare.com/1.1.1.1/dns-over-https). 🤖 The updater will connect `1.1.1.1` for IPv4 and `2606:4700:4700::1111` for IPv6. Since version 1.9.3, the updater will switch to `1.0.0.1` for IPv4 if `1.1.1.1` appears to be blocked or intercepted by your ISP or your router (which is still not uncommon). Since version 1.14.0, the blockage detection uses a variant of [the Happy Eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to reduce delay. |
-> | `cloudflare.trace`                | Get the IP address by parsing the [Cloudflare debugging page](https://one.one.one.one/cdn-cgi/trace). **This is the default provider.** 🤖 The updater will connect `1.1.1.1` for IPv4 and `2606:4700:4700::1111` for IPv6. Since version 1.9.3, the updater will switch to `1.0.0.1` for IPv4 if `1.1.1.1` appears to be blocked or intercepted by your ISP or your router (which is still not uncommon). Since version 1.14.0, the blockage detection uses a variant of [the Happy Eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to reduce delay.                |
-> | `local`                           | Get the IP address via local network interfaces and routing tables. The updater will use the local address that _would have_ been used for outbound UDP connections to Cloudflare servers. (No data will be transmitted.) ⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater will detect the addresses inside [the default bridge network in Docker](https://docs.docker.com/network/bridge/) instead of those in the host network.                                                         |
-> | 🧪 `local:<iface>` (since 1.15.0) | 🧪 Get the IP address via the specific local network interface `iface`. The updater will choose the first global unicast IP address of the matching IP family (IPv4 or IPv6). ⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater cannot access host network interfaces.                                                                                                                                                                                                                     |
-> | `url:<URL>`                       | Fetch the IP address from a URL. The provider format is `url:` followed by the URL itself. For example, `IP4_PROVIDER=url:https://api4.ipify.org` will fetch the IPv4 address from <https://api4.ipify.org>. Since 1.15.0, the updater will enforce the matching protocol (IPv4 or IPv6) when connecting to the provided URL. Currently, only HTTP(S) is supported.                                                                                                                                                                                                                    |
-> | `none`                            | Stop the DNS updating for the specified IP version completely. For example `IP4_PROVIDER=none` will disable IPv4 completely. Existing DNS records will not be removed. ⚠️ The IP addresses of the disabled IP version will be removed from WAF lists; so `IP4_PROVIDER=none` will remove all IPv4 addresses from all managed WAF lists. 🧪 As the support of WAF lists is experimental, this behavior is subject to changes and please [provide feedback](https://github.com/favonia/cloudflare-ddns/issues/new).                                                                      |
+> | Provider Name                                   | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+> | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+> | `cloudflare.doh`                                | Get the IP address by querying `whoami.cloudflare.` against [Cloudflare via DNS-over-HTTPS](https://developers.cloudflare.com/1.1.1.1/dns-over-https). 🤖 The updater will connect `1.1.1.1` for IPv4 and `2606:4700:4700::1111` for IPv6. Since version 1.9.3, the updater will switch to `1.0.0.1` for IPv4 if `1.1.1.1` appears to be blocked or intercepted by your ISP or your router (which is still not uncommon). Since version 1.14.0, the blockage detection uses a variant of [the Happy Eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to reduce delay. |
+> | `cloudflare.trace`                              | Get the IP address by parsing the [Cloudflare debugging page](https://one.one.one.one/cdn-cgi/trace). **This is the default provider.** 🤖 The updater will connect `1.1.1.1` for IPv4 and `2606:4700:4700::1111` for IPv6. Since version 1.9.3, the updater will switch to `1.0.0.1` for IPv4 if `1.1.1.1` appears to be blocked or intercepted by your ISP or your router (which is still not uncommon). Since version 1.14.0, the blockage detection uses a variant of [the Happy Eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to reduce delay.                |
+> | `local`                                         | Get the IP address via local network interfaces and routing tables. The updater will use the local address that _would have_ been used for outbound UDP connections to Cloudflare servers. (No data will be transmitted.) ⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater will detect the addresses inside [the default bridge network in Docker](https://docs.docker.com/network/bridge/) instead of those in the host network.                                                         |
+> | 🧪 `local.iface:<iface>` (since version 1.15.0) | 🧪 Get the IP address via the specific local network interface `iface`. The updater will choose the first global unicast IP address of the matching IP family (IPv4 or IPv6). ⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater cannot access host network interfaces.                                                                                                                                                                                                                     |
+> | `url:<URL>`                                     | Fetch the IP address from a URL. The provider format is `url:` followed by the URL itself. For example, `IP4_PROVIDER=url:https://api4.ipify.org` will fetch the IPv4 address from <https://api4.ipify.org>. Since version 1.15.0, the updater will enforce the matching protocol (IPv4 or IPv6) when connecting to the provided URL. Currently, only HTTP(S) is supported.                                                                                                                                                                                                            |
+> | `none`                                          | Stop the DNS updating for the specified IP version completely. For example `IP4_PROVIDER=none` will disable IPv4 completely. Existing DNS records will not be removed. ⚠️ The IP addresses of the disabled IP version will be removed from WAF lists; so `IP4_PROVIDER=none` will remove all IPv4 addresses from all managed WAF lists. 🧪 As the support of WAF lists is experimental, this behavior is subject to changes and please [provide feedback](https://github.com/favonia/cloudflare-ddns/issues/new).                                                                      |
 
 </details>
 
@@ -345,12 +345,12 @@ _(Click to expand the following items.)_
 
 > 👉 The updater will preserve existing parameters (TTL, proxy states, DNS record comments, etc.). Only when it creates new DNS records and new WAF lists, the following settings will apply. To change existing parameters, you can go to your [Cloudflare Dashboard](https://dash.cloudflare.com) and change them directly. If you think you have a use case where the updater should actively overwrite existing parameters in addition to IP addresses, please [let me know](https://github.com/favonia/cloudflare-ddns/issues/new). 🐞🧪 **KNOWN ISSUE: comments of stale WAF list items (not WAF lists themselves) will not be kept** because the Cloudflare API does not provide an easy way to update list items. The comments will be lost when the updater deletes stale list items and create new ones.
 
-| Name                                     | Meaning                                                                                                                                                                                                                                                                                      | Default Value                              |
-| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
-| `PROXIED`                                | Whether new DNS records should be proxied by Cloudflare. It can be any boolean value accepted by [strconv.ParseBool](https://pkg.go.dev/strconv#ParseBool), such as `true`, `false`, `0` or `1`. 🤖 Advanced usage: it can also be a domain-dependent boolean expression as described below. | `false`                                    |
-| `TTL`                                    | The time-to-live (TTL) (in seconds) of new DNS records.                                                                                                                                                                                                                                      | `1` (This means “automatic” to Cloudflare) |
-| `RECORD_COMMENT`                         | The [record comment](https://developers.cloudflare.com/dns/manage-dns-records/reference/record-attributes/) of new DNS records.                                                                                                                                                              | `""`                                       |
-| 🧪 `WAF_LIST_DESCRIPTION` (since 1.14.0) | 🧪 The text description of new WAF lists.                                                                                                                                                                                                                                                    | `""`                                       |
+| Name                                             | Meaning                                                                                                                                                                                                                                                                                      | Default Value                              |
+| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
+| `PROXIED`                                        | Whether new DNS records should be proxied by Cloudflare. It can be any boolean value accepted by [strconv.ParseBool](https://pkg.go.dev/strconv#ParseBool), such as `true`, `false`, `0` or `1`. 🤖 Advanced usage: it can also be a domain-dependent boolean expression as described below. | `false`                                    |
+| `TTL`                                            | The time-to-live (TTL) (in seconds) of new DNS records.                                                                                                                                                                                                                                      | `1` (This means “automatic” to Cloudflare) |
+| `RECORD_COMMENT`                                 | The [record comment](https://developers.cloudflare.com/dns/manage-dns-records/reference/record-attributes/) of new DNS records.                                                                                                                                                              | `""`                                       |
+| 🧪 `WAF_LIST_DESCRIPTION` (since version 1.14.0) | 🧪 The text description of new WAF lists.                                                                                                                                                                                                                                                    | `""`                                       |
 
 > 🤖 For advanced users: the `PROXIED` can be a boolean expression involving domains! This allows you to enable Cloudflare proxying for some domains but not the others. Here are some example expressions:
 >
@@ -398,11 +398,11 @@ _(Click to expand the following items.)_
 <details>
 <summary>📣 External notifications (Healthchecks, Uptime Kuma, and shoutrrr)</summary>
 
-| Name                         | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
-| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `HEALTHCHECKS`               | The [Healthchecks ping URL](https://healthchecks.io/docs/) to ping when the updater successfully updates IP addresses, such as `https://hc-ping.com/<uuid>` or `https://hc-ping.com/<project-ping-key>/<name-slug>` ⚠️ The ping schedule should match the update schedule specified by `UPDATE_CRON`. 🤖 The updater can work with _any_ server following the [same Healthchecks protocol](https://healthchecks.io/docs/http_api/), including self-hosted instances of [Healthchecks](https://github.com/healthchecks/healthchecks). Both UUID and Slug URLs are supported, and the updater works regardless whether the POST-only mode is enabled. |
-| `UPTIMEKUMA`                 | The Uptime Kuma’s Push URL to ping when the updater successfully updates IP addresses, such as `https://<host>/push/<id>`. You can directly copy the “Push URL” from the Uptime Kuma configuration page. ⚠️ Remember to change the “Heartbeat Interval” to match the update schedule specified by `UPDATE_CRON`.                                                                                                                                                                                                                                                                                                                                    |
-| 🧪 `SHOUTRRR` (since 1.12.0) | Newline-separated [shoutrrr URLs](https://containrrr.dev/shoutrrr/latest/services/overview/) to which the updater sends notifications of IP address changes and other events. Each shoutrrr URL represents a notification service, such as `discord://<token>@<id>` for Discord.                                                                                                                                                                                                                                                                                                                                                                    |
+| Name                                 | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
+| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `HEALTHCHECKS`                       | The [Healthchecks ping URL](https://healthchecks.io/docs/) to ping when the updater successfully updates IP addresses, such as `https://hc-ping.com/<uuid>` or `https://hc-ping.com/<project-ping-key>/<name-slug>` ⚠️ The ping schedule should match the update schedule specified by `UPDATE_CRON`. 🤖 The updater can work with _any_ server following the [same Healthchecks protocol](https://healthchecks.io/docs/http_api/), including self-hosted instances of [Healthchecks](https://github.com/healthchecks/healthchecks). Both UUID and Slug URLs are supported, and the updater works regardless whether the POST-only mode is enabled. |
+| `UPTIMEKUMA`                         | The Uptime Kuma’s Push URL to ping when the updater successfully updates IP addresses, such as `https://<host>/push/<id>`. You can directly copy the “Push URL” from the Uptime Kuma configuration page. ⚠️ Remember to change the “Heartbeat Interval” to match the update schedule specified by `UPDATE_CRON`.                                                                                                                                                                                                                                                                                                                                    |
+| 🧪 `SHOUTRRR` (since version 1.12.0) | Newline-separated [shoutrrr URLs](https://containrrr.dev/shoutrrr/latest/services/overview/) to which the updater sends notifications of IP address changes and other events. Each shoutrrr URL represents a notification service, such as `discord://<token>@<id>` for Discord.                                                                                                                                                                                                                                                                                                                                                                    |
 
 > ⚠️ If your network does not support IPv6, set `IP6_PROVIDER=none` to disable IPv6 completely. Otherwise, a failure to handle IPv6 will result in the status being reported as _down,_ even if IPv4 records are updated successfully.
 
@@ -421,18 +421,18 @@ _(Click to expand the following items.)_
 
 ⚠️ [oznu/cloudflare-ddns](https://github.com/oznu/docker-cloudflare-ddns) relies on the insecure DNS protocol to obtain public IP addresses; a malicious hacker could more easily forge DNS responses and trick it into updating your domain with any IP address. In comparison, we use only verified responses from Cloudflare, which makes the attack much more difficult. See the [design document](docs/DESIGN.markdown) for more information on security.
 
-| Old Parameter                          |     | Note                                                                                                                                                                                              |
-| -------------------------------------- | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `API_KEY=key`                          | ✔️  | Use `CF_API_TOKEN=key`                                                                                                                                                                            |
-| `API_KEY_FILE=file`                    | ✔️  | Use `CF_API_TOKEN_FILE=file`                                                                                                                                                                      |
-| `ZONE=example.org` and `SUBDOMAIN=sub` | ✔️  | Use `DOMAINS=sub.example.org` directly                                                                                                                                                            |
-| `PROXIED=true`                         | ✔️  | Same (`PROXIED=true`)                                                                                                                                                                             |
-| `RRTYPE=A`                             | ✔️  | Both IPv4 and IPv6 are enabled by default; use `IP6_PROVIDER=none` to disable IPv6                                                                                                                |
-| `RRTYPE=AAAA`                          | ✔️  | Both IPv4 and IPv6 are enabled by default; use `IP4_PROVIDER=none` to disable IPv4                                                                                                                |
-| `DELETE_ON_STOP=true`                  | ✔️  | Same (`DELETE_ON_STOP=true`)                                                                                                                                                                      |
-| `INTERFACE=iface`                      | ✔️  | To automatically select the local address, use `IP4/6_PROVIDER=local`. 🧪 To select the first address of a specific network interface, use `IP4/6_PROVIDER=local:iface` (available since 1.15.0). |
-| `CUSTOM_LOOKUP_CMD=cmd`                | ❌  | Custom commands are not supported because there are no other programs in the minimal Docker image                                                                                                 |
-| `DNS_SERVER=server`                    | ❌  | The updater only supports secure DNS queries using Cloudflare’s DNS over HTTPS (DoH) server. To enable this, set `IP4/6_PROVIDER=cloudflare.doh`.                                                 |
+| Old Parameter                          |     | Note                                                                                                                                                                                                           |
+| -------------------------------------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `API_KEY=key`                          | ✔️  | Use `CF_API_TOKEN=key`                                                                                                                                                                                         |
+| `API_KEY_FILE=file`                    | ✔️  | Use `CF_API_TOKEN_FILE=file`                                                                                                                                                                                   |
+| `ZONE=example.org` and `SUBDOMAIN=sub` | ✔️  | Use `DOMAINS=sub.example.org` directly                                                                                                                                                                         |
+| `PROXIED=true`                         | ✔️  | Same (`PROXIED=true`)                                                                                                                                                                                          |
+| `RRTYPE=A`                             | ✔️  | Both IPv4 and IPv6 are enabled by default; use `IP6_PROVIDER=none` to disable IPv6                                                                                                                             |
+| `RRTYPE=AAAA`                          | ✔️  | Both IPv4 and IPv6 are enabled by default; use `IP4_PROVIDER=none` to disable IPv4                                                                                                                             |
+| `DELETE_ON_STOP=true`                  | ✔️  | Same (`DELETE_ON_STOP=true`)                                                                                                                                                                                   |
+| `INTERFACE=name`                       | ✔️  | To automatically select the local address, use `IP4/6_PROVIDER=local`. 🧪 To select the first address of a specific network interface, use `IP4/6_PROVIDER=local.iface:name` (available since version 1.15.0). |
+| `CUSTOM_LOOKUP_CMD=cmd`                | ❌  | Custom commands are not supported because there are no other programs in the minimal Docker image                                                                                                              |
+| `DNS_SERVER=server`                    | ❌  | The updater only supports secure DNS queries using Cloudflare’s DNS over HTTPS (DoH) server. To enable this, set `IP4/6_PROVIDER=cloudflare.doh`.                                                              |
 
 </details>
 
diff --git a/internal/config/env_provider.go b/internal/config/env_provider.go
index 807c0fa..044e317 100644
--- a/internal/config/env_provider.go
+++ b/internal/config/env_provider.go
@@ -113,17 +113,17 @@ func ReadProvider(ppfmt pp.PP, key, keyDeprecated string, field *provider.Provid
 	case len(parts) == 1 && parts[0] == "local":
 		*field = provider.NewLocal()
 		return true
-	case len(parts) == 2 && parts[0] == "local":
+	case len(parts) == 2 && parts[0] == "local.iface":
 		if parts[1] == "" {
 			ppfmt.Noticef(
 				pp.EmojiUserError,
-				`%s=local: must be followed by a network interface name`,
+				`%s=local.iface: must be followed by a network interface name`,
 				key,
 			)
 			return false
 		}
 		ppfmt.Hintf(pp.HintExperimentalLocalWithInterface,
-			`You are using the experimental provider "local:%s" added in version 1.15.0`,
+			`You are using the experimental provider "local.iface:%s" added in version 1.15.0`,
 			parts[1])
 		*field = provider.NewLocalWithInterface(parts[1])
 		return true
diff --git a/internal/provider/local_iface.go b/internal/provider/local_iface.go
index 2c9f5df..a261626 100644
--- a/internal/provider/local_iface.go
+++ b/internal/provider/local_iface.go
@@ -5,7 +5,7 @@ import "github.com/favonia/cloudflare-ddns/internal/provider/protocol"
 // NewLocalWithInterface creates a protocol.LocalWithInterface provider.
 func NewLocalWithInterface(iface string) Provider {
 	return protocol.LocalWithInterface{
-		ProviderName:  "local:" + iface,
+		ProviderName:  "local.iface:" + iface,
 		InterfaceName: iface,
 	}
 }


Test patch:
diff --git a/internal/config/env_provider_test.go b/internal/config/env_provider_test.go
index 63839dc..6e3ed06 100644
--- a/internal/config/env_provider_test.go
+++ b/internal/config/env_provider_test.go
@@ -155,18 +155,18 @@ func TestReadProvider(t *testing.T) {
 		"cloudflare.doh":   {true, "    \tcloudflare.doh   ", false, "", none, doh, true, nil},
 		"none":             {true, "   none   ", false, "", trace, none, true, nil},
 		"local":            {true, "   local   ", false, "", trace, local, true, nil},
-		"local:lo": {
-			true, "   local   :  lo ", false, "", trace, localLoopback, true,
+		"local.iface:lo": {
+			true, "   local.iface   :  lo ", false, "", trace, localLoopback, true,
 			func(m *mocks.MockPP) {
-				m.EXPECT().Hintf(pp.HintExperimentalLocalWithInterface, `You are using the experimental provider "local:%s" added in version 1.15.0`, "lo") //nolint:lll
+				m.EXPECT().Hintf(pp.HintExperimentalLocalWithInterface, `You are using the experimental provider "local.iface:%s" added in version 1.15.0`, "lo") //nolint:lll
 			},
 		},
-		"local:": {
-			true, "   local: ", false, "", trace, trace, false,
+		"local.iface:": {
+			true, "   local.iface: ", false, "", trace, trace, false,
 			func(m *mocks.MockPP) {
 				m.EXPECT().Noticef(
 					pp.EmojiUserError,
-					`%s=local: must be followed by a network interface name`,
+					`%s=local.iface: must be followed by a network interface name`,
 					key,
 				)
 			},