Skip to content

Instantly share code, notes, and snippets.

@bagder
Last active March 10, 2024 21:13
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bagder/fe1f5ef823bc3314474725a6cf1f1205 to your computer and use it in GitHub Desktop.
Save bagder/fe1f5ef823bc3314474725a6cf1f1205 to your computer and use it in GitHub Desktop.
Setup an HTTP/3 test server

Setup a local HTTP/3 test server

... to toy with and run curl against it.

This is not advice on how to run anything in production. This is for development and experimenting.

Preqreqs

An existing local HTTP/1.1 server that hosts files. Preferably also a few huge ones. You can easily create huge local files like truncate -s=8G 8GB - they are huge but do not occupy that much space on disk since they're just a big hole.

In my Debian setup I just installed apache2. It runs on port 80 and has a document root in /var/www/html. I can get the 8GB file from it with curl localhost/8GB -o dev/null

Build

ngtcp2

Get, build and install quictls:

git clone https://github.com/quictls/openssl.git
cd openssl
./config enable-tls1_3 --prefix=$HOME/build-quictls
make && make install

Get, build and install nghttp3:

git clone https://github.com/ngtcp2/nghttp3.git
cd nghttp3
autoreconf -fi
./configure --prefix=$HOME/build-nghttp3 --enable-lib-only
make && make install

Get, build and install ngtcp2:

git clone https://github.com/ngtcp2/ngtcp2.git
cd ngtcp2
autoreconf -fi
./configure PKG_CONFIG_PATH=$HOME/build-quictls/lib/pkgconfig:$HOME/build-nghttp3/lib/pkgconfig LDFLAGS="-Wl,-rpath,$HOME/build-quictls/lib" --prefix=$HOME/build-ngtcp2 --without-gnutls
make && make install

nghttpx

(You can opt to use Caddy instead, then you can skip this step)

Get, build and install nghttp2:

git clone https://github.com/nghttp2/nghttp2.git
cd nghttp2
autoreconf -fi
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/daniel/build-quictls/lib/pkgconfig:/home/daniel/build-nghttp3/lib/pkgconfig:/home/daniel/build-ngtcp2/lib/pkgconfig  LDFLAGS=-L/home/daniel/build-quictls/lib CFLAGS=-I/home/daniel/build-quictls/include ./configure --enable-maintainer-mode --prefix=/home/daniel/build-nghttp2 --disable-shared --enable-app --enable-http3 --without-jemalloc --without-libxml2 --without-systemd
make && make install

curl

Get, build and install curl:

git clone https://github.com/curl/curl.git
cd curl
./buildconf
LIBS="-ldl" LDFLAGS="-Wl,-rpath,$HOME/build-quictls/lib -Wl,-rpath,$HOME/build-curl/lib" ./configure --with-nghttp2=$HOME/build-nghttp2 --prefix=$HOME/build-curl --with-openssl=$HOME/build-quictls --with-ngtcp2=$HOME/build-ngtcp2 --with-nghttp3=$HOME/build-nghttp3
make && make install

(Alternative ways to build curl with HTTP/3 support are documented here)

Run

nghttpx

(You can opt to use Caddy instead, see below)

Run the local h3 server on port 9443, make it proxy all traffic through to HTTP/1 on localhost port 80. For local toying, we can just use the test cert that exists in curl's test dir.

CERT=$CURLSRC/tests/stunnel.pem
$HOME/bin/nghttpx $CERT $CERT --backend=localhost,80 \
  --frontend="localhost,9443;quic"

curl

Get the 8GB file over HTTP/3 using our h3-enabled curl:

$HOME/build-curl/bin/curl --http3 https://localhost:9443/8GB -o /dev/null

HTTP/3 server alternative

Caddy

You can run a HTTP/3 reverse-proxy using Caddy instead of nghttpx. Install caddy, you can even put the single binary in a separate directory if you prefer.

In the same directory you put caddy, create a Caddyfile with the following content to run a HTTP/3 reverse-proxy on port 7443:

{
        auto_https disable_redirects
}

localhost:7443 {
	reverse_proxy localhost:80
}

Then run caddy:

./caddy start
@bagder
Copy link
Author

bagder commented Dec 21, 2021

@mholt Thanks for this! To make that match the nghttpx reverse-proxy setup, it would run as a user and only use a >1024 port, let's say 7443 to not collide with nghttpx (and not listen on port 80 nor 443). I don't understand how that should then be setup?

My failed attempt:

{
	servers :7443 {
		protocol {
			experimental_http3
		}
	}
}

localhost:7443 {
	reverse_proxy localhost:80
}

@mholt
Copy link

mholt commented Dec 21, 2021

@bagder Ah, good point. Caddy will automatically redirect HTTP (port 80) to the HTTPS port. The easiest way to change these ports globally for the whole server is to use the http_port and https_port global options:

{
	http_port  7080
	https_port 7443
	servers :7443 {
		protocol {
			experimental_http3
		}
	}
}

localhost {
	reverse_proxy localhost:80
}

Another option is to disable automatic HTTPS redirects instead:

{
	auto_https disable_redirects
	servers :7443 {
		protocol {
			experimental_http3
		}
	}
}

localhost:7443 {
	reverse_proxy localhost:80
}

if you only want to listen on an HTTPS port.

@bagder
Copy link
Author

bagder commented Dec 21, 2021

Thanks, I added that into the actual instruction.

@francislavoie
Copy link

Since Caddy v2.6.0, the experimental_http3 option is no longer needed. The servers block can be removed from the example.

@bagder
Copy link
Author

bagder commented Jan 30, 2023

So how would the complete caddy config look now?

@francislavoie
Copy link

{
	auto_https disable_redirects
}

localhost:7443 {
	reverse_proxy localhost:80
}

@matiasweb
Copy link

Have you thought about making a Docker image? ⭐

@bagder
Copy link
Author

bagder commented May 23, 2023

Feel free to use whatever is in here to make docker images or whatever you please. That is not for me to make. I have other things on my plate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment