How to Install cert-manager for SSL Certificate Automation on Kubernetes

Mar 26, 2026

What Is This Guide About?

This guide walks you through installing cert-manager — a tool that automatically handles SSL certificates for your websites running inside Kubernetes. Think of cert-manager as your personal certificate assistant: it requests, renews, and manages SSL certificates so your sites can use secure HTTPS connections without manual work.

In plain terms, this is what cert-manager does for you:

  • Automatically requests a free SSL certificate when you need one
  • Automatically renews the certificate before it expires
  • Stores the certificate securely inside your Kubernetes cluster
  • Works with popular DNS providers like Cloudflare, AWS Route53, and Google Cloud DNS

???? Who Should Use This Guide?
This guide is ideal for DevOps engineers, system administrators, and developers who manage Kubernetes clusters and want to automate SSL certificate management using a custom ACME server (such as FreeSSL).

Quick Reference Overview

DetailValue
Target PlatformKubernetes (version 1.19 or higher)
DNS Provider UsedCloudflare (can also use AWS, Google Cloud, DigitalOcean)
Validation MethodDNS-01 (proves domain ownership via DNS records)
ACME Server URLhttps://www.freessl.in/acme-new/acme/directory
Certificate RenewalAutomatic — cert-manager handles it for you
Installation MethodHelm (recommended) or kubectl YAML manifests

Before You Begin — Prerequisites

Before installing cert-manager, make sure you have the following ready.

1. A Running Kubernetes Cluster (v1.19 or higher)

Kubernetes is the system that runs and manages your applications inside containers. cert-manager is installed inside Kubernetes and requires version 1.19 or newer.

Check your Kubernetes version:

kubectl version --short

Verify cluster nodes are running:

kubectl get nodes
2. kubectl — The Command-Line Tool

kubectl is the command-line tool you use to talk to your Kubernetes cluster. It should already be installed and connected to your cluster. If you can run the commands above without errors, you are good to go.

Helm is a package manager for Kubernetes — similar to how App Store or apt-get works for apps, Helm helps you install Kubernetes applications easily. We recommend using Helm to install cert-manager.

4. Cluster Admin Permissions

You need admin-level access to your Kubernetes cluster. cert-manager creates cluster-wide resources that require elevated permissions.

5. Cloudflare Account with API Token

cert-manager uses Cloudflare's API to automatically create temporary DNS records to prove that you own the domain before issuing a certificate. You will create a special API token from your Cloudflare account in a later step.

6. EAB Credentials from Your ACME Server Administrator

EAB stands for External Account Binding. These are special credentials (a Key ID and HMAC Key) that the custom ACME server (FreeSSL) requires to verify your account before issuing certificates. Obtain these from your ACME server administrator before you begin.

?? Important: You need your EAB Key ID and HMAC Key ready before you can complete the setup. Contact your ACME server administrator to get these values.


Part 1 — Installing cert-manager

There are two ways to install cert-manager. We strongly recommend Method 1 (Helm) as it is easier to manage and upgrade.

1

Add the cert-manager Helm Repository

This tells Helm where to find the cert-manager package.

helm repo add jetstack https://charts.jetstack.io
helm repo update

The first command registers the official cert-manager repository. The second fetches the latest package list.

2

Create the cert-manager Namespace

A namespace is like a folder inside Kubernetes to keep cert-manager's components organized and separate from your other applications.

kubectl create namespace cert-manager
3

Install cert-manager

This installs cert-manager and all its required components (CRDs) into your cluster.

helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v1.13.3 \
--set installCRDs=true \
--set global.leaderElection.namespace=cert-manager

What these options mean:

  • --namespace cert-manager — Installs into the namespace you just created
  • --version v1.13.3 — Installs a specific, tested version
  • --set installCRDs=true — Also installs the Custom Resource Definitions
4

Verify the Installation

Check that all three cert-manager components are running successfully.

kubectl get pods -n cert-manager

You should see three pods all showing STATUS: Running:

NAME                                      READY   STATUS    RESTARTS   AGE
cert-manager-7d9f8c8d4f-xxxxx 1/1 Running 0 2m
cert-manager-cainjector-5c5695c4b-xxxxx 1/1 Running 0 2m
cert-manager-webhook-6b8d9c7f5d-xxxxx 1/1 Running 0 2m

? Success Check: If all three pods show 1/1 Running, your cert-manager installation is successful. If any pod shows Error or CrashLoopBackOff, wait a minute and check again. If the problem persists, check Part 8 (Troubleshooting).

Method 2: Install Using kubectl (YAML Manifests)

If you do not have Helm installed, you can install cert-manager directly using kubectl with a single command:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml

After installation, verify the Custom Resource Definitions (CRDs) were installed correctly:

kubectl get crd | grep cert-manager

You should see six entries listed:

certificaterequests.cert-manager.io
certificates.cert-manager.io
challenges.acme.cert-manager.io
clusterissuers.cert-manager.io
issuers.cert-manager.io
orders.acme.cert-manager.io

Part 2 — Setting Up Cloudflare DNS

cert-manager needs access to your DNS provider (Cloudflare) to prove that you own your domain. It does this by automatically creating a temporary DNS record during certificate issuance — this is called the DNS-01 challenge.

Step 1 — Create a Cloudflare API Token

An API Token gives cert-manager limited access to your Cloudflare account — only enough to create and delete DNS records.

  1. Log in to your Cloudflare account at cloudflare.com
  2. Click your profile icon in the top-right corner
  3. Go to: My Profile ? API Tokens ? Create Token
  4. Choose the template: Edit zone DNS
  5. Set the following permissions:
    • Zone ? DNS ? Edit
    • Zone ? Zone ? Read
  6. Choose which domains (zones) this token can access
  7. Click Create Token
  8. IMPORTANT: Copy and save the token immediately — Cloudflare only shows it once!

?? Security Note: Treat your API token like a password. Do not share it or store it in plain text. It will be stored securely inside Kubernetes as a Secret in the next step.

Step 2 — Store the API Token in Kubernetes

Run this command, replacing YOUR_CLOUDFLARE_API_TOKEN_HERE with your actual token:

kubectl create secret generic cloudflare-api-token \
--namespace=cert-manager \
--from-literal=api-token='YOUR_CLOUDFLARE_API_TOKEN_HERE'

Verify the secret was created:

kubectl get secret cloudflare-api-token -n cert-manager

Alternatively, using a YAML file:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token
namespace: cert-manager
type: Opaque
stringData:
api-token: YOUR_CLOUDFLARE_API_TOKEN_HERE
EOF

Part 3 — Setting Up EAB Credentials

EAB (External Account Binding) credentials are required by your custom ACME server (FreeSSL) to verify that you have a valid account. You should have received two values from your administrator:

  • EAB Key ID — a unique identifier for your account
  • EAB HMAC Key — a secret key used to sign your requests

Store EAB Credentials in Kubernetes

kubectl create secret generic acme-eab-credentials \
--namespace=cert-manager \
--from-literal=eab-kid='YOUR_EAB_KEY_ID_HERE' \
--from-literal=eab-hmac-key='YOUR_HMAC_KEY_HERE'

Verify the secret was created:

kubectl get secret acme-eab-credentials -n cert-manager -o yaml

Alternatively, using a YAML file:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: acme-eab-credentials
namespace: cert-manager
type: Opaque
stringData:
eab-kid: YOUR_EAB_KEY_ID_HERE
eab-hmac-key: YOUR_HMAC_KEY_HERE
EOF

Part 4 — Create the ClusterIssuer

A ClusterIssuer is a Kubernetes resource that tells cert-manager exactly how to issue certificates. Think of it as a profile or template that cert-manager uses every time it needs to request a certificate.

Create the ClusterIssuer Configuration File

Create a new file named cluster-issuer.yaml and paste the following content, replacing placeholders with your actual values:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: custom-acme-issuer
spec:
acme:
# The address of your ACME server
server:
https://www.freessl.in/acme-new/acme/directory
# Your email --- used for expiry notifications
email:
admin@example.com
# Where to store the ACME account private key
privateKeySecretRef:
name: custom-acme-account-key
# EAB credentials for account verification
externalAccountBinding:
keyID: YOUR_EAB_KEY_ID_HERE
keySecretRef:
name: acme-eab-credentials
key: eab-hmac-key
keyAlgorithm: HS256
# DNS validation using Cloudflare
solvers:
- dns01:
cloudflare:
email:
cloudflare@example.com
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
selector:
dnsZones:
- "example.com"
- "*.example.com"

Replace these values:

  • admin@example.com — your email for notifications
  • YOUR_EAB_KEY_ID_HERE — your EAB Key ID from Part 3
  • cloudflare@example.com — your Cloudflare account email
  • example.com — your actual domain name

Apply the ClusterIssuer

kubectl apply -f cluster-issuer.yaml

Verify the ClusterIssuer is Ready

kubectl get clusterissuer custom-acme-issuer -o wide

A successful result looks like this:

NAME                  READY   STATUS               AGE
custom-acme-issuer True Account registered 1m

The READY column must show True. If it shows False, check the detailed status:

kubectl describe clusterissuer custom-acme-issuer

Part 5 — Adjusting Timeout and Retry Settings (Optional)

If you experience timeouts or slow certificate issuance, you can tune these settings.

Create a file called values-custom.yaml with the following content:

global:
logLevel: 2 # 0 = minimal, 6 = very detailed
controller:
extraArgs:
- --dns01-check-retry-period=30s
- --max-concurrent-challenges=20
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
webhook:
timeoutSeconds: 30

