Acme error 405 "The request message was malformed" or "Method not allowed"

Hi

1. The problem I’m having:

My certificate is not renewing and has expired. I’m geting the “malformed request” error with zerossl and “Method not allowed” with letsencrypt.

2. Error messages and/or full log output:

The issue is reflected in the log file as follow:



DEBUG	no solver configured	{"challenge_type": "dns-01"}
2025/03/05 20:55:16.244	DEBUG	http request	{"method": "POST", "url": "https://acme-v02.api.letsencrypt.org/acme/authz/2264741945/485318515541", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Boulder-Requester":["2264741945"],"Cache-Control":["public, max-age=0, no-cache"],"Content-Length":["400"],"Content-Type":["application/json"],"Date":["Wed, 05 Mar 2025 20:55:16 GMT"],"Link":["<https://acme-v02.api.letsencrypt.org/directory>;rel=\"index\""],"Replay-Nonce":["O_IBgPpLoaVBPkze505Qio0OJB4ZnFW0pALyIw33nYT-khpH5SU"],"Server":["nginx"],"Strict-Transport-Security":["max-age=604800"],"X-Frame-Options":["DENY"]}, "status_code": 200}
2025/03/05 20:55:16.245	ERROR	tls.obtain	could not get certificate from issuer	{"identifier": "*.local.wyse.top", "issuer": "acme-v02.api.letsencrypt.org-directory", "error": "[*.local.wyse.top] solving challenges: *.local.wyse.top: no solvers available for remaining challenges (configured=[http-01 tls-alpn-01] offered=[dns-01] remaining=[dns-01]) (order=https://acme-v02.api.letsencrypt.org/acme/order/2264741945/360561434541) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
2025/03/05 20:55:16.245	DEBUG	tls.obtain	trying issuer 2/2	{"issuer": "acme.zerossl.com-v2-DV90"}
2025/03/05 20:55:16.245	DEBUG	tls.issuance.acme	using existing ACME account because key found in storage associated with email	{"email": "caddy@email.com", "ca": "https://acme.zerossl.com/v2/DV90"}
2025/03/05 20:55:16.245	INFO	tls.issuance.acme	waiting on internal rate limiter	{"identifiers": ["*.local.wyse.top"], "ca": "https://acme.zerossl.com/v2/DV90", "account": "caddy@email.com"}
2025/03/05 20:55:16.245	INFO	tls.issuance.acme	done waiting on internal rate limiter	{"identifiers": ["*.local.wyse.top"], "ca": "https://acme.zerossl.com/v2/DV90", "account": "caddy@email.com"}
2025/03/05 20:55:16.245	INFO	tls.issuance.acme	using ACME account	{"account_id": "https://acme.zerossl.com/v2/DV90/account/wNsze-F_7V6HSVv_0zpoBg", "account_contact": ["mailto:caddy@email.com"]}
2025/03/05 20:55:16.469	DEBUG	http request	{"method": "GET", "url": "https://acme.zerossl.com/v2/DV90", "headers": {"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Access-Control-Allow-Origin":["*"],"Content-Length":["712"],"Content-Type":["application/json"],"Date":["Wed, 05 Mar 2025 20:55:16 GMT"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]}, "status_code": 200}
2025/03/05 20:55:16.469	DEBUG	creating order	{"account": "https://acme.zerossl.com/v2/DV90/account/wNsze-F_7V6HSVv_0zpoBg", "identifiers": ["*.local.wyse.top"]}
2025/03/05 20:55:20.789	DEBUG	http request	{"method": "HEAD", "url": "https://acme.zerossl.com/v2/DV90/newNonce", "headers": {"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Type":["application/octet-stream"],"Date":["Wed, 05 Mar 2025 20:55:20 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["JwQSQiLXuLLhGn0_DXwoVrcGPajqzxx1I5cP83Ye1CU"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]}, "status_code": 200}
2025/03/05 20:55:25.748	DEBUG	http request	{"method": "POST", "url": "https://acme.zerossl.com/v2/DV90/newOrder", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["278"],"Content-Type":["application/json"],"Date":["Wed, 05 Mar 2025 20:55:25 GMT"],"Location":["https://acme.zerossl.com/v2/DV90/order/CJQekZxEc7Ve53f5_jNZ2Q"],"Replay-Nonce":["fYPME1jSoYpuB4mNW48SBJ7bWL8cVYq7ZlFVKKYJHD8"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]}, "status_code": 201}
2025/03/05 20:55:28.247	DEBUG	http request	{"method": "POST", "url": "https://acme.zerossl.com/v2/DV90/authz/kMRlNS70faRt5X5un-mSKA", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["298"],"Content-Type":["application/json"],"Date":["Wed, 05 Mar 2025 20:55:28 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["urCyucVaXunfqNDxrTLSLXfPl1TbcOBWz5BrEuPHf1o"],"Retry-After":["5"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]}, "status_code": 200}
2025/03/05 20:55:28.247	DEBUG	no solver configured	{"challenge_type": "dns-01"}
2025/03/05 20:55:31.839	DEBUG	http request	{"method": "POST", "url": "https://acme.zerossl.com/v2/DV90/authz/kMRlNS70faRt5X5un-mSKA", "headers": {"Content-Type":["application/jose+json"],"User-Agent":["Caddy/2.9.1 CertMagic acmez (linux; amd64)"]}, "response_headers": {"Access-Control-Allow-Origin":["*"],"Cache-Control":["max-age=0, no-cache, no-store"],"Content-Length":["142"],"Content-Type":["application/json"],"Date":["Wed, 05 Mar 2025 20:55:31 GMT"],"Link":["<https://acme.zerossl.com/v2/DV90>;rel=\"index\""],"Replay-Nonce":["oECSPvkohli-gNIHIuk3ZEVwZDIv4MAXTFM_0rLTKeY"],"Server":["nginx"],"Strict-Transport-Security":["max-age=15724800; includeSubDomains"]}, "status_code": 200}
2025/03/05 20:55:31.839	ERROR	tls.obtain	could not get certificate from issuer	{"identifier": "*.local.wyse.top", "issuer": "acme.zerossl.com-v2-DV90", "error": "[*.local.wyse.top] solving challenges: *.local.wyse.top: no solvers available for remaining challenges (configured=[http-01 tls-alpn-01] offered=[dns-01] remaining=[dns-01]) (order=https://acme.zerossl.com/v2/DV90/order/CJQekZxEc7Ve53f5_jNZ2Q) (ca=https://acme.zerossl.com/v2/DV90)"}
2025/03/05 20:55:31.839	DEBUG	events	event	{"name": "cert_failed", "id": "fcf2ef92-f4a9-44dc-8ffc-7a221ee7f90d", "origin": "tls", "data": {"error":{},"identifier":"*.local.wyse.top","issuers":["acme-v02.api.letsencrypt.org-directory","acme.zerossl.com-v2-DV90"],"renewal":false}}
2025/03/05 20:55:31.839	ERROR	tls.obtain	will retry	{"error": "[*.local.wyse.top] Obtain: [*.local.wyse.top] solving challenges: *.local.wyse.top: no solvers available for remaining challenges (configured=[http-01 tls-alpn-01] offered=[dns-01] remaining=[dns-01]) (order=https://acme.zerossl.com/v2/DV90/order/CJQekZxEc7Ve53f5_jNZ2Q) (ca=https://acme.zerossl.com/v2/DV90)", "attempt": 1, "retrying_in": 60, "elapsed": 16.19275439, "max_duration": 2592000}


3. Caddy version:

v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=
Installed with APT

4. How I installed and ran Caddy:

a. System environment:

Ubuntu1 20.04.2 virtual machine with systemd
Kernel 5.4.0-205-generic

b. Command:

sudo systemctl start caddy


c. Service/unit/compose file:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
EnvironmentFile=/etc/caddy/.env
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
RestartPreventExitStatus=1
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

d. My complete Caddy config:

{

        email caddy@email.com
        log default {
                output file /var/log/caddy.log
                format console
                level debug
                exclude http.log.access
        }

}

(cloudflare) {
        tls {
                dns cloudflare zone_token {env.CF_ZONE_TOKEN} api_token {env.CF_API_TOKEN}
                propagation_delay 10m
                disable_http_challenge
                disable_tlsalpn_challenge
        }
}
*.local.wyse.top {

        @app host app.local.wyse.top
        handle @app {
                reverse_proxy localhost:8081
        }
      
}

So you’ve disabled http and tlsapln challenges, which leaves only the dns challenge. The DNS challenge by default disables the other challenges, so that configuration isn’t necessary. The problem, other than the rate limiter, is that there is no solver configured. I believe the problem is due to the snippet you’re using not being properly referenced by the site blocks.

If this Caddy config is the entire contents of it, and you are trying to use Cloudflare DNS for everything, then you could remove the snippet and add the acme_dns global option to your first block. Otherwise, you need to import your cloudfare snippet. So your two options are below.

Global option
{
	email caddy@email.com
	acme_dns cloudflare {
		zone_token {env.CF_ZONE_TOKEN}
		api_token {env.CF_API_TOKEN}
	}
	log default {
		output file /var/log/caddy.log
		format console
		level debug
		exclude http.log.access
	}
}

*.local.wyse.top {

	@service host app.local.wyse.top
	handle @app {
		reverse_proxy localhost:8081
	} 
}
Import option
{
	email caddy@email.com
	log default {
		output file /var/log/caddy.log
		format console
		level debug
		exclude http.log.access
	}
}

(cloudflare) {
	tls {
		dns cloudflare zone_token {env.CF_ZONE_TOKEN} api_token {env.CF_API_TOKEN}
		propagation_delay 10m
	}
}
*.local.wyse.top {
	import cloudflare
	@service host app.local.wyse.top
	handle @app {
		reverse_proxy localhost:8081
	} 
}

Thanks for the help. There were missing curly brakets in your import dns directive but you helped me find the mistake. Another critical element was the missing resolvers 1.1.1.1 option. I also suspect upgrading caddy overwrote my custom binary with the neccessary cloudflare module. Finally I had inadvertently introduced a ficticious handle configuration error by giving my app a generic name, so the final file looks like this:

{
	email caddy@email.com
	log default {
		output file /var/log/caddy.log
		format console
		level debug
		exclude http.log.access
	}
}

(cloudflare) {
        tls {
                dns cloudflare {
                zone_token {env.CF_ZONE_TOKEN}
                api_token {env.CF_API_TOKEN}
                }
                propagation_delay 1m
                resolvers 1.1.1.1
        }
}
*.local.wyse.top {
        import cloudflare
        @app host app.local.wyse.top
        handle @app {
                reverse_proxy localhost:8081
        }
}
1 Like