SSL/TLS Cloudflare with Custom Hostnames

1. The problem I’m having:

I have the following issue/scenario. We are using debian 11 and caddy as a reverse proxy server to manage an ERP system. We have 2 domains from our own company. then our customer can whitelabel. We use cloudflare as our entry point.
Our own domains are hosted by cloudflare, customer domain is hosted externally.
Via custom Hostnames under the SSL system of cloudflaire we configured DNS-01 config and when checking the dashboard from cloudlfare all settings seems correct, we use Strick until Origin Server.

Now the issue, after a reboot of the proxy server, the custom domains get an SSL handshake failed Error code 525.The config, as far as i know did not change, and before the reboot all was working fine?

When i check in the folder where the SSL certificates are storeed, i see all other SSL domains folders, but the custom certificate for login.parani.co.id is not created/ does not exist

Under login.vanlooveren.info all is working but under login.parani.co.id it fails
Note vanlooveren.info is registred under cloudflair, parani.co.id is not.

2. Error messages and/or full log output:


```
2025/08/18 11:21:35.097	e\[31mERRORe\[0m	tls.obtain	could not get certificate from issuer	{“identifier”: “login.parani.co.id”, “issuer”: “acme-v02.api.letsencrypt.org-directory”, “error”: “\[login.parani.co.id\] solving challenges: presenting for challenge: adding temporary record for zone "parani.co.id.": expected 1 zone, got 0 for parani.co.id. (order=https://acme-staging-v02.api.letsencrypt.org/acme/order/153406413/26722229634) (ca=https://acme-staging-v02.api.letsencrypt.org/directory)”}
2025/08/18 11:21:35.097	e\[31mERRORe\[0m	tls.obtain	will retry	{“error”: “\[login.parani.co.id\] Obtain: \[login.parani.co.id\] solving challenges: presenting for challenge: adding temporary record for zone "parani.co.id.": expected 1 zone, got 0 for parani.co.id. (order=https://acme-staging-v02.api.letsencrypt.org/acme/order/153406413/26722229634) (ca=https://acme-staging-v02.api.letsencrypt.org/directory)”, “attempt”: 12, “retrying_in”: 1800, “elapsed”: 7224.255537743, “max_duration”: 2592000}
2025/08/18 11:21:35.097	e[31mERRORe[0m	cleaning up solver	{"identifier": "login.parani.co.id", "challenge_type": "dns-01", "error": "no memory of presenting a DNS record for \"_acme-challenge.login.parani.co.id\" (usually OK if presenting also failed)"}
github.com/mholt/acmez/v3.(*Client).solveChallenges.func1
	github.com/mholt/acmez/v3@v3.1.2/client.go:318
github.com/mholt/acmez/v3.(*Client).solveChallenges
	github.com/mholt/acmez/v3@v3.1.2/client.go:363
github.com/mholt/acmez/v3.(*Client).ObtainCertificate
	github.com/mholt/acmez/v3@v3.1.2/client.go:136
github.com/caddyserver/certmagic.(*ACMEIssuer).doIssue
	github.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:489
github.com/caddyserver/certmagic.(*ACMEIssuer).Issue
	github.com/caddyserver/certmagic@v0.23.0/acmeissuer.go:382
github.com/caddyserver/caddy/v2/modules/caddytls.(*ACMEIssuer).Issue
	github.com/caddyserver/caddy/v2@v2.10.0/modules/caddytls/acmeissuer.go:288
github.com/caddyserver/certmagic.(*Config).obtainCert.func2
	github.com/caddyserver/certmagic@v0.23.0/config.go:626
github.com/caddyserver/certmagic.doWithRetry
	github.com/caddyserver/certmagic@v0.23.0/async.go:104
github.com/caddyserver/certmagic.(*Config).obtainCert
	github.com/caddyserver/certmagic@v0.23.0/config.go:700
github.com/caddyserver/certmagic.(*Config).ObtainCertAsync
	github.com/caddyserver/certmagic@v0.23.0/config.go:505
github.com/caddyserver/certmagic.(*Config).manageOne.func1
	github.com/caddyserver/certmagic@v0.23.0/config.go:415
github.com/caddyserver/certmagic.(*jobManager).worker
	github.com/caddyserver/certmagic@v0.23.0/async.go:73

```

3. Caddy version:

I am using caddy version 2.10.0 but with the cloudflare module.

4. How I installed and ran Caddy:

caddy is running on a Debian VM with only caddy installed, as we use caddy here only as a reverse proxy.

a. System environment:

Debian GNU/Linux 11 (bullseye) x68, no docker, downloaded the caddy module via website, then uploaded it via ssh to debian server.

b. Command:

systemctl stop caddy
cd /usr/bin/
mv /usr/bin/caddy /usr/bin/caddyold
mv /usr/bin/caddy_linux_amd64_custom /usr/bin/caddy
chmod +x /usr/bin/caddy
systemctl start caddy

