Skip to main content

Bare-IP TLS Is GA: Instant HTTPS for Preview URLs Without a DNS Round-Trip

10 min readDora NodaDora Noda
Share
On this page

For a decade, the answer to "can I get a publicly trusted certificate for a bare IP address?" was effectively no — not from Let's Encrypt, anyway. On January 15, 2026, that answer flipped to yes. A branch deploy can now get valid HTTPS on its own node's raw IP with zero DNS records, zero TXT propagation waits, and zero wildcard bookkeeping.

The 60-second answer

If you run a git-push PaaS on a Cluster API fleet and you provision ephemeral per-PR preview environments, here is the verdict up front: use bare-IP certificates for short-lived, machine-scoped previews, and keep subdomains for anything a human bookmarks or that must survive rescheduling. The wiring is a cert-manager ClusterIssuer with the shortlived ACME profile:

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-ip
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    profile: shortlived # cert-manager >= v1.18; 160-hour lifetime
    privateKeySecretRef:
      name: letsencrypt-ip-account-key
    solvers:
      - http01:
          gatewayHTTPRoute:
            parentRefs:
              - name: preview-gateway
                namespace: gateway-system

plus a hand-written Certificate carrying the preview IP as a SAN:

yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: pr-4821-preview
  namespace: previews
spec:
  secretName: pr-4821-preview-tls
  issuerRef:
    name: letsencrypt-ip
    kind: ClusterIssuer
  ipAddresses:
    - 95.217.12.44 # the preview Machine's external IP
  renewBefore: 48h # 160h certs need an explicit, aggressive window

And here are the two constraints that shape everything else in this post: every IP certificate is valid for 160 hours (about six and a half days) with no longer-lived option, and IP identifiers can only be validated with http-01 or tls-alpn-01 — never dns-01, with no wildcards. If either of those is a dealbreaker for your setup, keep your wildcard and skip to the decision table at the end. Otherwise, read on for why this changes preview-URL design.

The news in 30 seconds

Let's Encrypt's January 15, 2026 announcement made two things generally available at once: short-lived certificates (160-hour validity, requested via the shortlived certificate profile) and IP address certificates for both IPv4 and IPv6. The two are coupled on purpose: IP certificates must use the short-lived profile, because IPs are more transient than domain names and deserve more frequent revalidation.

A few facts worth pinning down:

  • Opt-in, not the default. Let's Encrypt has no plan to make short-lived the default; subscribers switch by selecting the profile in their ACME client. The default lineage is on its own glide path from 90 days toward 45.
  • This was a long runway. Let's Encrypt issued its first IP certificate in July 2025, ran a late-2025 beta, and shipped Certbot support in March 2026. GA is the end of a careful rollout, not a flag flip.
  • Clients must speak profiles. Requesting the shortlived profile requires an ACME client that implements the profiles extension. cert-manager added spec.acme.profile in v1.18 — check your version before you promise anyone bare-IP previews.
  • The industry is moving the same direction. The CA/B Forum's Ballot SC-081v3 phases maximum public-TLS validity down from 398 days to 200 days (March 2026), 100 days (March 2027), and 47 days (March 2029). Short-lived automation you build for preview certs today is the same muscle you will need for everything by 2029.

How IP validation actually works (RFC 8738)

The reason bare-IP certs eliminate the DNS round-trip is structural, not incidental. Under RFC 8738, the ACME IP Identifier Validation Extension, an ip identifier may only be validated with the existing http-01 or tls-alpn-01 challenges — and with two critical modifications:

  1. The DNS resolution step is skipped. The CA connects to the identifier's IP value directly. There is no name to resolve, no CNAME to follow, no propagation to wait for.
  2. dns-01 is not offered for IPs. There is no _acme-challenge TXT record for an address, and wildcard semantics do not exist for IP identifiers at all.

For http-01, the CA fetches http://<ip>/.well-known/acme-challenge/<token> with the Host header set to the IP literal. For tls-alpn-01, it opens a TLS connection to the IP negotiating acme-tls/1. Either way, the practical requirement is the same: whatever answers challenges must be reachable at that exact IP on port 80 or 443. On a Cluster API fleet, that means your challenge solver has to live behind the same Gateway/load-balancer address the preview is served from — which is exactly where cert-manager's Gateway API solver already puts it.

This is also why bare-IP certs are a preview-URL feature and not a general replacement for DNS: validation proves control of the route to the IP right now, which is precisely the property an ephemeral environment has and precisely the property a stable production hostname needs DNS to pin down.

The full wiring: cert-manager plus Gateway API

The sketch at the top works, but three details bite everyone who wires this up the first time. All three are about the gap between "cert-manager automates DNS certs" and "cert-manager automates IP certs."

First, the Gateway annotation does not help you. Annotating a Gateway with cert-manager.io/cluster-issuer makes cert-manager derive DNS names from each listener's hostname — it does not read ipAddresses, and there is no hostname to derive from on an IP-only listener. For preview IPs you hand-write the Certificate with an explicit ipAddresses list, templated by whatever provisions the preview (a small controller, a CI job, or your platform's deploy pipeline).

Second, the HTTP-01 solver needs a port-80 HTTP listener on the same Gateway. cert-manager answers the challenge by creating a temporary HTTPRoute for /.well-known/acme-challenge/<token> attached to your Gateway, then deletes it after validation. No port-80 listener, no route attachment point, no validation. If your Gateway only serves 443, add the HTTP listener — it can exist solely for ACME and redirect everything else.

