SSL CertificatesTrust solutions
Automate Your Certificates with ACME
$25.00
  • Eliminate Manual Renewals
  • Easy Setup & Integration
  • Reduce Downtime Risks
  • Unlimited Certificates
GOGETSSL CLOUD CODE SIGNING CERTIFICATE
$354.17 Starting at
  • No hardware tokens/HSMs
  • No shipping = no delays
  • Integrate with cloud platforms
  • 1000 signings, one user seat
VULNERABILITY SCANNER WITHOUT COMPROMISES
$25.00 Basic Quick-Scan
  • OWASP Top 10 Scanning
  • Multi Page Web Applications
  • REST API & JavaScript Scan
  • Set it up in minutes
NEW FLEX SSL FEATURE AVAILABLE
$72.00 Starting at
  • Protect up to 250 domains
  • Wildcard domains
  • Single and sub-domains
  • Public IP addresses
Home Wiki ACME Knowledge base Install an ACME SSL Certificate in Kubernetes

How to Install & Automate SSL Certificates on Kubernetes and NGINX Ingress Using ACME

  • Automating SSL/TLS for your Kubernetes cluster using an ACME SSL certificate keeps your applications secure without manual renewals. This guide uses cert-manager with External Account Binding (EAB) and shows how to configure a kubeadm Kubernetes cluster with NGINX Ingress, issue, install, auto-renew, and verify certificates. Example commands use placeholders, replace them with your actual values.