c. Service/unit/compose file:

we do not use docker, plain debian with caddy only, no other software, pure proxy server

d. My complete Caddy config:

```
{
	debug
	email ssl@optilog.solutions
	metrics {
		per_host
	}
	admin localhost:2019
    log {
        level WARN
        output file /var/log/caddy/caddy.log
        format console
    }
}

(tlsCloudFlare) {
	tls {
		dns cloudflare 
		resolvers 1.1.1.1
		propagation_timeout 5m
	}
}

(tlsOffloadHandle) {
	# Do Not Offload the ssl cert here, but pass-through until the next Server.
	transport http {
		tls_server_name {host}
		tls
		tls_insecure_skip_verify
	}
}

(cacheable) {
	@cacheable {
		path *.css *.jpg *.jpeg *.png *.gif *.webp *.svg
		not header Cache-Control *no-cache*
	}
	header @cacheable Cache-Control "max-age=31536000"
}

(emptyUserAgentHeader) {
	# Filter out empty or missing user agent strings.
	@blankUserAgent {
		not header User-Agent * # Matches requests where the User-Agent header is empty or missing
	}
	respond @blankUserAgent 403
}

(botUserAgentHeader) {
	# filter out all the bot systems.
	@botUserAgent {
		header_regexp User-Agent "(bot|Googlebot)"
	}
	respond @botUserAgent 403
}

(garbageFilter) {
	# Prevent access to dot-files, except .well-known
	@dotFiles {
		path */.*
		path /wp-admin
		path /wp-content
		path /admin
		path /server
		path /assets
		path /debug
		path /default
		path /js
		path /core
		not path /.well-known/*
	}
	respond @dotFiles 403
}

(erpFilter) {
	redir / /login/Login 302
	# White list of accepted controller.
	@erpController {
		# White list of accepted controller.
		not path /favicon.ico
		not path /manifest.webmanifest
		not path /robots.txt
		path /info.php
		path /index.php
		path */*
	}
	respond @erpController 403
}


(proxyHeader) {
	## Extra Header Configs that defaults to all servers
	header {
		>Server "Caddy" "optiLogProxyServers"
		?Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
		?X-Frame-Options "DENY"
		?X-Content-Type-Options nosniff
		?Referrer-Policy strict-origin-when-cross-origin
		?Permissions-Policy "camera=(self), geolocation=(self)"
	}
}

# Import external Configuration files.
import frontend.caddy
import backend.caddy

# Production allowed customers domains.
https://login.parani.co.id {
    import tlsCloudFlare

	reverse_proxy https://erp.internal:5698 {
		import tlsOffloadHandle
	}
    import erpFilter
    import garbageFilter
    import emptyUserAgentHeader
    import botUserAgentHeader
    import proxyHeader
    import cacheable
}

# Personal test domains
https://login.vanlooveren.info {
    import tlsCloudFlare

	reverse_proxy https://erp.internal:5698 {
		import tlsOffloadHandle
	}
    import erpFilter
    import garbageFilter
    import emptyUserAgentHeader
    import botUserAgentHeader
    import proxyHeader
    import cacheable
}


# Main server configuration - properly configured for HTTPS
:443 {
	tls {
		dns cloudflare 
		resolvers 1.1.1.1
		propagation_timeout 5m
	}
	respond "Access Denied" 403
}

# HTTP to HTTPS redirect
:80 {
	redir https://{host}{uri} 301
}

```

Under the domain https://login.parani.co.id`` {, you specified (via tlsCloudFlare) the following: tls{ dns cloudflare}.

Note vanlooveren.info is registred under cloudflair, parani.co.id is not.

Since you specified that it should fetch the ceritifcates using the DNS provider cloudflare, it tries to do it this way. Because your actual situation is that this domain is not hosted via cloudflare, it doesn’t work

Either put that domain under cloudflare, or remove the dns cloudflare option

1 Like

Oke, how, why…. ugh…

It does work now??? Strange part is that this has been configured for a long time like this without any issue??

I am happy it works but now my question is, it seems that the settings under Cloudflare, for custom Hostnames, means have zero effect than, no need for any of these settings??

Second, now caddy will handle SSL by itself without cloudflare, Meaning HTTP challenge vs DNS-01 i assume???

This means also that only a CNAME has to be added to the customer that forwards login.parani.co.id to login.vanlooveren.info

Thank you for this respons, have a nice day

If the DNS challenge fails, after a while, it will try other challenges, eventually, it tries the HTTP-01 challenge

Do you use Cloudflare’s proxy (origin cloud) for login.vanlooveren.info? I think so because you talked about origin server security settings. Because you can’t CNAME to that from another domain, Cloudflare won’t have a certificate for the customer domain.

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