Support for HTTP-01 Challenge over Port 443 with Self-Signed Certificate (for Port 80-Blocked Environments)

Title: Support HTTP-01 Challenge over Port 443 with Self-Signed Certificate for Upgrade Path

I'm working in an environment where port 80 is permanently blocked by firewall policy, and DNS is managed by a separate team, so the dns-01 challenge is not feasible.

Our web server (NGINX) is running on port 443 with a self-signed certificate, and we would like to use Let's Encrypt to upgrade to a trusted certificate.

Unfortunately, none of the current ACME challenge flows allow us to do this:

  • http-01 is hardcoded to require port 80
  • tls-alpn-01 requires shutting down NGINX so Certbot can bind to port 443 directly
  • dns-01 is not an option in our environment
  • A self-signed certificate on 443 is rejected by the CA when trying to follow http → https redirects

:light_bulb: Proposal

Support an explicit, opt-in fallback that allows:

  • Serving the http-01 challenge over HTTPS on port 443
  • Presenting a self-signed certificate
  • Let’s Encrypt’s validation server skipping TLS validation and just checking the HTTP payload

Why this makes sense

  • Port 80 offers no encryption or authentication at all — it is not safer than 443 with a self-signed cert
  • http-01 challenges are about serving content, not proving TLS identity
  • This would allow users to transition from self-signed to trusted certs without taking down mission-critical services or depending on outside DNS admins

Constraints and Mitigations

This could be limited to:

  • Initial issuance only (not renewal)
  • Explicit --insecure-https-challenge flag
  • Rate-limited or audit-logged
  • Fallback-only behavior if port 80 fails or is known to be blocked

Request for Consideration

I understand that the ACME spec favors simplicity and deterministic behavior, but this is a real-world issue that affects users in locked-down environments.

Could the Certbot project and/or Let's Encrypt consider enabling a controlled fallback for http-01 validation over HTTPS with a self-signed cert to support this upgrade path?

Thanks for your consideration and all your work on the ACME ecosystem.

The HTTP-01 challenge can only be done on port 80. Allowing clients to specify arbitrary ports would make the challenge less secure, and so it is not allowed by the ACME standard.

When redirected to an HTTPS URL, it does not validate certificates (since this challenge is intended to bootstrap valid certificates, it may encounter self-signed or expired certificates along the way).

3 Likes

Unfortunately this is not possible. I'm not really knowledgeable with the exact details, but there are (apparently) good reasons why it's not possible to start the http-01 challenge over HTTPS.

You can probably find out details about this here on the Community, maybe from the earlier days of ACME.

A different solution might be to terminate TLS not by nginx, but by an application that terminates TLS and that will reverse proxy the connection to nginx but also can do the tls-alpn-01 challenge.

Maybe things like lets-proxy2 (I just saw that in the list of ACME Client Implementations, no experience with it), and there might be others out there too. HAProxy unfortunately only seems to have http-01 support.

Also, ChatGPT came up with using the nginx stream module (Module ngx_stream_core_module and https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html):

stream {
    map $ssl_preread_alpn_protocols $acme {
        "~\bacme-tls/1\b" 1;
        default           0;
    }

    upstream acme_backend {
        server 127.0.0.1:8443;
    }

    upstream nginx_backend {
        server 127.0.0.1:4433;
    }

    server {
        listen 443;
        proxy_pass $acme ? acme_backend : nginx_backend;
        ssl_preread on;
    }
}

For this example you'd need to have your http {} block listen on 4433. And you'd need a tls-alpn-01 capable ACME client which Certbot isn't. E.g. lego.

Note that ChatGPT probably made some mistakes (as LLM most often do) and I haven't tested the above.

1 Like

Other than the ideas already suggested, you could look at below. It handles TLS-ALPN challenges and passes through anything else unchanged to your webserver.

It does require exclusive use of port 443 so you'd have to change nginx to listen on some alternate port and pass through from this to that new port.

Putting something like Caddy in front of your nginx is another option

6 Likes

