1. Output of caddy version
:
v2.6.1
2. How I run Caddy:
Via docker compose, config see below.
a. System environment:
Docker on openSUSE Tumbleweed
b. Command:
Nothing, handled by docker compose, config see below.
c. Service/unit/compose file:
docker compose file:
caddy:
build: /mnt/containers/caddy
container_name: caddy
restart: unless-stopped
volumes:
- /mnt/containers/caddy/site:/srv
- /mnt/containers/caddy/data:/data
- /mnt/containers/caddy/config:/config
- /mnt/containers/caddy/caddyfile:/etc/caddy/Caddyfile
- /mnt/containers/caddy/certs:/certs
ports:
- 80:80
- 443:443/tcp
- 443:443/udp
dockerfile:
# syntax=docker/dockerfile:1
FROM docker.io/library/caddy:builder AS builder
RUN xcaddy build --with github.com/caddy-dns/dynv6
FROM docker.io/library/caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
d. My complete Caddy config:
Caddyfile fully working with wildcard certificates:
*.planck.v6.rocks {
tls {
dns dynv6 [api-key]
}
encode gzip
header {
Strict-Transport-Security "max-age=31536000;"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
X-Frame-Options "SAMEORIGIN"
X-Robots-Tag "none"
-Server
}
@homer host homer.planck.v6.rocks
handle @homer {
reverse_proxy homer:8080
}
@freshrss host freshrss.planck.v6.rocks
handle @freshrss {
reverse_proxy freshrss:80
}
@nextcloud host nextcloud.planck.v6.rocks
handle @nextcloud {
redir /.well-known/carddav /remote.php/carddav 301
redir /.well-known/caldav /remote.php/caldav 301
reverse_proxy nextcloud:80
}
@bookstack host bookstack.planck.v6.rocks
handle @bookstack {
reverse_proxy bookstack:80
}
@kavita host kavita.planck.v6.rocks
handle @kavita {
reverse_proxy kavita:5000
}
handle {
abort
}
}
Version without wildcard certificates, but with client certs (my_client_certs block), loaded for only some of the subdomains:
(my_local_only) {
@my_remote_block {
not remote_ip 192.168.1.0/24
}
respond @my_remote_block 403
}
(my_client_certs) {
tls {
client_auth {
mode require_and_verify
trusted_ca_cert_file [ca-file]
trusted_leaf_cert_file [leaf-file]
}
}
}
(my_basic_auth) {
basicauth {
[username] [pw-hash]
}
}
(my_header_config) {
encode gzip
header {
Strict-Transport-Security "max-age=31536000;"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
X-Frame-Options "SAMEORIGIN"
X-Robots-Tag "none"
-Server
}
}
nextcloud.planck.v6.rocks {
import my_header_config
redir /.well-known/carddav /remote.php/carddav 301
redir /.well-known/caldav /remote.php/caldav 301
reverse_proxy nextcloud:80
}
freshrss.planck.v6.rocks {
import my_client_certs
import my_header_config
reverse_proxy freshrss:80
}
homer.planck.v6.rocks {
import my_client_certs
import my_header_config
import my_basic_auth
reverse_proxy homer:8080
}
3. The problem I’m having:
I’m trying to use both tls client certs and a wildcard domain cert, but I only want the tls client certs enabled for some, not all, subdomains.
The two caddyfiles above do either-or (wildcard cert without subdomain client certs, or subdomain client certs without wildcard cert). So far, I have not found a way to do both at the same time with one caddyfile.
Reason for needing wildcard certs: Most of the time, my services are not available to the internet, port 443 is closed and the wildcard DNS entry points to my internal wireguard IP. Services are only available via my wireguard point-to-point tunnel, which is why a regular LE cert will not be able to be renewed. But a wildcard cert still works with these conditions.
Reason for needing client certs: Sometimes, I want to open up my services to the internet after all, at least temporarily. I want to do so safely. So for services like Homer, that come without any auth, I’d like to have at least basic auth enabled. And for services I only access via a web UI, I want client certs as additional security measure, so I don’t have to fully trust the services own auth or basic auth.
Reason for needing client certs only for some subdomains: Many apps don’t support client certs. Sadly, NextCloud is one of them. So while I do want client certs in general, for some services I don’t want them enforced, because it’d break app access. Which means client certs need to be enabled/disabled on subdomain-level.
4. Error messages and/or full log output:
None since individually, both types of config are working, I just don’t know how to combine them properly.
5. What I already tried:
Set up the caddyfile to use wildcard certs.
Set up the caddyfile to use regular certs with individual tls blocks for subdomains.
One possible solution I came up with is to simply use LEGo to generate the LE certs externally and manually specify the existing (external) wildcard cert within the regular non-wildcard subdomain-specific caddyfile entry. Something like:
freshrss.planck.v6.rocks {
tls [cert-file] [key-file] {
client_auth {
mode require_and_verify
trusted_ca_cert_file [ca-file]
trusted_leaf_cert_file [leaf-file]
}
}
reverse_proxy freshrss:80
}
This should enable me to use client certs individually for subdomains while still being able to use the (externally managed) wildcard cert, and being able to regularly (externally) renew the wildcard cert without having to open my services to the internet.
The drawback is, obviously, that caddy won’t manage the certs. I’d much rather use caddy, if in any way possible.
I haven’t found a way to configure the caddyfile to make this possible, but I think it might be possible with the json config. I have never used it, wasn’t able to untangle the documentation and am generally a bit lost on how to approach this if there is a json solution at all.