No certificate available for specific subdomain

1. Caddy version (caddy version): 2.5.1

2. How I run Caddy: Using a Docker container with caddy-security (latest versions)

a. System environment:

Ubuntu 20.04
Docker 20.10.16
Docker Compose 2.5.0

b. Command:

docker compose up -d

c. Service/unit/compose file:

(interpolation stuff is Ansible)

  caddy:
    build: "../../{{ app_dir }}/caddy"
    container_name: caddy
    ports:
      - 80:80
      - 443:443
    volumes:
      - "{{ app_dir }}/caddy/config:/config"
      - "{{ app_dir }}/caddy/data:/data"
      - "{{ app_dir }}/caddy/Caddyfile:/etc/caddy/Caddyfile"
      - "{{ app_dir }}/caddy/auth:/auth"
    environment:
      - "DOMAIN={{ domain_name }}"
      - CADDY_AUTH_USERS_PATH=/auth/users.json
    restart: unless-stopped

d. My complete Caddyfile or JSON config:

$DOMAIN is redacted.stream

{
  order authenticate before reverse_proxy

  log 
  
  security {

    local identity store localdb {
      realm local
      path {$CADDY_AUTH_USERS_PATH}
    }

    authentication portal myportal {
      enable identity store localdb
      cookie domain {$DOMAIN}
      cookie lifetime 86400
      crypto default token lifetime 43200
      ui {
        links {
          "Sonarr"    https://sonarr.{$DOMAIN} icon "las la-tv"
          "Radarr"    https://radarr.{$DOMAIN} icon "las la-film"
          "Bazarr"    https://bazarr.{$DOMAIN} icon "las la-closed-captioning"
          "Deluge"    https://deluge.{$DOMAIN} icon "las la-water"
          "Prowlarr"  https://prowlarr.{$DOMAIN} icon "las la-file-download"
          "WUD"       https://wud.{$DOMAIN} icon "las la-toolbox"
          "Duplicati" https://duplicati.{$DOMAIN} icon "las la-copy"
          "Portainer" https://portainer.{$DOMAIN} icon "lab la-docker"
          "Overseerr" https://overseerr.{$DOMAIN} icon "las la-edit"
          "Portal Settings" /settings icon "las la-cog"
        }
      }
    }

    authorization policy admin_policy {
        set auth url https://{$DOMAIN}
        allow roles authp/admin
        acl rule {
          comment allow admins
          match role authp/admin
          allow stop log info
        }
        acl rule {
          comment default deny
          match any
          deny log warn
        }
    }
  }
}

(protected_route) {
  {args.0}.{$DOMAIN} {
    route {
      authorize with admin_policy
      reverse_proxy {args.1}
    }
  }
}

(cors) {
  @origin{args.0} header Origin {args.0}
  header @origin{args.0} Access-Control-Allow-Origin "{args.0}"
  header @origin{args.0} Access-Control-Allow-Headers "*"
  header @origin{args.0} Vary Origin
  header @origin{args.0} Access-Control-Allow-Methods "*"
  header @origin{args.0} Access-Control-Allow-Credentials "true"
}

{$DOMAIN} {
  route {
    
    import cors https://sonarr.{$DOMAIN}
    import cors https://radarr.{$DOMAIN}
    import cors https://bazarr.{$DOMAIN}
    import cors https://deluge.{$DOMAIN}
    import cors https://prowlarr.{$DOMAIN}
    import cors https://wud.{$DOMAIN}
    import cors https://portainer.{$DOMAIN}
    import cors https://duplicati.{$DOMAIN}
    import cors https://overseer.{$DOMAIN}

    @options method OPTIONS
    handle @options {
      respond 204
    }
    handle {
      authenticate * with myportal
    }
  }
}

overseerr.{$DOMAIN} {
    route {
      reverse_proxy overseerr:5055
    }
}

import protected_route duplicati duplicati:8200
import protected_route sonarr sonarr:8989
import protected_route radarr radarr:7878
import protected_route bazarr bazarr:6767
import protected_route deluge deluge:8112
import protected_route prowlarr prowlarr:9696
import protected_route wud wud:3000
import protected_route portainer portainer:9000

3. The problem I’m having:

As you can see I have all my apps behind Caddy. Using Caddy-Security (CS) I authenticate myself and I can access all of them no problem in HTTPS. One app is different though : Overseerr. I want it reverse proxied but NOT protected behind CS authentication. When I go to overseer.redacted.stream I get SSL_ERROR_INTERNAL_ERROR_ALERT in my browser and you can see the logs below when that happens. If I first authenticate with CS though it goes through fine and I can access the app in HTTPS.

4. Error messages and/or full log output:

{"level":"debug","ts":1653244238.3464756,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"overseer.redacted.stream"}
{"level":"debug","ts":1653244238.3465316,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"*.redacted.stream"}
{"level":"debug","ts":1653244238.3465464,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"*.*.stream"}
{"level":"debug","ts":1653244238.3465593,"logger":"tls.handshake","msg":"no matching certificates and no custom selection logic","identifier":"*.*.*"}
{"level":"debug","ts":1653244238.3465748,"logger":"tls.handshake","msg":"all external certificate managers yielded no certificates and no errors","sni":"overseer.redacted.stream"}
{"level":"debug","ts":1653244238.3465924,"logger":"tls.handshake","msg":"no certificate matching TLS ClientHello","server_name":"overseer.redacted.stream","remote":"92.89.89.167:63044","identifier":"overseer.redacted.stream","cipher_suites":[4865,4867,4866,49195,49199,52393,52392,49196,49200,49162,49161,49171,49172,156,157,47,53],"cert_cache_fill":0.001,"load_if_necessary":true,"obtain_if_necessary":true,"on_demand":false}
{"level":"debug","ts":1653244238.3467653,"logger":"http.stdlib","msg":"http: TLS handshake error from 92.89.89.167:63044: no certificate available for 'overseer.redacted.stream'"}

5. What I already tried:

I did enable proxy support in Overseerr because apparently it’s needed. I tried replicating their Nginx config (see below) but to no avail. So I’m not sure if something’s wrong in CS or if I’m missing something.

6. Links to relevant resources:

Here, you could optimize this by putting all the headers in a single header directive, which makes the matcher only run once, instead of 6 times per snippet, which you import multiple times, so it’s like 6 x 9 matchers being executed, where it could just be 9:

(cors) {
	@origin{args.0} header Origin {args.0}
	header @origin{args.0} {
		Vary Origin
		Access-Control-Allow-Origin "{args.0}"
		Access-Control-Allow-Headers "*"
		Access-Control-Allow-Methods "*"
		Access-Control-Allow-Credentials "true"
	}
}

You don’t need to wrap things in route if you used the order global option to control the directive order. You can remove those.

I think you have a spelling mistake in your request, you missed the extra r at the end.

1 Like

Oh my god that was stupid, I hate how they named that thing. Thanks for the tips anyway !

1 Like

Nothing is forcing you to have to use the same name for your subdomain!

Yes but that’s just how I roll :sunglasses:

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