## TL;DR
Describe the Challenge; its reason tells you whether the solver pod never served the token or the self-check could not reach it. Then verify the solver pod is up, the ingress routes the challenge path, and DNS points at the ingress. The chain is Challenge to solver pod to ingress to DNS.

## Verbatim error
```text
Waiting for HTTP-01 challenge propagation: failed to perform self check GET request
```

## Steps
1. Inspect the Challenge and its reason.
```bash
kubectl get challenges -n [NAMESPACE]
kubectl describe challenge [CHALLENGE-NAME] -n [NAMESPACE]
```
Expected: the Status and Events name the failing step, for example the solver pod is not ready, the self-check GET failed, or the presented token mismatched. Also check kubectl get orders -n [NAMESPACE] for the parent order state.

2. Check the solver pod cert-manager created.
```bash
kubectl get pods -n [NAMESPACE] -l acme.cert-manager.io/http01-solver=true
kubectl logs -n [NAMESPACE] -l acme.cert-manager.io/http01-solver=true
```
Expected: a solver pod in Running state serving on its port. If it is missing or crashlooping, the challenge path has nothing to answer; the pod logs name the cause.

3. Verify the ingress routes the challenge path to the solver service.
```bash
kubectl get ingress -n [NAMESPACE]
kubectl describe ingress [SOLVER-INGRESS] -n [NAMESPACE]
```
Expected: a temporary ingress routing /.well-known/acme-challenge/ to the solver service. Wrong ingress class is the classic failure: the ingress was created for a controller that is not serving it.

4. Confirm DNS for the domain points at the ingress address.
```bash
kubectl get ingress [MAIN-INGRESS] -n [NAMESPACE] -o yaml
```
Expected: the ingress status shows an address, and public DNS for the domain resolves to it. If DNS points elsewhere, the CA reaches the wrong server and the challenge can never validate. Fix the DNS record and wait for propagation.

5. Check the self-check path: cert-manager verifies from inside the cluster by default, which fails when hairpin NAT or split-horizon DNS makes the domain unreachable from inside.
```bash
kubectl run -n [NAMESPACE] --rm -i --tty [DEBUG-POD] --image=[DEBUG-IMAGE] --restart=Never -- curl -v http://YOUR-DOMAIN/.well-known/acme-challenge/[TOKEN]
```
Expected: if this fails from inside but works from outside, the cluster's egress or DNS view is the problem, not the challenge. Fix the internal DNS or egress path, or disable the self-check only if you understand the tradeoff.

## When to use
- Certificates stay in pending with challenges stuck in Waiting for HTTP-01 challenge propagation
- The failure started after changing ingress class, DNS provider, or network policy
- Only some domains fail while others issue fine

## When not to use
- The challenge fails with a DNS-01 error; that is a DNS provider credential or record issue, different solver
- The order shows an invalid authorization from the CA; the domain never pointed at you
- cert-manager itself is crashlooping; fix the controller first

## Why it happens
HTTP-01 proves domain control by serving a token at a well-known path. cert-manager creates a solver pod and ingress for that path, then self-checks before telling the CA to verify. Any break, solver pod down, ingress misrouted, DNS wrong, internal networking blocking the self-check, stalls the challenge in propagation-waiting.

## Edge cases
- NetworkPolicies blocking the solver pod's traffic make the self-check fail while external validation would pass; allow the challenge path.
- Multiple ingress controllers fighting over the ingress class annotation route the challenge to the wrong controller.
- Wildcard certificates cannot use HTTP-01 at all; switch those to DNS-01.
- Very low TTL caching resolvers can serve stale DNS to the CA after you fix the record; wait out the old TTL before retrying.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_FDC-jHn93eeXDNcaqyca_Q