NGINX Ingress
    • *

      Prerequisites

      Mandatory (required for ACME automation)

      These requirements apply regardless of how the Kubernetes cluster is built. You must have the following in place to issue and auto-renew SSL/TLS certificates using ACME and cert-manager:

      • Working Kubernetes cluster
      • kubectl access to the cluster
      • An Ingress controller installed and publicly reachable on port 80
      • A domain with a DNS A record pointing to the cluster’s external IP
      • ACME subscription with External Account Binding (EAB) credentials (Key ID and HMAC key)
      • ACME server directory URL

      Environment Used in This Guide (Reference Only)

      The steps and examples in this guide were validated using the environment below. Users do not need to match this setup exactly.

      • Ubuntu 22.04 node
      • Single-node Kubernetes cluster initialized with kubeadm
      • containerd runtime
      • NGINX Ingress Controller
      • MetalLB for external IP assignment
      Note: Any Kubernetes distribution, Linux OS, container runtime, ingress controller, or load-balancing method may be used as long as the mandatory prerequisites above are met.
    • 1

      Step 1 - Install cert-manager

      Install the cert-manager CRDs and components used to request ACME certificates.

      1. Apply CRDs
                                                    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.1/cert-manager.crds.yaml --validate=false
                                                
      2. Create namespace
                                                    kubectl create namespace cert-manager
                                                
      3. Install cert-manager
                                                    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.1/cert-manager.yaml
                                                
      4. Verify cert-manager pods
                                                    kubectl get pods -n cert-manager --watch
                                                    # or once:
                                                    kubectl get pods -n cert-manager
                                                

      Replace these placeholders with your own values:

      • CERT_MANAGER_VERSION - cert-manager version used (v1.15.1+)
      Executing cert-manager installation steps
      Image Caption: Executing cert-manager installation steps including applying CRDs, creating the namespace, deploying components, and verifying running pods.
      Tips:
      • If CRD apply fails, re-run with --validate=false to bypass validation errors.
      • If cert-manager pods or webhook fail to start, verify the Kubernetes API server time is correct and CRDs are applied. Check logs with: kubectl logs -n cert-manager deploy/cert-manager
      • If pods are stuck in Pending or CrashLoopBackOff, run kubectl describe pod POD_NAME -n cert-manager for detailed errors.
    • 2

      Step 2 - Create EAB secret

      Store your External Account Binding (EAB) credentials for the ClusterIssuer. Replace ALL CAPS placeholders before applying.

      1. Create YAML file acme-eab-secret.yaml (file content)
                                                    apiVersion:v1
                                                    kind:Secret
                                                    metadata:
                                                      name:acme-eab-secret
                                                      namespace:cert-manager
                                                    type:Opaque
                                                    stringData:
                                                      kid:"EAB_KID"
                                                      hmacKey:"EAB_HMAC_KEY"
                                                
      2. Apply the secret
                                                    kubectl apply -f acme-eab-secret.yaml
                                                    # OR
                                                    kubectl create secret generic acme-eab-secret \
                                                    --namespace cert-manager \
                                                    --from-literal=kid="EAB_KID" \
                                                    --from-literal=hmacKey="EAB_HMAC_KEY"
                                                

      Replace these placeholders with your own values:

      • EAB_KID External Account Binding Key ID
      • EAB_HMAC_KEY External Account Binding HMAC Key
      Creating and applying the acme-eab-secret.yaml
      Image Caption: Creating and applying the acme-eab-secret.yaml file containing the EAB KID and HMAC key for cert-manager.
      Tips:
      • If ClusterIssuer reports missing EAB key data, verify the key: field in your ClusterIssuer matches hmacKey in the secret.
      • If the secret is not recognized, confirm it exists in the cert-manager namespace with the correct name (acme-eab-secret).
      • If apply fails, check YAML formatting and re-run: kubectl apply -f acme-eab-secret.yaml
    • 3

      Step 3 - Create ClusterIssuer for ACME + EAB (HTTP-01)

      Define a cluster-wide ACME issuer that uses your CA's ACME server and EAB secret for account registration. This configuration uses HTTP-01 challenge solving via NGINX Ingress.

      1. Create YAML file cluster-issuer.yaml
                                                    apiVersion:cert-manager.io/v1
                                                    kind:ClusterIssuer
                                                    metadata:
                                                      name:sectigo-prod
                                                    spec:
                                                      acme:
                                                        email:ACCOUNT_EMAIL
                                                        server:SERVER
                                                        privateKeySecretRef:
                                                          name:sectigo-prod
                                                        externalAccountBinding:
                                                          keyID:EAB_KID
                                                          keySecretRef:
                                                            name:acme-eab-secret
                                                            key:hmacKey
                                                        solvers:
                                                          - http01:
                                                            ingress:
                                                              class:nginx
                                                


        Replace these placeholders with your own values:

        • ACCOUNT_EMAIL - Email for ACME account (notifications)
        • SERVER - ACME directory URL (e.g., https://acme.sectigo.com/v2/DV)
        • EAB_KID - External Account Binding Key ID
      2. Apply ClusterIssuer
                                                    kubectl apply -f cluster-issuer.yaml
                                                
      3. Verify ClusterIssuer Registration
                                                    kubectl describe clusterissuer sectigo-prod
                                                    # look for Status: Ready=True and events showing registration
                                                
      Creating the ACME ClusterIssuer
      Image Caption: Creating the ACME ClusterIssuer, applying the cluster-issuer.yaml file, and verifying the issuer status as Ready in Kubernetes.
      Tips:
      • If ACME registration fails or shows invalid EAB, verify SERVER, EAB_KID, and EAB_HMAC_KEY values.
      • If secret not found, confirm acme-eab-secret exists in the cert-manager namespace.
      • If you receive HTTP 403/404 errors, verify the ACME server URL is correct.
    • 4

      Step 4 - Create Ingress for HTTP-01 + TLS

      Create an Ingress with cert-manager annotations to request and mount a TLS secret. Replace these placeholders with your own values:

      • INGRESS_NAME - Ingress resource name (hello-ingress)
      • NAMESPACE - Namespace where Ingress and Service live (default)
      • DOMAIN - testroot.net
      • SECRET_NAME - TLS secret name to be created by cert-manager (tls-secret)
      • SERVICE_NAME - hello-service
      • PATH - URL path for routing (use / for root, or /hello for the sample app)

      1. Ingress YAML header (save as ingress.yaml, section 1)
                                                    apiVersion:networking.k8s.io/v1
                                                    kind:Ingress
                                                    metadata:
                                                      name:INGRESS_NAME
                                                      namespace:NAMESPACE
                                                      annotations:
                                                        kubernetes.io/ingress.class:"nginx"
                                                
                                                    cert-manager.io/cluster-issuer:"sectigo-prod"
                                                
                                                    nginx.ingress.kubernetes.io/ssl-redirect:"true"
                                                
      2. Ingress spec TLS & rule (append to ingress.yaml, section 2)
                                                    spec:
                                                       ingressClassName:nginx
                                                       tls:
                                                         - hosts:
                                                           - DOMAIN
                                                         secretName:SECRET_NAME
                                                       rules:
                                                         - host:DOMAIN
                                                         http:
                                                           paths:
                                                             - path:/PATH
                                                             pathType:Prefix
                                                             backend:
                                                               service:
                                                                 name:SERVICE_NAME
                                                                 port:
                                                                   number:80
                                                
      3. Apply Ingress
                                                    kubectl apply -f ingress.yaml
      4. Check Ingress status
                                                    kubectl get ingress INGRESS_NAME -n NAMESPACE -o wide
      Creating and applying the hello-ingress
      Image Caption: Creating and applying the hello-ingress manifest with TLS and ClusterIssuer annotations, and verifying the ingress host, class, and address using kubectl get ingress.
      Tips:
      • If the ADDRESS column is empty or not showing the MetalLB IP → verify the NGINX Ingress service and MetalLB setup:
        kubectl get svc -n ingress-nginx
      • If ACME solver pods or temporary challenge ingresses are failing, inspect them using:
        kubectl get pods -A | grep acme
        kubectl get ingress -A | grep acme
      • If TLS is not provisioning and Ingress class mismatch occurs, ensure the following match the controller name:
        ingressClassName: nginx
        annotation: kubernetes.io/ingress.class: "nginx"
    • 5

      Step 5 - Monitor Certificate Issuance

      Verify cert-manager creates a Certificate and CertificateRequest, and confirm the HTTP-01 challenge succeeds. Replace these placeholders with your own values below:

      • CERTREQ_NAME - Name of the CertificateRequest created by cert-manager
      • SECRET_NAME - tls-secret (certificate secret)
      1. List Certificates
                                                    kubectl get certificate -A
                                                
      2. Describe Certificate (SECRET_NAME)
                                                    kubectl describe certificate SECRET_NAME -n NAMESPACE
                                                
        Verifying the issued TLS certificate
        Image Caption: Verifying the issued TLS certificate by checking the tls-secret status and describing the Certificate resource to confirm it is Ready.
      3. Inspect CertificateRequest
                                                    kubectl get certificaterequest -A
                                                    kubectl describe certificaterequest <CERTREQ_NAME> -n <NAMESPACE>
                                                
        Output of kubectl get certificaterequest
        Image Caption: Output of kubectl get certificaterequest and kubectl describe certificaterequest, confirming that the tls-secret-1 request is Approved and Ready using the sectigo-prod ClusterIssuer.
        Tips:
        • If the Certificate shows READY=False:
          Run:
          kubectl describe certificaterequest <name>
          This will usually show the ACME server error such as DNS failure, unreachable HTTP-01 challenge, or account registration issues.
        • If HTTP-01 challenge fails with 404 (common issue):
          This means the Ingress is not routing to the ACME solver pod.
          Fix by checking:
          - ingressClassName matches the controller (e.g., nginx)
          - Ingress Controller Service has a reachable external/MetalLB IP
          - No conflicting Ingress rules
    • 6

      Step 6 - Verify Externally

      Confirm TLS is served and the certificate is issued by your CA.

      1. HTTP to HTTPS redirect check
                                                    curl -I http://DOMAIN
                                                

        Expect: 308 redirect to https://DOMAIN
        Note: Replace DOMAIN with your actual domain name (for example, testroot.net).
      2. TLS handshake and cert details
                                                    curl -vk https://DOMAIN
                                                
        Verifying HTTP→HTTPS redirection (308)
        Image Caption: Verifying HTTP→HTTPS redirection (308) and testing the secured endpoint using curl -vk to confirm TLS 1.3, CA-issued certificate, and successful HTTPS response.
      3. Verify Kubernetes secret contains TLS data
                                                    kubectl get secret SECRET_NAME -n NAMESPACE -o yaml
                                                
        Output of kubectl get secret tls-secret -n default
        Image Caption: Output of kubectl get secret tls-secret -n default -o yaml showing the base64-encoded TLS certificate and private key.
      4. (Optional) Verify Certificate in web browser

        Access your domain using a web browser, click the padlock icon in the address bar, and inspect the certificate details. Confirm that the certificate is issued by the CA and that the connection is fully secured.

        TLS certificate details displayed in the browser
        Image Caption: TLS certificate details displayed in the browser, confirming the CA as the issuer and secure connection for the domain.
      Tips:
      • Connection refused: Ingress endpoint unreachable. Verify MetalLB external IP assignment, Ingress-NGINX service EXTERNAL-IP, and firewall/SG rules allowing 80/443.
      • Wrong or unexpected certificate (self-signed/CA not issued): A manual TLS secret exists or cert-manager failed issuance. Delete the manual secret and inspect:
        kubectl describe certificaterequest and kubectl describe certificate for ACME/CA errors.
      • If the browser shows a warning or incomplete chain: check that the tls-secret contains the full certificate chain (tls.crt) and that cert-manager is correctly issuing the fullchain.
    • 7

      Step 7 - Manual Renewal Test

      Test cert-manager's ability to re-issue a certificate by deleting the existing Certificate and Secret.

      WARNING: This temporarily deletes the TLS secret and causes brief downtime. Use only in test environments.

      1. View current certificate expiry
                                                      kubectl describe certificate SECRET_NAME -n NAMESPACE
                                                
        kubectl describe certificate output showing cert-manager successfully
        Image Caption: kubectl describe certificate output showing cert-manager successfully issuing a valid TLS certificate (Status: Ready) for the domain testroot.net.
      2. Force re-issue (exact two commands)
                                                    kubectl delete secret SECRET_NAME -n NAMESPACE
                                                    kubectl delete certificate SECRET_NAME -n NAMESPACE
                                                

        Note: Replace NAMESPACE with your actual Kubernetes namespace (for example, default).
      3. Watch cert-manager recreate and reissue
                                                  kubectl get certificaterequest -A
                                                  kubectl get certificate -A
                                                   kubectl get secret -n NAMESPACE
                                                
        Renewal triggered — cert-manager
        Image Caption: Renewal triggered — cert-manager creates new CertificateRequest and Secret.
      Tips:
      • CertificateRequest not Ready: Check cert-manager logs for ACME/issuer errors:
        kubectl logs -n cert-manager deploy/cert-manager
      • Certificate stuck Pending: Verify DNS A record matches the MetalLB external IP and Ingress is reachable over HTTP.
      • Secret not created/empty: Ensure Certificate resource references correct secretName and issuer (ClusterIssuer) is Ready.

Optional Checks & Troubleshooting

  • These steps are not required for most installations but are helpful if you encounter issues. You may also contact our support team for more questions.

    • *

      Quick Cluster Verification (Optional)

      Run these checks to confirm your Kubernetes cluster, ingress controller, DNS, and network are correctly configured before starting the ACME installation.

      1. Verify cluster health
                                                    kubectl get nodes
                                                
      2. Verify ingress controller is running
                                                    kubectl get pods -n ingress-nginx
                                                
      3. Verify ingress service has an external IP
                                                    kubectl get svc -n ingress-nginx
                                                
      4. Verify DNS resolution
                                                    nslookup DOMAIN
                                                
      5. Verify port 80 is reachable
                                                    curl -I http://DOMAIN
                                                

      This confirms:

      • Cluster health
      • Ingress controller availability
      • EXTERNAL-IP assignment
      • DNS resolution
      • HTTP (port 80) reachability for ACME HTTP-01 challenge
    • *

      Summary

      You have successfully:

      • Installed and verified cert-manager
      • Created a CA EAB secret
      • Created ClusterIssuer with HTTP-01 solver
      • Deployed sample app and Service
      • Created Ingress annotated for cert-manager
      • Issued and verified TLS certificate
      • Tested manual renewal and verified automatic renewal

      SSL renewals now run automatically without manual intervention.

    • *

      Final Placeholder Library (Universal + Kubernetes-focused)

      Placeholder - Description

      • ACCOUNT_EMAIL - Email used for ACME account registration
      • CERT_MANAGER_VERSION - cert-manager version (v1.15.1+)
      • CERTREQ_NAME - Certificate request resource name (auto-generated by cert-manager, appears in kubectl output)
      • DEPLOYMENT_NAME - Name of the Deployment (hello)
      • DOMAIN - Fully qualified domain (e.g., testroot.net)
      • EAB_HMAC_KEY - External Account Binding HMAC Key
      • EAB_KID - External Account Binding Key ID
      • INGRESS_NAME - Name of the Ingress resource (hello-ingress)
      • NAMESPACE - Kubernetes namespace (default: default)
      • POD_NAME - Specific pod name when running kubectl debugging commands (from kubectl get pods output)
      • SECRET_NAME - TLS secret created by cert-manager (tls-secret)
      • SERVER - ACME server URL (e.g., https://acme.sectigo.com/v2/DV)
      • SERVICE_NAME - Name of the Service (hello-service)

Fast Issuance within 3-5 minutes

Get a Domain Validation SSL certificate within just 5 minutes using our friendly and automated system. No paperwork, callback or company required.

Price Match 100% Guarantee

Found a better price? We will match it - guaranteed. Get the best possible price in the World with us. The correct place to save your money.

ACME SSLAutomation

No more manual installations or expiring certificates: automate your SSL certificates with ACME. Get Started with ACME SSL

Money Back 30-day guarantee

Customer satisfaction is our major concern. Get a full refund within 30 days for any purchase of SSL certificates with 100% guarantee.

Speed up SSL issuance

GoGetSSL® offers fastest issuance of SSL due to use of LEI code and API automation. Legal Entity Identifier (LEI) is a global identity code, just like DUNS. Learn how LEI works.

1,422,468+Total LEIs issued
224+Jurisdictions supported