Issue a new certificate when using Cloudflare Origin Certificate

1. The problem I’m having:

How do i get Caddy to issue certificates when also using Cloudflare Origin Certificate. So, I’m using Caddy as a reverse proxy for my apps. I have a Cloudflare wildcard origin certificate for my domain. I want to use it for most of my apps, but not all. For example, for app1.example.com, but not app2.example.com. How do I get Caddy to issue a certificate for app2.example.com, and not use the Cloudflare certificate that is matching? The Cloudflare certificate only works when proxying through Cloudflare.

I have tried the following:

  1. Added tls internal to my app2, but it does not issue a new certificate.
  2. Added auto_https ignore_loaded_certs. In this case, it also tries to issue a certificate for app1, which already explicitly uses the Cloudflare certificate.

2. Error messages and/or full log output:

This log is showing and preventing auto https, because I have a certificate already.

{"level":"info","ts":1739623637.9827669,"logger":"http.auto_https","msg":"skipping automatic certificate management because one or more matching certificates are already loaded","domain":"app2.example.com","server_name":"srv0"}

3. Caddy version:

2.9.1

4. How I installed and ran Caddy:

With Docker Compose, the installation is working correctly.

a. System environment:

Ubuntu 20.04, Docker.

b. Command:

# start caddy
docker compose up -d

# reload config when necessary
docker compose exec -w /etc/caddy caddy caddy reload

c. Service/unit/compose file:

services:
  caddy:
    image: caddy:2.9
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./certs:/certs:ro
      - ./logs:/var/log/caddy
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - proxy

networks:
  proxy:
    external: true

volumes:
  caddy_data:
  caddy_config:

d. My complete Caddy config:

{
	log {
		output file /var/log/caddy/admin.log {
			roll_size 1mb
			roll_keep 10
			roll_keep_for 720h
		}
		level INFO
		format json
	}
}

app1.example.com {
	reverse_proxy webapp:8000
	tls /certs/domain.crt /certs/domain.key
}

app2.example.com {
	reverse_proxy webapp:8000
}

5. Links to relevant resources:

Assuming your example.com domain is through Cloudflare, then you need to have the tls directive for app2.example.com. That would look like this:

{
	log {
		output file /var/log/caddy/admin.log {
			roll_size 1mb
			roll_keep 10
			roll_keep_for 720h
		}
		level INFO
		format json
	}
}

app1.example.com {
	reverse_proxy webapp:8000
	tls /certs/domain.crt /certs/domain.key
}

app2.example.com {
	tls {
		dns cloudflare {env.CF_API_TOKEN}
	}
	reverse_proxy webapp:8000
}

Assuming that you have the Caddy binary with the Cloudflare plugin, that should be all that is necessary to get a certificate for app2.example.com.

I don’t know the exact answer to your question, but here’s an alternative answer: why not generate your own certificates for both (possibly using the DNS challenge) and ignore the certificate Cloudflare provides? There’s no need to use it.

1 Like

Assuming your example.com domain is through Cloudflare, then you need to have the tls directive for app2.example.com

Doesn’t this use the other SSL certificate automatically because “one or more matching certificates are already loaded”. It is a wildcard certificate. Or is the Cloudflare plugin the deciding factor here? I haven’t tried that plugin.

What does this mean exactly? I would like to have them behind Cloudflare so my server IPs are not exposed, and it allows for some advanced request blocking. Also I would like to use a wildcard certificate so they dont reveal every subdomain. Is this still possible with this?

No, setting app2 to use DNS challenge to obtain a certificate will not interfere with the set certificate for app1 if you configure it properly. I may have misunderstood earlier, but to me it sounded like Caddy issued the wildcard certificate. If Cloudflare did, then you should still be able to use that certificate and tell Caddy it is for *.example.com. You would just explicitly mention specific apps to use tls dns to obtain separate certificates. You would need the Cloudflare plugin.

{
	log {
		output file /var/log/caddy/admin.log {
			roll_size 1mb
			roll_keep 10
			roll_keep_for 720h
		}
		level INFO
		format json
	}
}

*.example.com {

	tls /certs/domain.crt /certs/domain.key

	@app1 host app1.example.com
	handle @app1 {
		reverse_proxy webapp:8000
	}

	@app2 host app2.example.com
	handle @app2 {
		tls {
			dns cloudflare {env.CF_API_TOKEN}
		}
		reverse_proxy webapp:8000
	}
}

Yes, just have Caddy issue a wildcard certificate.

There’s no need to use the certificate provided by Cloudflare. They require you to have either a valid certificate, or the one they provided. Either will work. Personally I prefer to use a valid certificate from Letsencrypt because (a) it works even without Cloudflare, and (b) there’s an automated renewal mechanism vs downloading and installing the Cloudflare certificate manually.

1 Like

Thank you for this, I will test this out when I have time. I have never seen this nested syntax used like this before. Are there any downsides to it?

And yes, I meant that I got the certificate from Cloudflare. That is not necessary in the future though, if I can get a wildcard with Caddy and still use Cloudflare’s CDN.

Thanks for the help! I am new to Caddy, so I am not sure what my Caddyfile should look like to ensure I use the wildcard certificate that Caddy issues. So would I be able to use the same Letsencrypt wildcard certificate with or without Cloudflare’s CDN? Could you provide an example of this setup?

Downsides? Not really. Caddy is very efficient at parsing Caddyfile, and this is probably the best way to handle a wildcard (*) site block.


I’m not entirely sure how Cloudflare handles external certificates, specifically when using a tunnel or proxying. That would require some research on my end.


Assuming that Cloudflare can accept Let’sEncrypt’s certificates versus whatever Cloudflare does, here’s an example. It’s similar to my previous one:

{
	log {
		output file /var/log/caddy/admin.log {
			roll_size 1mb
			roll_keep 10
			roll_keep_for 720h
		}
		level INFO
		format json
	}
}

*.example.com {

	tls dns cloudflare {env.CF_API_TOKEN}

	@app1 host app1.example.com
	handle @app1 {
		reverse_proxy webapp:8000
	}

	@app2 host app2.example.com
	handle @app2 {
		reverse_proxy webapp:8000
	}
}
Optionally, you could use the global option instead of the directive.
{
	acme_dns cloudflare {env.CF_API_TOKEN}
	log {
		output file /var/log/caddy/admin.log {
			roll_size 1mb
			roll_keep 10
			roll_keep_for 720h
		}
		level INFO
		format json
	}
}

*.example.com {

	@app1 host app1.example.com
	handle @app1 {
		reverse_proxy webapp:8000
	}

	@app2 host app2.example.com
	handle @app2 {
		reverse_proxy webapp:8000
	}
}

I found this on the Caddy docs about wildcard certificates, and it looks like what you gave me. I haven’t yet tested this, but this looks very promising for my use-case. Thank you very much!

1 Like

Yes. Just have Caddy get an external certificate from Letsencrypt using DNS, and then you can use it with or without Cloudflare.

There’s a simpler way, though undocumented yet - use auto_https prefer_wildcard in the global options block. Then you can just define your sites normally, rather than having to use matchers. See Missing document on prefer_wildcard for auto_https · Issue #456 · caddyserver/website · GitHub

So you would just have

{
    auto_https prefer_wildcard
}

*.example.com {
    tls dns cloudflare {env.CF_API_TOKEN}
}

app1.example.com {
	reverse_proxy webapp:8000
}
1 Like