Can not get http/3 to work

caddy version v2.6.2, mac os

Hello,

I can not get caddy to provide http/3.
Can anybody help?

Thanks.
Chris

Caddy Response Header is:
HTTP/2 200 OK
alt-svc: h3=“:443”; ma=2592000
content-encoding: gzip
content-type: text/html; charset=UTF-8
server: Caddy
vary: Accept-Encoding
vary: Accept-Encoding
x-powered-by: caddy local proxy
x-powered-by: PHP/8.2.1
date: Sun, 29 Jan 2023 21:31:59 GMT
X-Firefox-Spdy: h2

caddyfile is

localhost:443 {
handle * {
root * …/Sites
php_fastcgi 127.0.0.1:9000
file_server browse
encode zstd gzip
header x-powered-by “caddy local proxy”
header vary Accept-Encoding
header Strict-Transport-Security max-age=31536000;
}

encode {
	gzip 4
	minimum_length 256

	match {
		header Content-Type text/*
		header Content-Type application/json*
		header Content-Type application/javascript*
		header Content-Type application/xhtml+xml*
		header Content-Type application/atom+xml*
		header Content-Type application/rss+xml*
		header Content-Type image/svg+xml*
		header Content-Type application/ld+json*
		header Content-Type application/manifest+json*
		header Content-Type application/vnd.geo+json*
		header Content-Type application/vnd.ms-fontobject*
		header Content-Type application/x-font-ttf*
		header Content-Type application/x-web-app-manifest+json*
		header Content-Type application/xml*
		header Content-Type font/opentype*
		header Content-Type image/bmp*
		header Content-Type image/x-icon*
		header Content-Type text/cache-manifest*
	}
}

tls localhost.pem localhost-key.pem

}

Please fill out the help topic template, as per the forum rules.

Please mind your post’s formatting.

1. Caddy version:

v2.6.2

2. How I installed, and run Caddy:

installed with homebrew

a. System environment:

mac os ventura 13.2 (22D49)
Firefox 109
Chrome 109

b. Command:

caddy run --watch

c. Service/unit/compose file:

Paste full file contents here.
Make sure backticks stay on their own lines,
and the post looks nice in the preview pane.

d. My complete Caddy config:

localhost:4443 {
	handle * {
		root * /Users/chris/Sites
		php_fastcgi 127.0.0.1:9000
		file_server browse
		encode zstd gzip
		header x-powered-by "caddy local proxy"
	}

	encode {
		gzip 4
		minimum_length 256

		match {
			header Content-Type text/*
			header Content-Type application/json*
			header Content-Type application/javascript*
			header Content-Type application/xhtml+xml*
			header Content-Type application/atom+xml*
			header Content-Type application/rss+xml*
			header Content-Type image/svg+xml*
			header Content-Type application/ld+json*
			header Content-Type application/manifest+json*
			header Content-Type application/vnd.geo+json*
			header Content-Type application/vnd.ms-fontobject*
			header Content-Type application/x-font-ttf*
			header Content-Type application/x-web-app-manifest+json*
			header Content-Type application/xml*
			header Content-Type font/opentype*
			header Content-Type image/bmp*
			header Content-Type image/x-icon*
			header Content-Type text/cache-manifest*
		}
	}

	tls internal
}

3. The problem I’m having:

https://localhost:4443/index.html

I can not get caddy to serve http/3.
Response header is http/2 with alt-svc: h3 but the browser does not switch to http/3.
Nor on reload, or clean cache.

HTTP/2 200 OK
alt-svc: h3=“:443”; ma=2592000
content-encoding: gzip
content-type: text/html; charset=UTF-8
server: Caddy
vary: Accept-Encoding
vary: Accept-Encoding
x-powered-by: caddy local proxy
x-powered-by: PHP/8.2.1
date: Sun, 29 Jan 2023 21:31:59 GMT
X-Firefox-Spdy: h2

4. Error messages and/or full log output:

2023/01/30 13:32:28.374	INFO	using adjacent Caddyfile
2023/01/30 13:32:28.375	WARN	Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies	{"adapter": "caddyfile", "file": "Caddyfile", "line": 37}
2023/01/30 13:32:28.377	INFO	admin	admin endpoint started	{"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2023/01/30 13:32:28.377	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc0002553b0"}
2023/01/30 13:32:28.383	INFO	http	enabling automatic HTTP->HTTPS redirects	{"server_name": "srv0"}
2023/01/30 13:32:28.394	INFO	pki.ca.local	root certificate is already trusted by system	{"path": "storage:pki/authorities/local/root.crt"}
2023/01/30 13:32:28.395	INFO	tls	cleaning storage unit	{"description": "FileStorage:/Users/chris/Library/Application Support/Caddy"}
2023/01/30 13:32:28.395	INFO	http	enabling HTTP/3 listener	{"addr": ":4443"}
2023/01/30 13:32:28.395	INFO	http.log	server running	{"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2023/01/30 13:32:28.395	INFO	http.log	server running	{"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2023/01/30 13:32:28.395	INFO	http	enabling automatic TLS certificate management	{"domains": ["localhost"]}
2023/01/30 13:32:28.396	INFO	tls	finished cleaning storage units
2023/01/30 13:32:28.397	WARN	tls	stapling OCSP	{"error": "no OCSP stapling for [localhost]: no OCSP server specified in certificate", "identifiers": ["localhost"]}
2023/01/30 13:32:28.397	INFO	autosaved config (load with --resume flag)	{"file": "/Users/chris/Library/Application Support/Caddy/autosave.json"}
2023/01/30 13:32:28.397	INFO	serving initial configuration
2023/01/30 13:32:28.397	INFO	watcher	watching config file for changes	{"config_file": "Caddyfile"}

5. What I already tried:

I tried differnt ports 443, 9443, 4443.
Disabled apache.
Tried with different tls parameters, such das “internal” and also providing selfcreated certification files (pem/key).
Also tried with experimental_http3 option in config file - which resulted in invalid option error.
Same with “protocol h2 h3” option.

6. Links to relevant resources:

Checked postings in caddy forum.

Thank you for your help.
Chris

1. Caddy version:

caddy version v2.6.2

2. How I installed, and run Caddy:

brew install caddy

a. System environment:

MacOSX Ventura
Firefox 109
Chrome 109

b. Command:

caddy run --watch

c. Service/unit/compose file:

Paste full file contents here.
Make sure backticks stay on their own lines,
and the post looks nice in the preview pane.

d. My complete Caddy config:

localhost:4443 {
	handle * {
		root * /Users/chris/Sites
		php_fastcgi 127.0.0.1:9000
		file_server browse
		encode zstd gzip
		header x-powered-by "caddy local proxy"
	}

	encode {
		gzip 4
		minimum_length 256

		match {
			header Content-Type text/*
			header Content-Type application/json*
			header Content-Type application/javascript*
			header Content-Type application/xhtml+xml*
			header Content-Type application/atom+xml*
			header Content-Type application/rss+xml*
			header Content-Type image/svg+xml*
			header Content-Type application/ld+json*
			header Content-Type application/manifest+json*
			header Content-Type application/vnd.geo+json*
			header Content-Type application/vnd.ms-fontobject*
			header Content-Type application/x-font-ttf*
			header Content-Type application/x-web-app-manifest+json*
			header Content-Type application/xml*
			header Content-Type font/opentype*
			header Content-Type image/bmp*
			header Content-Type image/x-icon*
			header Content-Type text/cache-manifest*
		}
	}

	tls internal
}

3. The problem I’m having:

I can not get caddy to serve http/3, all I get is http/2

HTTP/2 200 OK
alt-svc: h3=“:443”; ma=2592000
content-encoding: gzip
content-type: text/html; charset=UTF-8
server: Caddy
vary: Accept-Encoding
vary: Accept-Encoding
x-powered-by: caddy local proxy
x-powered-by: PHP/8.2.1
date: Sun, 29 Jan 2023 21:31:59 GMT
X-Firefox-Spdy: h2

4. Error messages and/or full log output:

chris@iMac caddy % curl -I --http2 https://localhost:4443
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
chris@iMac caddy % curl -I --http3 https://localhost:4443
HTTP/2 200 OK
alt-svc: h3=“:443”; ma=2592000
content-encoding: gzip
content-type: text/html; charset=UTF-8
server: Caddy
vary: Accept-Encoding
vary: Accept-Encoding
x-powered-by: caddy local proxy
x-powered-by: PHP/8.2.1
date: Sun, 29 Jan 2023 21:31:59 GMT
X-Firefox-Spdy: h2

5. What I already tried:

I tried differnt ports 443, 9443, 4443.
Disabled apache.
Tried “protocol” and “experimental_http3” options which resulted in error, invalid option.
Tried “tls internal” and also “tls” with self created certs.
Nothing works.

Thank you for your help.

6. Links to relevant resources:

Checked all the “http/3” posts in caddy forum, as well as whatever else I found about “caddy http/3”

Hello francis, please delete the first post, that wasn’t formatted correctly. As well as the double post.
Thanks.

You probably need to run sudo caddy trust to make sure Caddy’s internal root CA cert is added to your trust store.

Browsers will often end up not using HTTP/3 because they first make HTTP/2 requests first, then might use H3 if they see Alt-Svc and that it might be a performance benefit to do so. Over localhost, it might never use it because directly connecting to localhost is so fast anyways.

Using curl --http3 is the best way to test it, because it will unconditionally try to connect using HTTP/3.

Try it on an actual server instead, it might work more consistently in browsers.

1 Like

thank you.
I have tried with http/3 compiled CURL:

curl --http3 -I https://www.cloudflare.com/

with response:

HTTP/3 200 
date: Tue, 31 Jan 2023 00:12:04 GMT
content-type: text/html; charset=utf-8
accept-ranges: bytes
....
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400

but when I try curl --http3 -I https://localhost:4443, I do get a blinking cursor only, no result.

when I try curl --http2 -I https://localhost:4443

I get:

curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

that is while https://localhost:4443 in the browser works, but with http/2.

as for “sudo caddy trust” I get the following response:

2023/01/31 00:19:05.739	INFO	root certificate is already trusted by system	{"path": "localhost:2019/pki/ca/local"}

So that is already enabled - but why is it listed on port 2019 not 4443 as defined as listening port in my Caddyfile?

Also, now, when I have apache running in the background (port:80), I get this error when I start caddy with the mentioned Caddyfile:

Error: loading initial config: loading new config: http app module: start: listening on :80: listen tcp :80: bind: address already in use

Can’t I run caddy on port :4443 while apache is listening on port :80?

Thank you!

Because Caddy’s admin API runs on port 2019. The caddy trust command pulls the root CA cert from the admin API, to make sure it uses the correct one.

By default, Caddy will try to enable Automatic HTTPS, which involves setting up an HTTP server (by default, port 80) to perform HTTP->HTTPS redirects, and to solve the ACME HTTP challenge (when you need a publicly trusted cert).

I recommend changing Apache to use a use a different port like 8080 or something, so that Caddy can use port 80.

That doesn’t make sense to me. I’m not sure why curl wouldn’t be trusting Caddy’s cert.

I don’t use a Mac, so I can’t really suggest anything to try there.

thank you.

I have it running side by side with apache, but no http/3 yet.
Is there anything I have to add to Caddyfile?
Any SSL settings or link to self created SSL certifcate such as with apache or nginx?

Also experimental_http3 option is not recognized:

{
	servers {
		protocol {
			experimental_http3
		}
	}
}

Error: adapting config using caddyfile: parsing caddyfile tokens for ‘servers’: …/conf/Caddyfile:4 - Error during parsing: unrecognized protocol option ‘experimental_http3’

No, experimental_http3 was only necessary prior to v2.6.0. In that version, we enabled HTTP/3 by default.

On my mac, caddy http3 is working perfectly. Though I am not using curl but write a simple golang http3 client.

Golang code:

func TestHttp3(t *testing.T) {
	config := &tls.Config{ServerName: "example.com"}
	client := &http.Client{Transport: &http3.RoundTripper{TLSClientConfig: config}}
	resp, err := client.Get("https://127.0.0.1")
	t.Log(resp, err)
}

Caddyfile

https://127.0.0.1 {
    tls /tmp/example.com.crt /tmp/example.com.key
    respond "Hello"
}

Test output

1 Like

Thanks.
Your Caddyfile works on Firefox & Chrome and returns “Hello”, with http/2, not http/3.

The go script fails with:

package main

import (
	"net/http"
)

func TestHttp3(t *testing.T) {
	config := &tls.Config{ServerName: "localhost"}
	client := &http.Client{Transport: &http3.RoundTripper{TLSClientConfig: config}}
	resp, err := client.Get("https://127.0.0.1")
	t.Log(resp, err)
}
./caddy.go:7:19: undefined: testing
./caddy.go:8:13: undefined: tls
./caddy.go:9:37: undefined: http3

Any idea?

You need to import those packages.

package main

import (
	"crypto/tls"
	"github.com/quic-go/quic-go/http3"
	"net/http"
	"testing"
)

func TestHttp3(t *testing.T) {
	config := &tls.Config{ServerName: "localhost"}
	client := &http.Client{Transport: &http3.RoundTripper{TLSClientConfig: config}}
	resp, err := client.Get("https://127.0.0.1")
	t.Log(resp, err)
}

In my environment, chrome also uses h2 even though h3 is available. It’s a browser thing.

1 Like

I have added the packages to the script and.

sudo git clone https://github.com/quic-go/quic-go.git
in
/opt/local/lib/go/src

now I get

/opt/local/lib/go/src/quic-go/http3/client.go:20:2: no required module provides package github.com/quic-go/qpack: go.mod file not found in current directory or any parent directory; see 'go help modules'
/opt/local/lib/go/src/quic-go/http3/body.go:8:2: no required module provides package github.com/quic-go/quic-go: go.mod file not found in current directory or any parent directory; see 'go help modules'
/opt/local/lib/go/src/quic-go/http3/server.go:17:2: no required module provides package github.com/quic-go/quic-go/internal/handshake: go.mod file not found in current directory or any parent directory; see 'go help modules'
/opt/local/lib/go/src/quic-go/http3/client.go:15:2: no required module provides package github.com/quic-go/quic-go/internal/protocol: go.mod file not found in current directory or any parent directory; see 'go help modules'
/opt/local/lib/go/src/quic-go/http3/client.go:16:2: no required module provides package github.com/quic-go/quic-go/internal/qtls: go.mod file not found in current directory or any parent directory; see 'go help modules'
/opt/local/lib/go/src/quic-go/http3/client.go:17:2: no required module provides package github.com/quic-go/quic-go/internal/utils: go.mod file not found in current directory or any parent directory; see 'go help modules'
/opt/local/lib/go/src/quic-go/http3/capsule.go:6:2: no required module provides package github.com/quic-go/quic-go/quicvarint: go.mod file not found in current directory or any parent directory; see 'go help modules'

Not familiare with go …

Don’t clone the repo like that.

Put the text I gave you above in main.go. Make a go.mod file beside it, put module http3-test in it and that’s it. Run go mod tidy, then go build. Then you can run ./http3-test

hm, after go build, I get

runtime.main_main·f: function main is undeclared in the main package

Alright, from the top.

Make a file http3_test.go and put this in it:

package http3_test

import (
	"crypto/tls"
	"github.com/quic-go/quic-go/http3"
	"net/http"
	"testing"
)

func TestHttp3(t *testing.T) {
	config := &tls.Config{ServerName: "localhost"}
	client := &http.Client{Transport: &http3.RoundTripper{TLSClientConfig: config}}
	resp, err := client.Get("https://localhost")
	t.Log(resp, err)
}

Create a file go.mod beside it, put this in it:

module http3_test

Run go mod tidy

You should see some go: lines from figuring out the dependencies.

Run go test -v http3_test.go

You should see this:

=== RUN   TestHttp3
    http3_test.go:14: &{200 OK 200 HTTP/3.0 3 0 map[Content-Type:[text/plain; charset=utf-8] Server:[Caddy]] 0xc0005960c0 -1 [] false false map[] 0xc00017e000 0xc000538000} <nil>
--- PASS: TestHttp3 (0.01s)
PASS
ok  	command-line-arguments	0.012s
1 Like

Now I get:

cat go.mod
package http3_test
go mod tidy
go: errors parsing go.mod:
/usr/local/Cellar/caddy/2.6.2/conf/go.mod:1: unknown directive: package
cat http3_test.go
package http3_test

import (
	"crypto/tls"
	"github.com/quic-go/quic-go/http3"
	"net/http"
	"testing"
)

func TestHttp3(t *testing.T) {
	config := &tls.Config{ServerName: "localhost"}
	client := &http.Client{Transport: &http3.RoundTripper{TLSClientConfig: config}}
	resp, err := client.Get("https://localhost")
	t.Log(resp, err)
}