Back to articles
Technology Insight

Scaling SaaS Platforms: Implementing On-Demand TLS with Caddy Server for Automated Customer Domain SSL

May 29, 2026

Introduction: The Multi-Tenant Domain Challenge

For modern Software-as-a-Service (SaaS) platforms, e-commerce builders, and website hosting providers, allowing clients to point their custom domains (e.g., shop.customer.com) to a centralized Virtual Private Server (VPS) cluster is a standard feature. However, managing SSL/TLS certificates at this scale presents a monumental operational hurdle. Traditional approaches involving Let's Encrypt rate limits, complex ACME client scripts, and manual web server reloads quickly break down when handling tens of thousands of external domains.

This is where Caddy Server shines. As a modern, cloud-native web server written in Go, Caddy natively automates certificate management. Its most powerful feature for multi-tenant architectures is On-Demand TLS. Instead of pre-configuring certificates for every possible domain, Caddy obtains certificates dynamically during the TLS handshake when a user visits the domain for the very first time. This guide explores how to architecture, secure, and configure On-Demand TLS on Caddy across a high-availability VPS cluster.

---

Understanding Caddy's On-Demand TLS Architecture

In a standard setup, a web server must know its hostnames beforehand to load the corresponding SSL certificates into memory. When a request arrives, the server matches the Server Name Indication (SNI) extension of the TLS handshake with its loaded certificates.

With On-Demand TLS, Caddy alters this workflow entirely:

  1. A visitor accesses customer.com, which points via an A/AAAA or CNAME record to your VPS cluster.
  2. The request hits the Caddy server. Caddy checks its local storage for an existing certificate for customer.com.
  3. If no certificate exists, Caddy executes an internal or external Ask URL HTTP request to verify if this domain is authorized to use your platform.
  4. If the backend approves, Caddy initiates an ACME challenge (via Let's Encrypt or ZeroSSL) in the background, completes it in seconds, issues the certificate, caches it, and fulfills the initial TLS handshake.
Crucial Note: Never enable On-Demand TLS without an 'Ask' endpoint. Without validation, malicious actors can point millions of random domains to your server IP, forcing Caddy to request certificates indefinitely, exhausting your ACME rate limits and causing a Distributed Denial of Service (DDoS) on your infrastructure.
---

Step-by-Step Configuration Guide

1. Setting Up the Ask Endpoint Backend

Before configuring Caddy, you need a lightweight internal API endpoint within your SaaS application. When Caddy queries this endpoint, it passes the domain as a query parameter (e.g., [https://api.yourplatform.internal/check-domain?domain=customer.com](https://api.yourplatform.internal/check-domain?domain=customer.com)).

  • Success: If the domain belongs to an active, paying user, return an HTTP status code 200 OK.
  • Failure: If the domain is unknown or inactive, return an HTTP status code 400 Bad Request or 404 Not Found.

2. Writing the Caddyfile

Below is a comprehensive production-ready Caddyfile configuration designed for handling scalable, on-demand customer domains across a VPS cluster.

{
    # Global options
    email [email protected]
    
    # Storage configuration for cluster synchronization
    storage file_system /var/lib/caddy

    # Core On-Demand TLS Security
    tls {
        on_demand {
            ask [https://api.yourplatform.internal/check-domain](https://api.yourplatform.internal/check-domain)
            interval 2m
            burst 5
        }
    }
}

# Catch-all block for customer domains
:443 {
    tls {
        on_demand
    }

    # Reverse proxy traffic to your internal application service
    reverse_proxy 127.0.0.1:8080 {
        header_up Host {http.request.host}
        header_up X-Real-IP {http.request.remote}
        header_up X-Forwarded-For {http.request.remote}
        header_up X-Forwarded-Proto {http.request.scheme}
    }

    # Enable compression for optimal performance
    encode gzip zstd
    
    # Logging configuration for traffic analytics
    log {
        output file /var/log/caddy/access.log {
            roll_size 10mb
            roll_keep 10
        }
    }
}
---

Optimizing for a Distributed VPS Cluster

When running a cluster of multiple VPS nodes behind a Layer 4 Load Balancer, individual file systems cannot keep track of issued certificates independently. If Node A issues a certificate, Node B won't have it, leading to redundant challenge requests and potential rate-limiting errors.

Shared Storage Backends

To resolve this, configure Caddy to use a shared storage provider instead of the default file_system storage module. Popular cluster-ready storage plugins for Caddy include:

  • Redis Storage (caddy-dns/redis): Highly recommended for sub-millisecond certificate retrieval across nodes.
  • S3 Storage: Great for durability, using AWS S3, DigitalOcean Spaces, or self-hosted MinIO clusters.
  • Consul / Etcd: Excellent for strictly consistent configuration management inside microservice networks.

Rate Limiting Safeguards

The interval and burst options within the on_demand block are vital defensive mechanisms. In our example configuration, burst 5 and interval 2m dictate that Caddy will only attempt to issue a maximum of 5 new certificates every 2 minutes. Any requests beyond this ceiling are immediately dropped, preserving your system resources and Let's Encrypt quotas during anomalous traffic spikes.

---

Production Best Practices and Monitoring

Deploying automated infrastructure at scale requires proactive observability. Ensure your operations pipeline incorporates the following procedures:

Pre-flight DNS Checking

While the ask endpoint ensures the domain is registered on your platform, it doesn't guarantee the customer configured their DNS properly. If they point an invalid or broken CNAME to your cluster, the ACME challenge will fail. To optimize performance, have your ask endpoint execute a quick lookup (such as a dig +short equivalent) to verify that the domain's DNS record targets your cluster before returning a 200 OK status to Caddy.

Monitoring and Alerting

Monitor Caddy's performance using its built-in Prometheus metrics endpoint. Keep a close watch on the following key metrics:

  • caddy_tls_certificates_total: Track the growth of certificates in your cache.
  • caddy_http_requests_total: Monitor spikes in connection counts.
  • Log outputs detailing string errors such as ACME validation failed to identify customers facing configuration issues.
---

Conclusion

Caddy's On-Demand TLS transforms the complex challenge of scaling custom domain SSL management from an infrastructure nightmare into a seamless, set-and-forget operation. By pairing Caddy's lightweight architecture with a robust backend Ask URL validator and a shared storage layer like Redis, you can reliably support tens of thousands of customer domains on your VPS cluster. This approach keeps your operations secure, bounds your system maintenance overhead, and delivers a premium, zero-friction branding experience for your end users.

Scaling SaaS Platforms: Implementing On-Demand TLS with Caddy Server for Automated Customer Domain SSL | DPTCloud