Let’s talk about keeping your TLS certificates fresh without you having to lift a finger. Automating TLS certificate renewal is crucial, and certbot and cert-manager are the two big players here.

cert-manager: The Kubernetes Native

If you’re running Kubernetes, cert-manager is almost certainly the way to go. The most surprising thing about cert-manager is that it doesn’t just renew certificates; it manages the entire lifecycle, from issuance to renewal to revocation, all declared as Kubernetes resources.

Imagine you have a web application deployed via a Deployment and exposed by a Service and Ingress. You want TLS for that Ingress. With cert-manager, you declare this desire directly in your Kubernetes manifests.

Here’s a simplified example of what your Ingress might look like:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    # This annotation tells cert-manager to issue a certificate for this Ingress
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls-secret # cert-manager will create/update this Secret
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-service
            port:
              number: 80

And here’s the ClusterIssuer it refers to, which tells cert-manager how to get certificates (in this case, using Let’s Encrypt’s production API):

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-private-key # cert-manager stores its ACME account key here
    solvers:
    - http01:
        ingress:
          class: nginx # Assuming you're using nginx-ingress controller

When you apply these manifests, cert-manager (which you’ve already installed in your cluster) sees the Ingress with the cert-manager.io/cluster-issuer annotation. It then creates a CertificateRequest resource. It uses the specified ClusterIssuer to interact with Let’s Encrypt. Let’s Encrypt challenges your domain (e.g., via HTTP-01 challenge, where cert-manager temporarily modifies your Ingress to serve a specific file). Once validated, Let’s Encrypt issues the certificate, and cert-manager stores it in the Secret named myapp-tls-secret. Your Ingress controller then picks up this Secret and starts serving traffic over TLS.

cert-manager constantly watches its Certificate and CertificateRequest resources. When a certificate is nearing expiration (by default, 30 days before), it automatically initiates the renewal process by creating a new CertificateRequest. The same validation flow occurs, and the Secret is updated with the renewed certificate.

The real power here is the declarative nature. You define the desired state (I want TLS for myapp.example.com using Let’s Encrypt via the letsencrypt-prod issuer), and cert-manager handles the imperative steps to achieve and maintain that state. It supports various issuers (Let’s Encrypt, HashiCorp Vault, Venafi, private CAs) and challenge types (HTTP-01, DNS-01).

One of the most powerful, yet often overlooked, aspects of cert-manager is its ability to manage internal Certificate Authorities (CAs) within your cluster. You can create a CA issuer in cert-manager that generates its own self-signed root certificate, and then use this CA issuer to issue certificates for your internal services. This allows you to have a consistent, managed PKI for all your internal applications without relying on external CAs or manual certificate distribution. You simply create a Certificate resource referencing your internal CA issuer, and cert-manager will ensure certificates are issued and renewed, and the root CA certificate can be distributed to your clients (e.g., by mounting it into pods or configuring application trust stores).

The next logical step after automating your public-facing TLS is often to automate internal service-to-service communication security.

certbot: The Standalone Workhorse

certbot is the command-line tool primarily used for obtaining and renewing certificates from Let’s Encrypt. It’s fantastic for single servers or when you’re not in a Kubernetes environment.

The most surprising thing about certbot is how simple its core operation is: it’s a client that speaks the ACME protocol to a Certificate Authority. It’s designed to be run directly on the machine that will host the certificate.

Let’s say you have a single web server running Nginx on an Ubuntu machine. You’d install certbot and its Nginx plugin:

sudo apt update
sudo apt install certbot python3-certbot-nginx

To get a certificate for mywebsite.example.com, you’d run:

sudo certbot --nginx -d mywebsite.example.com

certbot will then interact with Let’s Encrypt. For the Nginx plugin, it typically uses the http-01 challenge. It will temporarily modify your Nginx configuration to serve a specific file from a specific URL that Let’s Encrypt’s servers will request. If successful, Let’s Encrypt issues the certificate, and certbot saves it to /etc/letsencrypt/live/mywebsite.example.com/ and configures Nginx to use it.

Renewal is handled by a cron job or systemd timer that certbot sets up automatically. You can test the renewal process with:

sudo certbot renew --dry-run

This command simulates the renewal process without actually changing any certificates. It’s crucial for verifying your renewal setup.

The default renewal configuration for certbot (often managed by /etc/cron.d/certbot or a systemd timer) runs certbot renew twice a day. This command checks all installed certificates and renews any that are due for renewal (typically within 30 days of expiration). The --nginx plugin ensures that Nginx is reloaded automatically after a successful renewal to pick up the new certificate.

The core mechanics involve certbot creating a .well-known/acme-challenge/ directory and file on your web server, which Let’s Encrypt’s servers then query. If the content matches what Let’s Encrypt expects, validation passes. The challenge is temporary and removed after validation. The Nginx plugin automates the configuration changes and reloads required for this.

The one thing most people don’t realize is that certbot can also manage certificates for services other than the one it’s directly interacting with for the challenge, provided you configure it correctly. For example, you can use the dns-01 challenge with a plugin (like certbot-dns-route53 or certbot-dns-cloudflare) to automate renewals by updating DNS TXT records. This is invaluable if your web server isn’t directly accessible from the internet or if you prefer DNS validation. The dns-01 challenge involves certbot creating a TXT record in your DNS zone that proves you control the domain, rather than serving a file via HTTP.

The next hurdle you’ll likely face is managing certificates for multiple domains or subdomains on the same server efficiently, or integrating certificate management into a CI/CD pipeline.

Want structured learning?

Take the full Tls-ssl course →