Apply with:

helm upgrade cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v1.13.3 \
--values values-custom.yaml

Method B: Edit the Deployment Directly

kubectl edit deployment cert-manager -n cert-manager

In the editor, find the args section under containers and add:

args:
- --dns01-check-retry-period=30s
- --max-concurrent-challenges=20
- --v=2

Part 6 — Using Other DNS Providers

If you use a different DNS provider, here are the configurations for the most common alternatives.

Option A: AWS Route53

apiVersion: v1
kind: Secret
metadata:
name: route53-credentials
namespace: cert-manager
type: Opaque
stringData:
secret-access-key: YOUR_AWS_SECRET_KEY
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: custom-acme-route53
spec:
acme:
server:
https://www.freessl.in/acme-new/acme/directory
email:
admin@example.com
privateKeySecretRef:
name: custom-acme-account-key
externalAccountBinding:
keyID: YOUR_EAB_KEY
keySecretRef:
name: acme-eab-credentials
key: eab-hmac-key
keyAlgorithm: HS256
solvers:
- dns01:
route53:
region: us-east-1
accessKeyID: YOUR_AWS_ACCESS_KEY_ID
secretAccessKeySecretRef:
name: route53-credentials
key: secret-access-key

Option B: Google Cloud DNS

kubectl create secret generic clouddns-sa \
--namespace=cert-manager \
--from-file=key.json=gcp-service-account.json
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: custom-acme-clouddns
spec:
acme:
server:
https://www.freessl.in/acme-new/acme/directory
email:
admin@example.com
privateKeySecretRef:
name: custom-acme-account-key
externalAccountBinding:
keyID: YOUR_EAB_KEY
keySecretRef:
name: acme-eab-credentials
key: eab-hmac-key
keyAlgorithm: HS256
solvers:
- dns01:
cloudDNS:
project: your-gcp-project-id
serviceAccountSecretRef:
name: clouddns-sa
key: key.json

Option C: DigitalOcean DNS

apiVersion: v1
kind: Secret
metadata:
name: digitalocean-dns
namespace: cert-manager
type: Opaque
stringData:
access-token: YOUR_DIGITALOCEAN_API_TOKEN
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: custom-acme-digitalocean
spec:
acme:
server:
https://www.freessl.in/acme-new/acme/directory
email:
admin@example.com
privateKeySecretRef:
name: custom-acme-account-key
externalAccountBinding:
keyID: YOUR_EAB_KEY
keySecretRef:
name: acme-eab-credentials
key: eab-hmac-key
keyAlgorithm: HS256
solvers:
- dns01:
digitalocean:
tokenSecretRef:
name: digitalocean-dns
key: access-token

Part 7 — Testing and Verification

Check the ClusterIssuer Status

# List all ClusterIssuers and their status
kubectl get clusterissuer

# See detailed information about your ClusterIssuer
kubectl describe clusterissuer custom-acme-issuer

# View live cert-manager logs
kubectl logs -n cert-manager -l app=cert-manager -f

# View webhook logs
kubectl logs -
n cert-manager -l app=webhook -f
Request a Test Certificate

Replace test.example.com with a domain you actually control:

cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-certificate
namespace: default
spec:
secretName: test-certificate-tls
issuerRef:
name: custom-acme-issuer
kind: ClusterIssuer
dnsNames:
- test.example.com
EOF

Monitor the Certificate Status

kubectl get certificate test-certificate -w
kubectl describe certificate test-certificate
kubectl get secret test-certificate-tls -o yaml

Part 8 — Troubleshooting Common Issues

? Issue 1: ClusterIssuer Is Not Ready (READY: False)

This usually means the EAB credentials are incorrect, or cert-manager cannot reach the ACME server.

# Check for error messages
kubectl describe clusterissuer custom-acme-issuer

# Check cert-manager logs for errors
kubectl logs -n cert-manager -l app=cert-manager --tail=100

# Verify your EAB Key ID is correct
kubectl get secret acme-eab-credentials -n cert-manager -o jsonpath='{.data.eab-kid}' | base64 -d

Common fixes:

  • Double-check your EAB Key ID and HMAC Key — ensure no extra spaces
  • Verify the ACME server URL is correct and accessible
  • Delete and recreate the ClusterIssuer if credentials were wrong

? Issue 2: DNS Propagation Timeout

If your DNS provider is slow, cert-manager may time out before the record is visible. Increase the DNS check interval:

kubectl edit deployment cert-manager -n cert-manager
# In the editor, add or change this argument:
# --dns01-check-retry-period=60s

? Issue 3: ACME Account Registration Failure

First, test if the ACME server is reachable:

curl -k https://www.freessl.in/acme-new/acme/directory

Have any Questions

Call HTTPS

If you have any questions, feel free to call us