certbot icon indicating copy to clipboard operation
certbot copied to clipboard

[Feature Request]: IP address subjectAlternativeName certificates

Open jsha opened this issue 6 months ago • 5 comments

What problem does this feature solve or what does it enhance?

Let's Encrypt will offer certificates with IP address SANs sometime in 2025. We should discuss what we'd like to do in Certbot in terms of supporting them.

Support for identifiers with "type": "ip" is already landed in acme, including in make_csr. So we only need to add support on the Certbot CLI side.

For storing lineages, when all identifiers on a certificate are IP addresses, we need to make sure we can pick a name for the lineage based on an IP address. For IPv4 addresses this should be straightforward. For IPv6 addresses, which contain colons, there will be some filesystem compatibility issues on Windows. For those, we should replace colons with - (or some other character).

For solving challenges: Only HTTP-01 and TLS-ALPN-01 are allowed, per BRs. There's no DNS-01 challenge defined for IP address certificates, because there's no place in the DNS that proves control of an IP address.

We've deprecated TLS-ALPN-01 support so that leaves us only needing to worry about HTTP-01 support.

Supporting HTTP-01 in the standalone plugin should be straightforward, and may already work by default, if the standalone server isn't checking the Host header. Similarly, the webroot plugin should Just Work, assuming the user has a path that is served when a request is made by IP address (usually this will be the default virtualhost).

For the Apache and Nginx plugins, it gets more complicated. We need to insert some code that will respond to the challenge URL. Where to put it?

A given machine can have multiple IP addresses. It's also possible that a machine has only internal IP addresses (e.g. 10.0.0.1), but through the magic of routing receives traffic from an external IP address. In other words it may not know the list of IP addresses that route to it.

Both Nginx and Apache support routing traffic based on the IP address of the local interface it arrived on. In Nginx that's done by specifying an IP address in the listen directive of a server block^1. In Apache that's done by specifying an IP address in the VirtualHost directive^2. However, since the machine doesn't necesarily know its own external IP address, trying to match on these directives will be misleading in some cases, and will result in lots of complexity trying to chase various cases.

Proposed Solution

By comparison, the server_name / ServerName directives are reliable, since they take effect based on the Host header of a request, which is always present and will contain an IP address for IP address validation requests.

So I propose we implement this logic:

  1. If there is a server / VirtualHost block with a server name matching the IP address we are trying to validate, put the response stanza there.
  2. Otherwise, try to put the response stanza in the default virtualhost.
    • For Apache, this will be the first VirtualHost block that contains * or _default_. If there is no such block, but there is exactly oneVirtualHost block (specifying a hostname or an IP address), use that.
    • For Nginx, this will be the listen directive that has default_server, if exactly one such directive exists.

We could even consider (2) optional. I include it because it's probably a common use case: deploying a stock config for Apache / Nginx that is not aware of its IP address, and trying to get an IP address certificate right off the bat (e.g. for talking to an administrative interface), using a script that calls Certbot and does know the IP address.

I think these use cases should be explicitly not supported:

  • Automatically deduce IP addresses to request based on server configuration. This was a useful bootstrap for HTTPS novices to "just turn on HTTPS," but certificates for IP addresses are a niche enough use case that I think we don't need as much automagic here.
  • Multiple server / VirtualHost blocks that listen on distinct interfaces but do not have server_name / ServerName directives for the relevant IP addresses. Handling these well would add a lot of complexity for bugs and would still leave edge cases around external vs internal addresses. Users with such setups can make things work trivially by adding server_name /ServerName.

Alternatives Considered

We could choose to support IP address subjectAlternativeName certificates only via the manual and webroot plugins.

jsha avatar Jun 13 '25 20:06 jsha

First IP address certificate issued

IP address certificates are available right now in Staging. They should be generally available in Prod later in 2025, at the same time that short-lived certificates become generally available.

strobecat avatar Jul 04 '25 16:07 strobecat

We're getting support questions about this on the Let's Encrypt Community, so there seems to be a need for this. (And I concur; Certbot is at risk of lagging behind ACME client competitors.)

osirisinferi avatar Jul 07 '25 16:07 osirisinferi

I originally drafted this in a text file locally, and when I pasted it into this issue, I omitted a whole section! Sorry about that. I've edited the original post to include the missing text, which is everything above "Proposed Solution".

jsha avatar Jul 10 '25 21:07 jsha

@jsha I hacked together a version which successfully requested an IP staging certificate for my NGINX server. See #10370

ojura avatar Jul 18 '25 14:07 ojura

sorry i haven't commented on this before, but i wanted to suggest that in the first set of PR(s) here we do just try adding this to the manual, standalone, and/or webroot plugins and we can do any apache and nginx work later. it might be relatively straightforward, but i think there are some questions about how we want to support IP addresses on the CLI, interactive UI, and our plugin API and the non-installer plugins should be an easier place for us to start experimenting with those things

bmw avatar Sep 08 '25 18:09 bmw