SSL_PROTOCOL_ERROR for wildcard on demand TLS

1. Caddy version (caddy version):

v2.2.1 h1:Q62GWHMtztnvyRU+KPOpw6fNfeCD3SkwH7SfT1Tgt2c=

2. How I run Caddy:

a. System environment:

I have the Linux amd64 binary in my app directory, it is named caddy and marked executable. I am running Caddy as a reverse proxy on Debian.

b. Command:

I start caddy with sudo ./caddy start

d. My complete Caddyfile or JSON config:

* {
  tls {

3. The problem I’m having:

I am setting up a custom domain system for a blogging platform I am making, and it works by having the person setting up the domain CNAME it to my domain (, and add a TXT record so I know which blog to serve. My node app does all that, and it works well, but it is HTTP only. I am trying to use Caddy for the on demand TLS so when someone connects to my server from a new CNAME, Caddy will get a Let’s Encrypt cert for the domain and serve HTTPS. When I change the * in my Caddyfile to (a custom domain set up with my blogging system), it works wonderfully. However, I need to accept any domain, not just that one.

4. Error messages and/or full log output:

There are no Caddy errors, but Chrome gives me the error ERR_SSL_PROTOCOL_ERROR when connecting, and curl gives curl: (35) error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error

5. What I already tried:

I already tried using :80, :443, but Caddy seems to treat them as hostnames, so I assume that the page I got that information from was for an older version of Caddy.

6. Links to relevant resources:

What’s in your server logs? (Make sure to enable debug mode first)

Thanks for the pointer on debug mode.

2020/12/14 20:18:40.543 INFO    using adjacent Caddyfile
2020/12/14 20:18:40.547 INFO    admin   admin endpoint started  {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["", "localhost:2019", "[::1]:2019"]}
2020/12/14 20:18:40.547 INFO    tls     setting internal issuer for automation policy that has only internal subjects but no issuer configured  {"subjects": ["*"]}
2020/12/14 20:18:40.554 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0xc000496f50"}
2020/12/14 20:18:40.578 INFO    http    server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2020/12/14 20:18:40.578 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "srv0"}
2020/12/14 20:18:40.658 INFO    root certificate is already trusted by system   {"path": "storage:pki/authorities/local/root.crt"}
2020/12/14 20:18:40.661 DEBUG   http    starting server loop    {"address": "[::]:443", "http3": false, "tls": true}
2020/12/14 20:18:40.664 DEBUG   http    starting server loop    {"address": "[::]:80", "http3": false, "tls": false}
2020/12/14 20:18:40.662 INFO    tls     cleaned up storage units
2020/12/14 20:18:40.669 INFO    autosaved config        {"file": "/root/.config/caddy/autosave.json"}
2020/12/14 20:18:40.672 INFO    serving initial configuration
2020/12/14 20:18:51.395 DEBUG   http.stdlib     http: TLS handshake error from xx.xx.xx.xx:52304: no certificate available for ''

I am guessing only the last line is relevant. I have on_demand on, so why isn’t it getting certs?

Probably because * only matches single-label domains like localhost? Try removing that (replace with a port or something).

See the docs:

Thank you so much! That did the trick.

1 Like

Also, please make sure you use the ask option to validate that the domains are trusted, otherwise someone could run a DDOS against your server by forcing it to issue certs for random domains.

An attacker could just configure a wildcard subdomain like * to point to your server, then make requests like then and so on with a bot, forcing your server to issue certs for those. You’ll end up hitting rate limits pretty quickly, and no other domains can be issued. And it’ll fill up your disk space, etc.

So ask is very important to protect against that. Make sure you use it.

1 Like

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