Third, pin the issuer to the short-lived profile and set renewBefore explicitly. The issuer in the sketch selects profile: shortlived so every Certificate it signs gets the 160-hour lineage. cert-manager's default renew-before is two-thirds of the duration (about 53 hours here), which is correct but implicit; writing renewBefore: 48h makes the ~4.5-day renewal cadence visible to the next person reading the manifest. More on that math in a moment.

A complete minimal Gateway for previews therefore looks like this: an HTTP listener on port 80 (ACME + redirect), an HTTPS listener on 443 referencing the preview secret, and the preview HTTPRoute binding the two. The preview pipeline's job on each new branch deploy is just: allocate the preview address, apply the Certificate with that IP, wait for Ready, then route traffic.

Tying cert lifecycle to Machine lifecycle

This is the part that makes bare-IP certs a fleet feature rather than a generic trick — and the part the title promises. On a Cluster API fleet, a preview environment's IP is typically the external address of a freshly provisioned Machine (or a floating IP attached to it). That gives you a natural lifecycle pairing:

  • Machine provisioned → mint the cert. The moment the Machine has an address and the Gateway routes to it, apply the Certificate. First validation takes seconds because there is no DNS propagation in the loop — the CA connects straight to the IP.
  • Machine deleted → garbage-collect the cert. The Certificate and its Secret belong to the preview namespace; delete them with the preview. A 160-hour cert for a preview that lived 3 days expires harmlessly a few days later even if cleanup misses once — short lifetimes are a backstop, not just a cost.
  • Preview rescheduled to a new IP → new validation, new cert. This is the sharp edge. An IP cert is bound to the address, not the workload. If the preview moves to another Machine with a different external IP, the old cert is useless and the new IP needs its own validation round. Design for it: either pin previews to stable floating IPs for their lifetime, or make re-issuance on IP change a normal, tested code path rather than an incident.

The floating-IP question deserves a deliberate call. On Hetzner — the bread-and-butter substrate for self-hosted CAPI fleets — a floating IP follows the preview across Machine replacements, which converts "reschedule breaks TLS" into "reschedule is invisible." The cost is a small pool of floating IPs to manage and the automation to attach/detach them. If your previews are truly disposable (hours, not days), ephemeral node IPs plus re-issuance are simpler; if reviewers bookmark preview links across a multi-day review cycle, float the IP.

The renewal math nobody can skip

A 160-hour certificate with cert-manager's default renew-before-two-thirds renews roughly every 107 hours — about every four and a half days. Every preview cert on your fleet therefore generates ~6-7 ACME order lifecycles per month for as long as the preview lives. Three consequences:

  1. Renewal automation is not optional; it is the entire design. This is why Let's Encrypt positions short-lived certs for "subscribers that have fully automated their renewal process." If your cert pipeline still involves a human clicking anything, bare-IP previews will page you within a week.
  2. Monitor the renewal loop, not the expiry date. Alerting "cert expires in 24 hours" on a 160-hour cert means you have one business day to fix a broken renewal path. Alert instead on Certificate Ready=False, on failed Challenge/Order resources, and on time-since-last-successful-issuance per preview namespace.
  3. Budget ACME traffic at fleet scale. A hundred long-lived previews each renewing weekly is hundreds of validations a month against your Gateways — trivial for the CA, but real load your solver path now carries. Keep the port-80 listener and solver RBAC healthy; they are control-plane infrastructure now, not setup-time scaffolding.

Note the asymmetry that makes this acceptable: previews are short-lived, so most preview certs are issued once and garbage-collected before their first renewal ever fires. The renewal load concentrates on the long tail of previews that live for weeks — exactly the ones you should probably be nudging toward a stable subdomain anyway.

Bare IP versus subdomain: the decision table

ConcernBare-IP cert (https://95.217.12.44/)Subdomain (https://pr-4821.onbex.co/)
DNS dependencyNone — validation hits the IP directlyWildcard or per-branch record; DNS-01 or HTTP-01
Time to first valid HTTPSSeconds after the Machine routesSeconds (wildcard) to minutes (TXT propagation)
Lifetime / renewal load160h fixed; renewal ~every 4.5 daysUp to 398d today (shrinking to 47d by 2029); wildcard renews once for all previews
IP reassignmentBreaks TLS; needs re-issuance or floating IPsInvisible — the name follows the new IP
Memorability / shareabilityPoor — nobody bookmarks an IP with confidenceGood — branch names in URLs are self-describing
Wildcard reuseImpossible — no IP wildcards existOne cert covers every preview
Client compatibilityAny modern TLS stack; some corporate proxies distrust IP SANsUniversal

The verdict from the top holds: bare-IP for ephemeral, machine-scoped previews where DNS is pure overhead; subdomains for anything humans bookmark, share in review threads, or expect to survive rescheduling. Many fleets will end up with both — bare-IP as the instant default the moment a Machine provisions, upgrading to a branch subdomain when the PR leaves draft. That hybrid is not indecision; it matches each mechanism to the lifetime it was designed for.

The 47-day world is coming

Zoom out one level and bare-IP previews are a rehearsal. By March 2029 every public certificate you operate — preview, staging, production — lives inside a 47-day maximum, and the operational posture that requires (fully automated issuance, renewal-loop monitoring, short-lived-first thinking) is exactly what IP certs force you to build today. A fleet that can mint, serve, and garbage-collect 160-hour certs per preview without human touch has already done the hard part of the 47-day migration; the remaining work is policy, not plumbing.

Start small: one preview Gateway, one shortlived issuer, floating IPs for anything that must survive a reschedule, and alerts on the renewal loop rather than the expiry date. The DNS round-trip you delete is real latency off every branch deploy — and the automation you build to delete it is the same automation 2029 is going to demand anyway.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex