Error 421 on Firefox w/ caddy mTLS, cURL works fine

1. The problem I’m having:

I’m trying to setup a Caddy web-server with client authentication (mTLS).

From the client machine, I can take a generated client P12 file debian-pc.p12, pass it into a cURL command with the self-signed root cert root.crt that i used to sign it, and I’m able to connect just fine.

Full cURL output:

curl -vL --cert-type P12 --cert debian-pc.p12:<password> --cacert root.crt https://10.0.0.2
*   Trying 10.0.0.2:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: root.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_CHACHA20_POLY1305_SHA256 / X25519MLKEM768 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
*  subject: 
*  start date: Feb 20 13:16:05 2026 GMT
*  expire date: Feb 21 01:16:05 2026 GMT
*  subjectAltName: host "10.0.0.2" matched cert's IP address!
*  issuer: CN=Caddy Local Authority - ECC Intermediate
*  SSL certificate verify ok.
*   Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256
*   Certificate level 1: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256
*   Certificate level 2: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256
* Connected to 10.0.0.2 (10.0.0.2) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://10.0.0.2/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: 10.0.0.2]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.14.1]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: 10.0.0.2
> User-Agent: curl/8.14.1
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Request completely sent off
< HTTP/2 421 
< alt-svc: h3=":443"; ma=2592000
< server: Caddy
< content-length: 0
< date: Fri, 20 Feb 2026 19:02:23 GMT
< 
* Connection #0 to host 10.0.0.2 left intact

However, once I import the P12 file into the Firefox Certificate Manager and try to connect via browser, it throws Error code: 421 Misdirected Request.

Things I’ve tried:

  • Clearing browser cache
  • Clearing DNS cache
  • Running caddy trust on the client machine
  • Disabling HTTP/2 in the browser
  • Using Chrome (same error)
  • Starting over and completely regenerating the root CA and all keys
  • Restarting caddy
  • Restarting the server and client machines
  • Reinstalling Firefox

This has been giving me a lot of trouble over the past few days. I’m new to Caddy and not a pro at any of this stuff, so do bear with me, any help is much appreciated :slight_smile:

2. Error messages and/or full log output:

journalctl -u caddy -f
Feb 20 13:36:53 home-pi caddy[4082]: {"level":"info","ts":1771612613.8604417,"msg":"define JAVA_HOME environment variable to use the Java trust"}
Feb 20 13:36:53 home-pi caddy[4082]: {"level":"info","ts":1771612613.872483,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/var/lib/caddy/.local/share/caddy","instance":"b9500594-97dd-4a23-b613-b5476e5f3957","try_again":1771699013.8724763,"try_again_in":86399.999997656}
Feb 20 13:36:53 home-pi caddy[4082]: {"level":"info","ts":1771612613.872899,"logger":"tls","msg":"finished cleaning storage units"}
Feb 20 13:36:53 home-pi sudo[4096]: pam_unix(sudo:auth): conversation failed
Feb 20 13:36:53 home-pi sudo[4096]: pam_unix(sudo:auth): auth could not identify password for [caddy]
Feb 20 13:36:53 home-pi sudo[4096]:    caddy : user NOT in sudoers ; PWD=/ ; USER=root ; COMMAND=/usr/bin/tee /usr/local/share/ca-certificates/Caddy_Local_Authority_-_2026_ECC_Root_181431030895689318105254784498745868923.crt
Feb 20 13:36:53 home-pi caddy[4082]: {"level":"error","ts":1771612613.8992815,"logger":"pki.ca.local","msg":"failed to install root certificate","error":"failed to execute sudo: exit status 1","certificate_file":"storage:pki/authorities/local/root.crt"}
Feb 20 13:36:53 home-pi caddy[4082]: {"level":"info","ts":1771612613.9001496,"msg":"autosaved config (load with --resume flag)","file":"/var/lib/caddy/.config/caddy/autosave.json"}
Feb 20 13:36:53 home-pi caddy[4082]: {"level":"info","ts":1771612613.9003837,"msg":"serving initial configuration"}
Feb 20 13:36:53 home-pi systemd[1]: Started caddy.service - Caddy.

3. Caddy version:

caddy version: 2.6.2

4. How I installed and ran Caddy:

I followed the instructions for stable release installation under the Debian, Ubuntu, Raspbian header in the Caddy docs: Install — Caddy Documentation

a. System environment:

Client: Debian, x86_64 CPU, no docker
Server: Raspberry Pi OS, aarch64 CPU

b. Command:

systemctl stop caddy
systemctl start caddy
systemctl restart caddy

d. My complete Caddy config:

# The Caddyfile is an easy way to configure your Caddy web server.
#Test website
10.0.0.2 {
        #Caddy example lives here
        root * /usr/share/caddy
        file_server

        #mTLS verify client
        tls {
                client_auth {
                        #Default is none
                        #there are other options here if you want it to be optional
                        #i.e. to bypass a signin page when using mTLS
                        mode require_and_verify
                        trust_pool file {
                                #Can be specified multiple times for multiple roots
                                pem_file /etc/caddy/root.pem
                        }
                }
        }
}

5. Links to relevant resources:

Thanks!

You’re using WAY too old a version. Use the official installation instructions, don’t use the debian repo package.

1 Like

Now I’m on

v2.10.2 h1:g/gTYjGMD0dec+UgMw8SnfmJ3I9+M2TdvoRL/Ovu6U8=

and still, the same issue :frowning: