2026-10-30 OVH1 101 (proxy) enable HTTP/3 for beta.openfoodfacts.net#
In order to enabling HTTP/3 for the first canary, it was was enabled for the OFF Explorer staging deployment. Following a guide from PB was followed. In the 101 LXC container, the QUIC key was generated and excluded from etckeeper.
$ mkdir -p /etc/nginx/ssl/
$ openssl rand -base64 32 > /etc/nginx/ssl/quic_host.key
$ chmod 400 /etc/nginx/ssl/quic_host.key
$ chown www-data:www-data /etc/nginx/ssl/quic_host.key
$ echo "nginx/ssl/quic_host.key" >> /etc/.gitignore
$ git add /etc/.gitignore
$ git commit -m "chore: Ignore QUIC key from git"
Created a new reusable HTTP/3 config at /opt/openfoodfacts-infrastructure/confs/ovh1-reverse-proxy/nginx/conf.d/http3.conf, and created a new symlink
http3_stream_buffer_size 1m;
quic_retry on;
ssl_early_data off;
quic_gso off;
quic_host_key /etc/nginx/ssl/quic_host.key;
$ ln -s /opt/openfoodfacts-infrastructure/confs/ovh1-reverse-proxy/nginx/conf.d/http3.conf /etc/nginx/conf.d/http3.conf
and updated the nginx/sites-enabled/beta.openfoodfacts.net.conf to enable HTTP/3:
diff --git a/confs/ovh1-reverse-proxy/nginx/sites-enabled/beta.openfoodfacts.net.conf b/confs/ovh1-reverse-proxy/nginx/sites-enabled/beta.openfoodfacts.net.conf
index 8f1054a16..32ab3a7fd 100644
--- a/confs/ovh1-reverse-proxy/nginx/sites-enabled/beta.openfoodfacts.net.conf
+++ b/confs/ovh1-reverse-proxy/nginx/sites-enabled/beta.openfoodfacts.net.conf
@@ -6,6 +6,7 @@ map $uri $beta_off_net_basic_auth_setting {
server {
listen 443 ssl; # managed by Certbot
+ listen 443 quic reuseport;
ssl_certificate /etc/letsencrypt/live/beta.openfoodfacts.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/beta.openfoodfacts.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
@@ -14,6 +15,9 @@ server {
server_name beta.openfoodfacts.net;
http2 on;
+ http3 on;
+
+ add_header Alt-Svc 'h3=":443"; ma=3600, h3-29=":443"; ma=3600' always;
# off:off basic username to avoid indexation by bots (it's staging env)
auth_basic_user_file /etc/nginx/off.htpasswd;
Allowed UDP 443 in the firewall:
$ iptables -A INPUT -p udp -m udp --dport 443 -j ACCEPT
$ ip6tables -A INPUT -p udp -m udp --dport 443 -j ACCEPT
From another host, the connection was tested successfully using docker run -it --rm ymuski/curl-http3 curl -ILv https://beta.openfoodfacts.net/health --http3-only, http3check, and http3-test.
I tested without the Alt-Svc header first, as asked for in https://github.com/openfoodfacts/openfoodfacts-infrastructure/issues/679#issue-5292086065. For each nginx config change, I first ran nginx -t and upon success systemctl reload nginx.service.
The UDP firewall rules were manually added to /etc/iptables/rules.v4 and /etc/iptables/rules.v6, as no other management tool seems to be in place.
Rollout checklist progress (OVH1 CT 101 canary)#
Scope: only OVH1 LXC container 101 (reverse proxy) for beta.openfoodfacts.net was checked/performed. No access to Scaleway, KS1, or other edges. Baseline items were not performed and are intentionally omitted from this report.
Verify the runtime on every edge#
- [x] (OVH1/101 only) Runtime checked on the canary edge; no access to Scaleway/KS1.
- [x] (OVH1/101)
nginx -Vcontains--with-http_v3_module. - [x] (OVH1/101) TLS 1.3 enabled and NGINX uses the expected OpenSSL runtime.
- [x] (OVH1/101) Kernel supports
SO_REUSEPORT(native in PVE 6 kernel). - [X] Keep 0-RTT, QUIC GSO, and QUIC eBPF disabled for the initial rollout
Open UDP/443#
- [ ] Add a protocol-specific
iptables_public_udp_portsvariable to the Ansible firewall role — not done (manual change on OVH1/101 only). - N/A Generate IPv4 and IPv6 UDP rules from that variable (Ansible path not used).
- N/A Set
iptables_public_udp_ports: [443]forscaleway-proxy(no access). - [x] (OVH1/101, deviation from checklist) UDP/443 opened via
iptables/ip6tableson CT 101 and persisted manually in/etc/iptables/rules.v4and/etc/iptables/rules.v6; not via effective OVH nftables config / repo safe reload procedure. - N/A Audit and open UDP/443 in the KS1 host firewall (no access).
- [~] End-to-end UDP/443 verification: external connection from the Internet (browser/client) was successful; Proxmox firewall was not changed (only CT 101) and appeared not relevant. Provider firewall/security groups, full Proxmox host/container firewall audit, routing/NAT, and both address families were not fully verified as a checklist audit.
- [ ] Verify that current fail2ban actions also block abusive QUIC clients — not checked.
QUIC key and NGINX configuration#
- [x] (OVH1/101) Persistent host-local QUIC key created at
/etc/nginx/ssl/quic_host.key(deviation from checklist path/etc/nginx/quic_host.key), mode400(chmod 400), ownerwww-data:www-data, excluded frometckeeper/Git via/etc/.gitignore; not committed. Other edges: no access. - [x] Key generated once manually (
openssl rand -base64 32); no automation guard/“only when absent” logic documented. - [x]
quic_host_key /etc/nginx/ssl/quic_host.key;andquic_retry on;configured (inhttp3.conf). - [x] (OVH1/101, IPv4) QUIC listener added alongside TCP:
listen 443 quic reuseport;andhttp3 on;inbeta.openfoodfacts.netvhost;http2 on;retained. No IPv6 QUIC listener added. - [x]
nginx -trun before each config change/reload; complete assembled config tested as part of reload workflow.
Canary without browser advertisement#
- [x] QUIC listener enabled on
beta.openfoodfacts.netwithoutAlt-Svcfirst. -
[x] UDP socket confirmed with
ss -lunp:root@proxy:/# ss -lunp State Recv-Q Send-Q Local Address:Port Peer Address:Port Process UNCONN 0 0 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=30535,fd=93),("nginx",pid=30534,fd=93),("nginx",pid=30533,fd=93),("nginx",pid=30532,fd=93),("nginx",pid=29172,fd=93)) UNCONN 0 0 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=30535,fd=92),("nginx",pid=30534,fd=92),("nginx",pid=30533,fd=92),("nginx",pid=30532,fd=92),("nginx",pid=29172,fd=92)) UNCONN 0 0 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=30535,fd=91),("nginx",pid=30534,fd=91),("nginx",pid=30533,fd=91),("nginx",pid=30532,fd=91),("nginx",pid=29172,fd=91)) UNCONN 0 0 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=30535,fd=90),("nginx",pid=30534,fd=90),("nginx",pid=30533,fd=90),("nginx",pid=30532,fd=90),("nginx",pid=29172,fd=90))
- [x] External HTTP/3 test succeeded (
docker run -it --rm ymuski/curl-http3 curl -ILv https://beta.openfoodfacts.net/health --http3-only, http3check, http3-test). - [x] HTTP/2 and HTTP/1.1 over TCP still work (checked).
- [x] Client fallback when UDP/443 blocked: UDP was temporarily blocked on the server again; fallback in Edge on the client occurred without noticeable delay.
Advertise and observe the beta canary#
- [x]
Alt-Svcadded for beta responses (deviation from checklist value):add_header Alt-Svc 'h3=":443"; ma=3600, h3-29=":443"; ma=3600' always;. - [~] Header verification partially checked (not fully verified across HTML, immutable assets, redirects, errors, and all locations that define their own
add_headerdirectives). - [X] HTTP/3 usage successfully recorded in logs (
$http3/$server_protocolor equivalent). - [ ] No multi-day monitoring documented (NGINX QUIC errors, worker stability, CPU, memory, UDP drops, latency, fallback behavior).
Expand to static/image hosts#
- [ ] (Out of scope) Enable/advertise HTTP/3 for shared
static.openfoodfacts.net/images.openfoodfacts.netvhost — not done (beta canary only). - [ ]
mapolicy deviation: beta already usesma=86400(no stagedma=3600→ma=86400documented). - N/A Scaleway
static.openfoodfacts.orghost-based advertisement — no access / not done. - N/A Verify
add_headerinheritance in every relevant location on other edges — no access / not done. - N/A
images.openfoodfacts.orgKS1 rollout — no access / not done. - N/A KS1
Alt-Svcinheritance in local-file and@proxy2paths — no access / not done. - N/A KS1 image/cache/range/404/large-image tests — no access / not done.
Monitoring#
- N/A/No External HTTP/3-only probe per enabled hostname (canary scope).
- N/A/No Normal TCP HTTPS availability probe retained as primary check (no monitoring change documented).
- N/A/No Alerts for UDP/443 down, HTTP/3-only failures, or missing
Alt-Svc. - N/A/No Separate IPv4/IPv6 probes.
- N/A/No Protocol share/performance comparison before/after.