I have a good configuration from v2 that redirects all :80 traffic to :443 and has a wildcard certificate for the domain. HTTP/2 has worked flawlessly for a long time. My configuration is relatively simple (a few services in a docker compose file) so upgrading to v3 required no changes. I enabled HTTP/3 on my TLS entrypoint (:443) and opened port 443 for UDP traffic in the compose file.
netstat shows the service listening on UDP port 443 locally and nmap/netcat from another host on the LAN indicate traffic is not blocked by any firewalls (neither device nor network). Firefox and curl connect to the server but fail to upgrade the connection to HTTP/3.
curl -I
shows the svc-adv seems to be coming through OK:
alt-svc: h3=":443"; ma=2592000
curl --http3
works because it falls back to HTTP/2 while curl --http3-only
displays the following verbose output after a 30 second timeout:
* Host my.domain:443 was resolved.
* IPv6: (none)
* IPv4: 192.168.0.2
* Trying 192.168.0.2:443...
* QUIC cipher selection: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* QUIC connection has been shut down
* QUIC connect to 192.168.0.2 port 443 failed: Couldn't connect to server
* Failed to connect to my.domain port 443 after 30123 ms: Couldn't connect to server
* Closing connection
curl: (7) QUIC connection has been shut down
Any tips would be appreciated. Thanks!
Share your full Traefik static and dynamic config, and docker-compose.yml
if used.
Thanks bluepuma77, docker-compose.yml:
version: "3.7"
networks:
# network for services proxied by traefik
frontend:
ipam:
config:
- subnet: 172.31.0.0/24
# gateway will be 172.31.0.1
secrets:
namecheap_key:
file: secrets/namecheap_key
namecheap_user:
file: secrets/namecheap_user
volumes:
traefik-acme:
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
command:
- --global.checknewversion=false
- --global.sendanonymoususage=false
- --api=true
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.portal.address=:8880
- --entrypoints.portal.http.redirections.entryPoint.to=websecure
- --entrypoints.websecure.address=:443
- --entrypoints.websecure.http.tls.certResolver=leresolver
- --entrypoints.websecure.http.tls.domains[0].main=$DOMAIN
- --entrypoints.websecure.http.tls.domains[0].sans=*.$DOMAIN
- --entrypoints.websecure.http3
- --certificatesresolvers.leresolver.acme.email=admin@$DOMAIN
- --certificatesresolvers.leresolver.acme.storage=/acme/acme.json
- --certificatesresolvers.leresolver.acme.dnschallenge.provider=namecheap
- --certificatesresolvers.leresolver.acme.dnschallenge.delaybeforecheck=90
- --providers.docker=true
- --providers.docker.defaultRule=Host(`{{ index .Labels "com.docker.compose.service"}}.$DOMAIN`)
- --providers.docker.network=docker_frontend
- --providers.file.directory=/config
environment:
NAMECHEAP_API_KEY_FILE: /run/secrets/namecheap_key
NAMECHEAP_API_USER_FILE: /run/secrets/namecheap_user
TZ:
networks:
frontend:
ipv4_address: 172.31.0.254
ports:
- "80:80"
- "443:443/tcp"
- "443:443/udp"
- "8880:8880"
volumes:
- traefik-acme:/acme
- $DOCKERDIR/traefik/config:/config
- "/var/run/docker.sock:/var/run/docker.sock:ro"
secrets:
- namecheap_key
- namecheap_user
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=websecure
- traefik.http.routers.traefik.service=api@internal
unifi:
user: unifi
image: ghcr.io/jacobalberty/unifi-docker
container_name: unifi
restart: unless-stopped
ports:
- "8080:8080"
- "8443:8443"
- "3478:3478/udp"
environment:
TZ:
networks:
frontend:
volumes:
- $DOCKERDIR/unifi:/unifi
labels:
- traefik.enable=true
- traefik.http.routers.unifi.entrypoints=websecure
- traefik.http.routers.unifi.service=unifi-docker
- traefik.http.services.unifi-docker.loadbalancer.server.port=8443
- traefik.http.services.unifi-docker.loadbalancer.server.scheme=https
- traefik.http.services.unifi-docker.loadbalancer.serverstransport=unifi@file
- traefik.http.routers.portal.rule=Host(`portal.$DOMAIN`)
- traefik.http.routers.portal.entrypoints=websecure
- traefik.http.routers.portal.service=portal-docker
- traefik.http.services.portal-docker.loadbalancer.server.port=8880
- traefik.http.services.portal-docker.loadbalancer.server.scheme=http
dynamic configuration:
http:
routers:
dsm:
entrypoints:
- websecure
service: dsm-synology
rule: Host(`dsm.my.domain`)
services:
dsm-synology:
loadBalancer:
servers:
- url: http://172.31.0.1:5000/
serversTransports:
unifi:
insecureSkipVerify: true
middlewares:
https-redirect:
redirectScheme:
scheme: https
permanent: true
port: "443"
secure-headers:
headers:
contentTypeNosniff: true
customFrameOptionsValue: "SAMEORIGIN"
stsSeconds: 31536000
stsIncludeSubdomains: true
referrerPolicy: "same-origin"
customResponseHeaders:
server: ""
Permissions-Policy: "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
Maybe try
--entryPoints.name.http3=true
Did you read the note (doc):
As HTTP/3 actually uses UDP, when traefik is configured with a TCP entryPoint on port N with HTTP/3 enabled, the underlying HTTP/3 server that is started automatically listens on UDP port N too. As a consequence, it means port N cannot be used by another UDP entryPoint. Since HTTP/3 requires the use of TLS, only routers with TLS enabled will be usable with HTTP/3.
Adding =true
didn't seem to have any effect. Yes, I saw that note. You'll see in my static (cli) config that there are no UDP entrypoints defined--just the three http entrypoints. And yes, all of the routers using the websecure entrypoint (which are all of them) use the static TLS configuration (letsencrypt resolver) and the traefik GUI is showing TLS=true for all routers.
Hmm. Doesn't seem like much there except a convenient link to the docs we both have read. I'll give it a few more days and if nobody has any ideas here I'll probably file a bug report. I suspect there is something non-obvious about my configuration that is to blame, but given that you've also looked over my work and don't see anything obviously wrong, that suggests either the docs need improving or there is a legit bug.