In this situation, you can either use the TLS-ALPN-01 challenge, or delegate the required _acme-challenge DNS records to a secondary system that you control and use the DNS-01 challenge. The other team would only have to create a single CNAME record once; ACME Servers will follow that record to the secondary dns system for authentication. Many people will self-host this with acme-dns, many others will use a commercial service. Some even use self-host with bind.

Unfortunately your request is not something viable. It would fall victim to the same security concerns that caused the TLS-SNI-01 challenge to be rescinded. The TLS-ALPN-01 challenge was introduced as a replacement, because it is not subject to the same vulnerabilities.

Edit: it was tls-sni-01, not https-01. here is the announcement which links to the security concerns: March 13, 2019: End-of-Life for All TLS-SNI-01 Validation Support

5 Likes

In the ACME drafts there even was a tls-sni-02 apparently, but I don't think Let's Encrypt ever implemented that challenge. Also gone now though, didn't survive to the RFC status. Not sure what the differences are between tls-sni-01 and tls-sni-02, but probably a good bet tls-sni-02 was deemed insecure too.

2 Likes

A lot of shared hosting providers don't handle port 443 properly if HTTPS is not already configured.

It's unfortunate, but this is what killed TLS-SNI-01 and in my opinion makes using 443 as you describe unsafe.

A redirect from port 80 is acceptable because it is generally deliberately configured

4 Likes

That's not practical - the current nginx server needs to have exclusive use of port 443, but thanks for the suggestion.

I still don't see how using https is any less secure than http - the web server is responsible for using the right server {} block based on SNI - what am I missing?

If the paid certificate vendors allow verification via https using self signed certs - then letsencrypt should as well. If some users are worried about a specific security issue related to using https instead of http, then they don't need to use it, but by not having https as an option, letencrypt shuts the door on users that can't use port 80, or don't want to do DNS delegation, or can't have their web servers give up port 443 for any amount of time.

Let's Encrypt isn't, doesn't claim to be, and doesn't attempt to be all things to all people. Users who have made choices that preclude their use of Let's Encrypt are free to use a different CA, or perhaps to rethink those choices.

5 Likes

Just curious why it would. Requests inbound on port 443 get seen first by the uacme proxy handler. If it is a TLS-ALPN request it processes it. If it is not it passes it unchanged to nginx on some other port. Front-end proxies often proxy to backend servers on alternate ports.

6 Likes

The short of it is that if you (1) don't have control over port 80, (2) don't have control over the ALPN negotiated on port 443, and (3) don't have control over DNS, then you really don't have control over that domain name.

If you can't get your network administrators to open up port 80 (even to redirect to another place, such as port 443 with a self-signed certificate), or allow you to run software on 443 that can automatically handle getting certificates via ALPN (such as Caddy, uacme, or something else), or allow you control over DNS (even a CNAME to delegate to something like acme-dns that you can control), then your network administrators clearly don't think you should control the name and get a certificate for it.

6 Likes

I thought there was a module available for Nginx similar to mod_md for Apache, that does ALPN by default? Am I misremembering this?

5 Likes

Nginx has a standard module (though not built by default) that enables tls-alpn auth through a proxy to another service

I don't know of any ACME nginx modules. IIRC, there are a few OpenResty modules that handle this. Last I checked, most nginx ACME implementations involved offloading the ACME process onto a secondary service (shell script, app, docker container, etc).

az_ made this experimental routing table a while back GitHub - letsdebug/acme-alpn-proxy

3 Likes

An alternative is to defer certificate management to your infrastructure team (assuming they are the ones who control DNS) and setup a certificate request process where:

  • folks who need one can ask for a cert to be created (using DNS domain validation)
  • the cert + key can then be:
    • automatically deployed to a know location on the target machine
    • and/or stored in secrets vault you have access to and periodically pulled via API.

At the risk of self promotion, Certify Management Hub (beta) does all that, with role based access etc: Getting Started | Certify The Web Docs - it also has a managed challenges feature where you can let the hub complete DNS challenge on behalf of your client, so you don't need to know/store privileged secrets. There is also an experimental ACME proxy option in the works (which lets you use any EAB enabled ACME client to create an order, the hub sorts out the challenge responses for you, controlled by the hub administrator).

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.