Is this the best/intended way to set up wildcard certs?

Hi everyone- This configuration actually works as intended, so I don’t have a problem exactly, but there are a few things I’m unclear on and I’m unsure whether this is the intended way to do it.

I need to respond to dozens of different *.actuallyplayed.com subdomains, so I definitely want a wildcard cert for that domain. I also need to respond to a couple of other domains- here they’re just represented by another subdomain, bar.actuallyplayed.com, but only because I don’t have another real domain handy to point to it. Please imagine it’s bar.example.com.

For the avoidance of doubt,

  • hello3.actuallyplayed.com and hello4.actuallyplayed.com should (and do) use a wildcard cert
  • bar.actuallyplayed.com should (and does) use a non-wildcard cert

1. Caddy version (caddy version):

v2.4.0-beta.2 h1:DUaK4qtL3T0/gAm0fVVkHgcMN04r4zGpfPUZWHRR8QU=

2. How I run Caddy:

a. System environment:

Docker, with a builder dockerfile that adds the cloudflare module. No issues with that.

b. Command:

docker-compose -f docker-compose-asdf2.yml run --service-ports caddy sh
# then, in the container's shell
caddy run --config /caddy_config.json

c. Service/unit/compose file:

version: "3.7"

services:
  caddy:
    build:
      context: ./caddy
    restart: unless-stopped
    command: ["caddy", "run", "--config", "/caddy_config.json"]
    ports:
      - 80:80
      - 443:443
    volumes:
      - caddy_data:/data
      - caddy_config:/config
      - ./caddy_config_testasdf.json:/caddy_config.json

volumes:
  caddy_data:
  caddy_config:

d. My complete Caddyfile or JSON config:

{
  "logging": {
    "logs": {
      "default": {
        "level": "DEBUG"
      }
    }
  },
  "apps": {
    "tls": {
      "automation": {
        "policies": [
          {
            "subjects": ["*.actuallyplayed.com"],
            "issuers": [
              {
                "module": "acme",
                "ca": "https://acme-staging-v02.api.letsencrypt.org/directory",
                "challenges": {
                  "dns": {
                    "provider": {
                      "name": "cloudflare",
                      "api_token": "redacted"
                    }
                  }
                }
              }
            ]
          }
        ]
      }
    },

    "http": {
      "servers": {
        "asdf": {
          "tls_connection_policies": [
            {
              "match": {
                "sni": ["*.actuallyplayed.com"]
              }
            }
          ],
          "automatic_https": {
            "disable": false
          },
          "listen": [":443"],

          "routes": [
            {
              "match": [
                {
                  "host": ["*.actuallyplayed.com"]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "match": [
                        {
                          "host": ["hello3.actuallyplayed.com"]
                        }
                      ],
                      "handle": [
                        {
                          "handler": "static_response",
                          "body": "hi3",
                          "close": true
                        }
                      ],
                      "terminal": true
                    },
                    {
                      "match": [
                        {
                          "host": ["hello4.actuallyplayed.com"]
                        }
                      ],
                      "handle": [
                        {
                          "handler": "static_response",
                          "body": "hi4",
                          "close": true
                        }
                      ],
                      "terminal": true
                    }
                  ]
                }
              ]
            },
            {
              "match": [
                {
                  "host": ["bar.actuallyplayed.com"]
                }
              ],
              "handle": [
                {
                  "handler": "static_response",
                  "body": "hi bar",
                  "close": true
                }
              ]
            }
          ]
        }
      }
    }
  }
}

3. The problem I’m having:

Before ending up with that file, my first intuition had been to:

  • List each domain/subdomain flatly under asdf.routes, rather than needing the subroute that responds to a wildcard
  • Set automatic_https.disable=true for every domain that I want to be covered by a wildcard
  • Rely on the policy under tls.automation to handle the renewal of a wildcard cert, which would then be used for those domains

But this doesn’t work as I expect. The wildcard cert is never requested purely by virtue of that policy existing, and when automatic_https.disable=true, any requests resulted in this log entry:

2021/04/17 10:48:01.123 DEBUG   http.stdlib     http: TLS handshake error from 192.168.176.1:52548: no certificate available for 'hello4.actuallyplayed.com'

So, questions/comments:

  1. The “subroute matching a wildcard” solution I used feels like a workaround, like I’m tricking Caddy into doing what I want. Is there another way?
  2. Do I need tls_connection_policies? (if I omit it Caddy mentions in the log that it’s added its own, but doesn’t show the full JSON it added).
  3. I’m unsure about my use of terminal, in particular with regards to whether the wildcard subroute handler should have it and/or its own subroutes.
  4. In general, I’m not confident that I know whether I’m following best practices or using the system as intended.

(On the other hand, if I /am/ using it as intended, I’ll publish this JSON as an example somewhere since it took quite a while to figure out how to write it! :slight_smile: )

Any thoughts would be appreciated either way. Many thanks for taking the time.

4. Error messages and/or full log output:

N/A, see above

5. What I already tried:

See above

6. Links to relevant resources:

N/A

I’m not at my PC right now, so this’ll need to do for now; I wrote a PR recently to add this config example to the docs for a “best practice” way to do wildcard routing in the Caddyfile:

You can take that example and run caddy adapt --pretty on it to see what the JSON looks like and go from there.

Edit: It’s now here in the docs:

1 Like

Thanks @francislavoie! It looks like I was fairly close with the subroute approach, which is reassuring.
I’ve since noticed that zerossl has no rate limiting, so it’s tempting to just go with individual certs and rely on http challenges… will depend on the exact number of subdomains I end up needing. Either way, I appreciate the best practice reference.

This topic was automatically closed after 30 days. New replies are no longer allowed.