From the makers of DNScale: PostScale -- reliable email delivery for developers. PostScale

    Email & TLSIntermediate

    cert-manager DNS-01 with DNScale

    Use cert-manager with the DNScale DNS-01 webhook to issue Let's Encrypt certificates for Kubernetes Ingress, Gateway, and wildcard certificate workflows.

    Answer snapshot

    cert-manager can solve ACME DNS-01 challenges through DNScale by using a webhook solver. Install cert-manager, deploy the DNScale webhook, store a zone-scoped DNScale API token as a Kubernetes Secret, define an Issuer or ClusterIssuer with groupName `acme.dnscale.eu` and solverName `dnscale`, then request Certificates as usual. Test against Let's Encrypt staging before production.

    What you'll learn

    • Install and configure the DNScale cert-manager DNS-01 webhook
    • Store DNScale API credentials safely in Kubernetes
    • Create a staging and production ClusterIssuer
    • Request wildcard and normal certificates through DNS-01
    • Troubleshoot common cert-manager DNS-01 failures

    cert-manager can automate Let's Encrypt certificates inside Kubernetes. With DNScale's DNS-01 webhook, cert-manager proves domain control by creating temporary _acme-challenge TXT records through the DNScale API.

    Use this guide when:

    • you need wildcard certificates
    • port 80 HTTP-01 validation is blocked or unsuitable
    • certificates should be issued from inside Kubernetes
    • Ingress or Gateway resources need automated TLS

    For broader ACME background, read Let's Encrypt DNS-01 Challenges with DNScale. For cert-manager's generic webhook model, see the official cert-manager webhook solver documentation and DNS01 documentation.

    How It Works

    The flow is:

    1. A Certificate resource asks cert-manager for a certificate.
    2. cert-manager creates an ACME order and challenge.
    3. cert-manager sends the DNS01 challenge to the DNScale webhook.
    4. The webhook creates a TXT record at _acme-challenge.<name> through the DNScale API.
    5. Let's Encrypt validates the TXT record.
    6. cert-manager stores the issued certificate in a Kubernetes Secret.
    7. The webhook removes the temporary TXT record.

    The webhook uses cert-manager's external DNS01 solver fields: groupName, solverName, and provider-specific config.

    Prerequisites

    You need:

    • a Kubernetes cluster
    • cert-manager installed
    • a DNScale-hosted DNS zone
    • a DNScale API token scoped to the validation zone
    • the DNScale cert-manager webhook installed in the cluster
    • CAA records that allow Let's Encrypt if you publish CAA

    Use staging before production. It proves the webhook, token, DNS propagation, and cleanup path without spending production rate limits.

    Install cert-manager

    Install cert-manager with your normal cluster process. The official installation path changes over time, so follow the current cert-manager installation documentation.

    After installation, confirm the controller is running:

    kubectl get pods -n cert-manager

    Install the DNScale Webhook

    Install the DNScale webhook in the same cluster. If using the published chart:

    helm install cert-manager-webhook-dnscale \
      oci://ghcr.io/dnscaleou/charts/cert-manager-webhook-dnscale \
      --namespace cert-manager

    If you are installing from a local checkout of the webhook chart:

    helm install cert-manager-webhook-dnscale \
      ./deploy/dnscale-webhook \
      --namespace cert-manager

    The webhook group name used by the DNScale chart is:

    acme.dnscale.eu

    Confirm the webhook service is present:

    kubectl get deployment,service,apiservice -n cert-manager | grep dnscale

    Store the DNScale API Token

    Create a Kubernetes Secret in the namespace where cert-manager will read solver credentials. For a ClusterIssuer, the DNScale webhook reads the Secret from the challenge resource namespace. Keeping the token in cert-manager is common for cluster-wide issuance, but align this with your cluster's cert-manager policy.

    apiVersion: v1
    kind: Secret
    metadata:
      name: dnscale-api-token
      namespace: cert-manager
    type: Opaque
    stringData:
      api-token: <your-dnscale-api-token>

    Apply it:

    kubectl apply -f dnscale-api-token.yaml

    Use a zone-scoped DNScale key. The webhook needs to find the matching zone and create/delete TXT records. It does not need billing, user-management, or unrelated zone access.

    Create a Staging ClusterIssuer

    Start with Let's Encrypt staging:

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-staging-dnscale
    spec:
      acme:
        email: admin@example.com
        server: https://acme-staging-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-staging-dnscale-account-key
        solvers:
          - dns01:
              webhook:
                groupName: acme.dnscale.eu
                solverName: dnscale
                config:
                  apiTokenSecretRef:
                    name: dnscale-api-token
                    key: api-token

    Apply it:

    kubectl apply -f clusterissuer-staging.yaml
    kubectl describe clusterissuer letsencrypt-staging-dnscale

    Request a Test Certificate

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: example-com-staging
      namespace: default
    spec:
      secretName: example-com-staging-tls
      issuerRef:
        name: letsencrypt-staging-dnscale
        kind: ClusterIssuer
      dnsNames:
        - example.com
        - "*.example.com"

    Apply and inspect:

    kubectl apply -f certificate-staging.yaml
    kubectl describe certificate example-com-staging
    kubectl get orders,challenges

    During validation, check for the TXT record:

    dig TXT _acme-challenge.example.com @ns1.dnscale.eu +short

    When issuance succeeds, cert-manager stores the certificate:

    kubectl get secret example-com-staging-tls -o yaml

    The staging certificate is not browser-trusted. Use it only to verify the flow.

    Create a Production ClusterIssuer

    After staging works, create the production issuer:

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-production-dnscale
    spec:
      acme:
        email: admin@example.com
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-production-dnscale-account-key
        solvers:
          - dns01:
              webhook:
                groupName: acme.dnscale.eu
                solverName: dnscale
                config:
                  apiTokenSecretRef:
                    name: dnscale-api-token
                    key: api-token

    Switch your real Certificate resources to letsencrypt-production-dnscale only after staging succeeds.

    Ingress Example

    If your ingress controller reads cert-manager certificates from Secrets, reference the production issuer and TLS secret:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: app
      namespace: default
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-production-dnscale
    spec:
      tls:
        - hosts:
            - app.example.com
          secretName: app-example-com-tls
      rules:
        - host: app.example.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: app
                    port:
                      number: 80

    Troubleshooting

    Challenge stays pending

    Inspect the challenge:

    kubectl describe challenge -A

    Common causes:

    • webhook deployment is not ready
    • APIService is unavailable
    • Secret name or key is wrong
    • token cannot access the zone
    • CAA does not allow Let's Encrypt
    • resolver cannot see the TXT record yet

    Secret not found

    Check where cert-manager expects the token Secret:

    kubectl get secret -A | grep dnscale-api-token

    The apiTokenSecretRef name and key must match the Secret exactly.

    TXT record does not appear

    Check webhook logs:

    kubectl logs -n cert-manager deploy/cert-manager-webhook-dnscale

    Then verify the zone is hosted in DNScale and the token can edit it.

    CAA blocks issuance

    If the zone publishes CAA, allow Let's Encrypt:

    example.com.  CAA 0 issue "letsencrypt.org"

    Verify:

    dig CAA example.com +short

    Read DNS CAA Record Explained before changing CAA policy for production domains.

    Cleanup leaves stale records

    Stale _acme-challenge TXT records usually mean cleanup failed after validation. They are not normally dangerous, but they are clutter. Confirm the token has delete permission and inspect webhook logs for API errors.

    Operational Notes

    • Use one token per zone or environment.
    • Keep staging and production ACME account keys separate.
    • Use staging before production issuer changes.
    • Monitor certificate renewal events.
    • Treat webhook upgrades like production certificate infrastructure changes.
    • Keep CAA records aligned with your ACME CA.

    Frequently asked questions

    Why use DNS-01 with cert-manager?
    DNS-01 is required for wildcard certificates and works even when the Kubernetes workload is not publicly reachable on port 80. cert-manager publishes a temporary TXT record, waits for validation, then removes it after issuance.
    What does the DNScale webhook do?
    The webhook implements cert-manager's external DNS01 solver interface. cert-manager sends ACME challenge requests to the webhook, and the webhook creates or deletes the required `_acme-challenge` TXT records through the DNScale API.
    What DNScale permissions does the webhook need?
    Use a zone-scoped API token with enough access to list zones and create/delete TXT records for the validation zone. Do not reuse an account-wide administrative key.
    Should I use an Issuer or ClusterIssuer?
    Use an Issuer when one namespace owns the certificate workflow. Use a ClusterIssuer when many namespaces need the same ACME account and DNS-01 solver.
    Can this issue wildcard certificates?
    Yes. DNS-01 is the ACME challenge type that supports wildcard certificates such as `*.example.com`.
    What should I test first?
    Use Let's Encrypt staging first, request a disposable certificate, inspect the Challenge and Order resources, and confirm the temporary TXT record appears and is cleaned up.

    Related guides

    Ready to manage your DNS with confidence?

    DNScale provides anycast DNS hosting with a global network, real-time analytics, and an easy-to-use API.

    Start free