Dynamic Domain Routing with Caddy - Challenges with Multi-Tenant SaaS Proxy Configuration

I’m developing a SaaS platform where customers can add their own custom domains with a unique architecture:

Infrastructure Overview:

  • Caddy v2 (latest version)
  • Docker-based deployment
  • Frontend running on port 5173
  • Centralized proxy mechanism

Domain Configuration Flow:

  1. Customer adds a custom domain (e.g., pay.customercompany.com)
  2. Domain points to a central proxy (proxy.myplatform.com.br)
  3. Central proxy (proxy.myplatform.com.br) has a gray cloud Cloudflare configuration, pointing directly to the server IP

DNS Configuration:

pay.customercompany.com.br (CNAME) → proxy.myplatform.com.br
proxy.myplatform.com.br (A Record) → Server IP

Current Caddy Routes Configuration:

[
  {
    "match": [
      {
        "host": ["proxy.myplatform.com.br"]
      }
    ],
    "handle": [{
      "handler": "reverse_proxy",
      "upstreams": [
        {
          "dial": "frontend:5173"
        }
      ]
    }]
  },
  {
    "match": [
      {
        "host": ["api.myplatform.com.br"]
      }
    ],
    "handle": [{
      "handler": "reverse_proxy", 
      "upstreams": [
        {
          "dial": "backend:3000"
        }
      ]
    }]
  },
  {
    "match": [
      {
        "host": ["pay.customercompany.com.br"]
      }
    ],
    "handle": [{
      "handler": "reverse_proxy",
      "upstreams": [
        {
          "dial": "frontend:5173"
        }
      ]
    }]
  }
]

TLS Configuration:

{
  "tls": {
    "automation": {
      "policies": [{
        "subjects": ["*"],
        "issuers": [{
          "module": "acme",
          "challenges": {
            "http": { "disable": false },
            "tlsalpn": { "disable": false }
          }
        }]
      }]
    }
  }
}

Solutions Already Attempted:

  1. Wildcard TLS configuration (*)
  2. Adding Cloudflare-specific headers
  3. Verifying DNS resolution
  4. Manually configuring routes
  5. Validating internal container connectivity

Current Challenge: When trying to access a dynamically added domain (e.g., pay.customercompany.com.br), I encounter:

  • Browser Error: “Too Many Redirects” (ERR_TOO_MANY_REDIRECTS)
  • Domain has a valid SSL certificate
  • Cloudflare configured with gray cloud

Technical Environment:

  • Ubuntu Server
  • Docker
  • Containers:
    • Caddy (reverse proxy)
    • Frontend (React)
    • Backend (Node.js)

Specific Questions:

  • Why aren’t dynamically added domains being routed correctly?
  • How to handle multiple domains in a dynamic environment?
  • Are there specific Cloudflare configurations needed for Caddy?

Additional Information:

  • Latest Caddy version
  • Domains point correctly
  • SSL certificates functioning

Looking for guidance on implementing a robust, dynamic domain routing solution that can:

  • Dynamically add new customer domains
  • Correctly route through the proxy domain
  • Automatically manage SSL certificates
  • Support multiple customer domains

Any insights or solutions would be greatly appreciated!

I can elaborate later, but your use case is definitely supported and where Caddy excels. You need to use the on-demand TLS feature. I’ve linked the relevant sections in the docs and in a Wiki article:

1 Like