Back to articles
Technology Insight

Scaling SaaS Platforms: Implementing On-Demand TLS with Caddy Server for Thousands of Custom Domains

May 30, 2026

Introduction to Multi-Tenant Domain Challenges

In modern Software-as-a-Service (SaaS) architectures, e-commerce platforms, and website builders, allowing users to point their custom domains (e.g., [www.clientdomain.com](https://www.clientdomain.com)) to a centralized Virtual Private Server (VPS) cluster is a standard requirement. Historically, managing SSL/TLS certificates for tens of thousands of external domains was an operational nightmare. System administrators had to build complex cron jobs, handle Let's Encrypt rate limits manually, or deploy expensive enterprise load balancers.

Caddy Server revolutionizes this workflow through its native On-Demand TLS capability. Instead of pre-generating certificates for all possible domains, Caddy generates an SSL certificate on-the-fly during the initial TLS handshake when a user visits the domain for the very first time. This article provides an enterprise-grade guide to designing, configuring, and securing an On-Demand TLS setup on a Caddy-powered VPS cluster.

The Architecture of On-Demand TLS

To understand why Caddy is so efficient, we must look at how the TLS handshake interacts with certificate provisioning. In a traditional setup, the web server must already possess the certificate and private key matching the Server Name Indication (SNI) sent by the client browser. If the certificate is missing, the handshake fails immediately.

With On-Demand TLS enabled, Caddy alters this lifecycle:

  1. A visitor requests [https://customer-shop.com](https://customer-shop.com), which points to your VPS cluster IP via an A/AAAA record.
  2. Caddy intercepts the TLS Client Hello and extracts the SNI (customer-shop.com).
  3. Before requesting a certificate, Caddy executes an internal or external Ask Endpoint HTTP request to verify if this domain belongs to a valid customer in your database.
  4. If the endpoint responds with a 200 OK status, Caddy contacts an ACME provider (like Let's Encrypt or ZeroSSL) via an internal worker pool to request, validate, and install the certificate in real-time.
  5. The TLS handshake completes successfully, and subsequent requests use the cached certificate.
Critical Security Note: Running On-Demand TLS without an 'Ask' endpoint is highly dangerous. Bad actors can perform a Distributed Denial of Service (DDoS) attack by pointing millions of random domains to your server, forcing your infrastructure to exhaust ACME rate limits and disk space.

Step-by-Step Configuration Guide

1. Designing the Authentication Endpoint (The 'Ask' URL)

Before modifying Caddy's configuration, you need an internal API endpoint that decides whether a domain is authorized to receive a certificate. This API can be written in Node.js, Go, Python, or PHP. It must accept a domain query parameter and return an HTTP status code 200 if allowed, or 404/403 if denied.

Here is an example conceptual logic for your backend application:

// Example in Node.js / Express
app.get('/api/check-domain', async (req, res) => {
    const domain = req.query.domain;
    const isRegistered = await database.lookupDomain(domain);
    
    if (isRegistered) {
        return res.status(200).send('Allowed');
    }
    return res.status(404).send('Not Found');
});

2. Writing the Production Caddyfile

Next, configure your Caddyfile to utilize the global option for On-Demand TLS and link it to your backend application. Below is a robust production blueprint designed for high-availability VPS environments.

{
    # Global Options
    email [email protected]
    
    on_demand_tls {
        ask [http://127.0.0.1:8080/api/check-domain](http://127.0.0.1:8080/api/check-domain)
        interval 2m
        burst 5
    }
}

# Catch-all block for customer domains
:443 {
    tls {
        on_demand
    }
    
    # Proxy traffic to your main multi-tenant application cluster
    reverse_proxy 127.0.0.1:3000 {
        header_up Host {header.Host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
    
    # Enable compression for optimized performance
    encode gzip zstd
    
    # Standard logging configuration
    log {
        output file /var/log/caddy/access.log {
            roll_size 50mb
            roll_keep 10
        }
    }
}

Production Considerations and Best Practices

Mitigating the 'First-Load' Latency

Because the certificate is requested during the very first TLS handshake, the initial visitor will experience an extra 2 to 5 seconds of latency while Let's Encrypt validates the domain via the HTTP-01 challenge. To optimize this user experience:

  • Ensure your VPS cluster has fast, unthrottled outbound internet connectivity to ACME endpoints.
  • Configure your application UI to inform customers to wait a minute after changing their DNS settings before testing their custom domain.
  • Pre-warm certificates during customer onboarding by making a background HTTP call from your backend to Caddy right after they point their DNS records.

Storage and Clustering

By default, Caddy stores certificates on the local file system. If you scale horizontally across multiple VPS instances behind an upstream cloud load balancer (like AWS ALB or Cloudflare), you cannot rely on local storage. You must configure a shared storage backend so all Caddy instances can access the same certificates.

Popular distributed storage plugins for Caddy include:

  • caddy-dns/redis: Uses a Redis cluster to synchronize certificates instantly.
  • caddy-dns/s3: Leverages AWS S3 or MinIO object storage for centralized persistence.
  • Database Storage: Storing certificates directly inside PostgreSQL or MySQL.

Rate Limiting and Abuse Prevention

Even with the ask parameter active, you should implement strict rate limiting inside the on_demand_tls block using the interval and burst parameters as demonstrated in our configuration blueprint. This ensures that even if your internal database becomes slow or compromised, Caddy will not overwhelm the Let's Encrypt API, which could result in a temporary platform-wide IP ban.

Conclusion

Caddy's On-Demand TLS feature completely eliminates the architectural complexity traditionally associated with managing dynamic, multi-tenant SSL certificates. By implementing a secure validation endpoint and adhering to distributed storage patterns, you can confidently scale your platform to handle thousands of white-label customer domains with minimal maintenance overhead. It represents a paradigm shift in modern infrastructure management, enabling startups and enterprises alike to deliver premium custom domain features effortlessly.

Scaling SaaS Platforms: Implementing On-Demand TLS with Caddy Server for Thousands of Custom Domains | DPTCloud