How can I force Certbot to call the Cloudflare API via IPv4?

When adding/renewing domains via Cloudflare DNS I'm getting the following error.

Error determining zone_id: #### Cannot use the access token from location: [ IPv6 Address ]. Please confirm that you have supplied valid Cloudflare API credentials. (Did you enter a valid Cloudflare Token?)

This is because I've enabled IP restriction on my Cloudflare token but only have a static IPv4 address and Certbot is calling the Cloudflare API via IPv6.

How can I force Certbot to call the Cloudflare API via IPv4?

Hi @PHLAK, and welcome to the LE community forum :slight_smile:

The topic title:
"Force Cloudflare DNS to use IPv4 address?"

doesn't exactly match the actual required request:
"How can I force Certbot to call the Cloudflare API via IPv4?"

And it [topic title] makes this less likely to attract the proper visitors/responses.
I'd replace the title to match that question for best results.

3 Likes

That said, I'm not sure you can't just fix the IPv6 problem and use that path.
Why is CF denying access to you from your IPv6 address?

2 Likes

When configuring a Cloudflare API token you can limit it's access to one or more specific IP addresses. I have a dedicated IPv4 address but my IPv6 address is not static. Therefore I would like to use use my IPv4 address for the IP address filter and force Certbot to only call the Cloudflare API on the IPv4 address.

1 Like

OK, now I understand better.

Can you make it static?

2 Likes

Doesn't your ISP provide something like a /64 specifically routed to your system?

2 Likes

No, my ISP does not provide a static IPv6 address. This is why I would like to force Certbot to use my IPv4 address.

I'd still ask them if you can statically assign your existing IPv6 address.
Then set CF with that IPv6/128 address.

2 Likes

I've already explored this option and it's not an option I have.

So, I looked at the certbot-dns-cloudflare code and it's using Cloudflare's own API library implementation to connect to the API. While that is also open source and you could modify it, it seems like a big nuisance.

I think I would suggest using the netns feature on Linux, which allows you to run a program in a different network environment than other programs on the same system. It is related to containerization but it can be used manually and only affects the program's view of the network configuration.

You can run sudo ip netns add my-no-ipv6-netns (just once per boot) and then sudo ip netns exec my-no-ipv6-netns COMMAND where the COMMAND can be any command, which will run in its own independent copy of the system network configuration. The COMMAND can be commands to manipulate the network configuration by apparently, for example, deleting IPv6 addresses so that the netns has no IPv6 connectivity at all. Then you can do the sudo ip netns exec my-no-ipv6-netns certbot ... to run Certbot in this environment.

I guess you would also need to ensure that your renewals run in the same netns environment with a netns exec. You could make a shell script that wraps the certbot execution with this netns, and then make the renewal jobs point to that instead of the real certbot.

4 Likes

Thanks @schoen, from the sound of it this isn't possible to achieve with Certbot (or certbot-dns-cloudflare). I'll look into netns. My other thought was to see if I could block IPv6 resolution to api.cloudflare.com at the DNS level.

1 Like

@schoen Sounds like a hassle, isn't the following possible?

@PHLAK Is it perhaps possible to list api.cloudflare.com (and perhaps dash.cloudflare.com if needed) in /etc/hosts? And of course only the IPv4 addresses. Of course this would mean the entire process could fail if Cloudflare decides to change the IP addresses of the host(s), but hopefully that doesn't occur often?

Not very future proof, but hey, it's simple :smiley:

3 Likes

Yeah, there are alternative solutions but none of them are ideal.

For the record, the ideal solution (for me anyway) would be having a configuration option (e.g. dns_cloudflare_ip_version=4) we could define in /etc/letsencrypt/cloudflare.ini that would force the request to use a specific IP version. Second best option would be a command flag (e.g. --dns-cloudflare-ipv4). These would allow overriding only Certbot Cloudflare requests without having to make a system-level or network-wide change.

Is it possible to spin up an IPv4 only response DNS server?
[that way the IPv4 address would stay current]
Or exploit local DNS cache to contain only IPv4 addresses for that FQDN...
Like:
dig A api.cloudflare.com
certbot renew
[but something that actually works - LOL]

2 Likes

@rg305 You mean a resolver? Which would resolve the api.cloudflare.com hostname for the host running Certbot?

2 Likes

Yes.

2 Likes

Can't we somehow force Python with requests.packages.urllib3.util.connection.HAS_IPV6 = False and then run certbot.main or something like that? :stuck_out_tongue:

Like, write a very tiny wrapper script?

3 Likes

Not sure if this works...
But it sounds promising:
Linux: Prefer IPv4 over IPv6 in dual-stack environment (and prevent problems when only IPv4 exists) « SF-Alpha o_O! (bjgang.org)

Edit: TESTED and WORKS!

PING api.cloudflare.com(2606:4700:300a::6813:c01d (2606:4700:300a::6813:c01d)) 56 data bytes
64 bytes from 2606:4700:300a::6813:c01d (2606:4700:300a::6813:c01d): icmp_seq=1 ttl=57 time=254 ms

One single change in /etc/gai.conf file:
Take the "#" out from line: #precedence ::ffff:0:0/96 100
vi /etc/gai.conf

PING api.cloudflare.com (104.19.193.29) 56(84) bytes of data.
64 bytes from 104.19.193.29 (104.19.193.29): icmp_seq=1 ttl=54 time=6.44 ms
2 Likes

Hm, but that isn't selective for Certbot only. Prefer IPv4 over IPv6 sounds like a regression to me, worth not looking into.

@PHLAK Another question: you say your IPv4 is static, but your IPv6 is dynamic. HOW dynamic is it actually? E.g., my ISP routes an entire /48 range to my CPE router, so my computers on the internal network can choose out of 1208925819614629174706176 different IP addresses if I wanted to. Isn't it possible you can add a range to Cloudflares IP restrictions? It would make sense and it would also make sense you have your own "static" IPv6 range for your internet connection.

Hm, looking at my own Cloudflare dashboard at my tokens, it says:

Client IP Address Filtering

Select IP addresses or ranges of IP addresses to filter.

And when I add my /48 (in the form of 2001:db8:ef01::/48) it works nicely :slight_smile:

5 Likes

The /etc/gai.conf file can be easily overwritten temporarily to induce the IPv4 preference only for certbot renewals.

And I also agree that it sounds strange that the ISP isn't routing some /64 [or thereabouts] to his equipment.

3 Likes