bunkerity / bunkerity/bunkerweb

[BUG] HTTP/3 (QUIC) issue with IPv6 / IPv4 dual-stack

Open
#3,013 4 comments 0 reactions 1 assignee Claimed by @TheophileDiot View on GitHub
bug core docker
Dominant language
Python
Stars
10.9k
Forks
643
Avg merge
1d 10h
Merged PRs (30d)
42

Description

### What happened?

🐞 Problem description

Hello,

I’ve noticed an unexpected behavior with BunkerWeb related to HTTP/3 (QUIC) when running in a dual-stack IPv4 / IPv6 environment.

I would like to get feedback from the community or the BunkerWeb team to understand whether this is:
- a known bug,
- a misconfiguration on my side,
- or a current limitation.

✅ Expected behavior

1. Services accessible over IPv4 and IPv6
2. Proper support for:
- HTTP/1.1
- HTTP/2
- HTTP/3 (QUIC)
3. HTTP/3 should use the same IP family as the initial connection (IPv4 or IPv6)

❌ Observed behavior

When UDP port 443 is opened to enable HTTP/3:
The browser correctly initiates the connection over IPv6 (HTTPS TCP 443).
Then, the browser attempts to establish a QUIC (HTTP/3) connection.
This QUIC attempt is made only over IPv4, even though the initial connection was IPv6.

Result:
- Connections fail or become unstable
- Services are partially unreachable
- No HTTP/3 IPv6 traffic appears in the logs

⚠️ This issue only happens with BunkerWeb.
I have never experienced this behavior with other reverse proxies or services supporting HTTP/3 in dual-stack environments.

🔍 Additional observations

If UDP 443 is closed, everything works fine (IPv4 & IPv6 over HTTP/1.1 and HTTP/2)
As soon as UDP 443 is opened, issues start

Logs show:
- Initial connection over IPv6
- QUIC attempts only over IPv4
- No QUIC attempts over IPv6
- The issue seems related to QUIC handling in a dual-stack IPv4/IPv6 setup

I have noticed that when I use dual-stack, it establishes the http2 connection in ipv6, but when it tests QUIC, it does so with ipv4. This breaks the tokens and makes the hosted services unstable.
I tested Only IPv4 and Only IPv6 and found no problems.

Thanks in advance for your help.

### How to reproduce?

1. Deploy BunkerWeb 1.6.6 in a Docker container on a host with dual-stack IPv4 and IPv6 (e.g. Proxmox).
2. Expose the container on the LAN with:
- TCP 80
- TCP 443
3. Ensure services are reachable over both IPv4 and IPv6 using HTTP/1.1 and HTTP/2.
4. Open UDP port 443 on the firewall to enable HTTP/3 (QUIC).
5. Access a service using a browser from an IPv6-capable client.
6. Observe that:
- The initial HTTPS connection is established over IPv6.
- The browser then attempts HTTP/3 (QUIC) only over IPv4.
- No QUIC traffic over IPv6 appears in the logs.
7. The connection becomes unstable or fails.

### Configuration file(s) (yaml or .env)

```YAML
x-bw-env: &bw-env
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24"
DATABASE_URI: "mariadb+pymysql://XXXXXXXXXXXXX:XXXXXX@bw-db:3306/XX"
TZ: Europe/Paris

services:
bunkerweb:
image: bunkerity/bunkerweb:1.6.6
labels:
- com.centurylinklabs.watchtower.enable=true
ports:
- "1.1.1.1:80:8080/tcp"
- "1.1.1.1:443:8443/tcp"
- "1.1.1.1:443:8443/udp"
- "[fd01::1]:80:8080/tcp"
- "[fd01::1]:443:8443/tcp"
- "[fd01::1]:443:8443/udp"
environment:
<<: *bw-env
BW_LOGS: "on" # Active les logs dans l'UI
LOGS: "on" # Active les logs en local
ACCESS_LOG: "on"
ERROR_LOG: "on"
EXPORT_LOGS: "on" # Autorise l'UI à lire les logs
LOG_FILES: "access.log,error.log,modsec_audit.log"
restart: unless-stopped
volumes:
- bw-data:/data
- /var/log/bunkerweb:/var/log/bunkerweb
- /var/log/bunkerweb:/data/logs:ro
- /etc/ssl/certs:/etc/ssl/certs:ro
networks:
- bunker
- bw-apps
logging:
driver: "none"

bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.6.6
labels:
- com.centurylinklabs.watchtower.enable=true
environment:
<<: *bw-env
BUNKERWEB_INSTANCES: "bunkerweb"
SERVER_NAME: ""
MULTISITE: "yes"
UI_HOST: "http://bw-ui:7000"
USE_CROWDSEC: "yes"
CROWDSEC_API: "http://host.docker.internal:8080"
CROWDSEC_APPSEC_URL: "http://host.docker.internal:7422"
CROWDSEC_API_KEY: "XXXXXXXXXXXXXXXXXXXXXXXX"
USE_VIRUSTOTAL: "yes"
VIRUSTOTAL_API_KEY: "XXXXXXXXXXXXXXXXXX"
volumes:
- bw-data:/data
- /etc/ssl/certs:/etc/ssl/certs:ro
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- bunker
- bunker-db

bw-ui:
image: bunkerity/bunkerweb-ui:1.6.6
labels:
- com.centurylinklabs.watchtower.enable=true
environment:
<<: *bw-env
restart: unless-stopped
networks:
- bunker
- bunker-db

bw-db:
image: mariadb:11
labels:
- com.centurylinklabs.watchtower.enable=true
environment:
TZ: Europe/Paris
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: "XXX"
MYSQL_USER: "XXXXXXXXXXX"
MYSQL_PASSWORD: "XXXXXXXXXXXXXXXXX"
volumes:
- bw-dbdata:/var/lib/mysql
- /etc/ssl/certs:/etc/ssl/certs:ro
restart: unless-stopped
networks:
- bunker-db

networks:
bunker:
name: bunker
ipam:
driver: default
config:
- subnet: 10.20.30.0/24
bunker-db:
name: bunker-db
bw-apps:
name: bw-apps
external: true

volumes:
bw-data:
bw-dbdata:
```

### Relevant log output

```shell

```

### BunkerWeb version

1.6.6

### What integration are you using?

Docker

### Linux distribution (if applicable)

Ubuntu 24.04.3 LTS (Proxmox Container)

### Removed private data

- [x] I have removed all private data from the configuration file and the logs

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.