commit 8800fabca14901203230beb75f3861a80ca4b400
parent ed65a5cd5e7b91655d9a78cc8d141117fb3f631f
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 22 Mar 2026 22:41:28 +0100
enable HTTP2/HTTP3 by default everywhere, fixes #11223
Diffstat:
9 files changed, 64 insertions(+), 57 deletions(-)
diff --git a/roles/auditor/templates/etc/nginx/sites-available/auditor-nginx.conf.j2 b/roles/auditor/templates/etc/nginx/sites-available/auditor-nginx.conf.j2
@@ -1,31 +1,18 @@
server {
- listen 443 ssl;
- listen [::]:443 ssl;
+ include conf.d/listen.conf.inc;
- # Do not identify as nginx
- server_tokens off;
server_name auditor.{{ domain_name }};
-
ssl_certificate /etc/letsencrypt/live/auditor/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auditor/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/auditor/chain.pem;
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL:10m;
- ssl_dhparam /etc/ssl/private/dhparam.pem;
- ssl_protocols TLSv1.3 TLSv1.2;
- ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
-
- add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
# Bigger than default timeout to support long polling
proxy_read_timeout 6500s;
keepalive_requests 1000000;
keepalive_timeout 6500s;
- if ($http_user_agent ~* "Bytedance|bytespider|Amazonbot|Claude|Anthropic|AI|GPT|acebook") { return 451 ; }
-
error_log /var/log/nginx/auditor.{{ domain_name }}.err;
access_log /var/log/nginx/auditor.{{ domain_name }}.log;
diff --git a/roles/challenger/templates/etc/nginx/sites-available/email-challenger-nginx.conf.j2 b/roles/challenger/templates/etc/nginx/sites-available/email-challenger-nginx.conf.j2
@@ -1,10 +1,6 @@
server {
+ include conf.d/listen.conf.inc;
- listen 443 ssl;
- listen [::]:443 ssl;
-
- # Do not identify as nginx
- server_tokens off;
server_name email.challenger.{{ domain_name }};
include conf.d/challenger-tls.conf.inc;
@@ -14,8 +10,6 @@ server {
keepalive_requests 10000;
keepalive_timeout 650s;
- if ($http_user_agent ~* "Bytedance|bytespider|Amazonbot|Claude|Anthropic|AI|GPT|acebook") { return 451 ; }
-
error_log /var/log/nginx/email.challenger.{{ domain_name }}.err;
access_log /var/log/nginx/email.challenger.{{ domain_name }}.log apm;
diff --git a/roles/challenger/templates/etc/nginx/sites-available/postal-challenger-nginx.conf.j2 b/roles/challenger/templates/etc/nginx/sites-available/postal-challenger-nginx.conf.j2
@@ -1,16 +1,11 @@
server {
- listen 443 ssl;
- listen [::]:443 ssl;
+ include conf.d/listen.conf.inc;
- # Do not identify as nginx
- server_tokens off;
server_name postal.challenger.{{ domain_name }};
include conf.d/challenger-tls.conf.inc;
- add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
-
# Bigger than default timeout to support long polling
proxy_read_timeout 650s;
keepalive_requests 10000;
diff --git a/roles/challenger/templates/etc/nginx/sites-available/sms-challenger-nginx.conf.j2 b/roles/challenger/templates/etc/nginx/sites-available/sms-challenger-nginx.conf.j2
@@ -1,16 +1,11 @@
server {
- listen 443 ssl;
- listen [::]:443 ssl;
+ include conf.d/listen.conf.inc;
- # Do not identify as nginx
- server_tokens off;
server_name sms.challenger.{{ domain_name }};
include conf.d/challenger-tls.conf.inc;
- add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
-
# Bigger than default timeout to support long polling
proxy_read_timeout 650s;
keepalive_requests 10000;
diff --git a/roles/exchange/templates/etc/nginx/sites-available/exchange-nginx.conf.j2 b/roles/exchange/templates/etc/nginx/sites-available/exchange-nginx.conf.j2
@@ -1,10 +1,7 @@
server {
- listen 443 ssl;
- listen [::]:443 ssl;
+ include conf.d/listen.conf.inc;
- # Do not identify as nginx
- server_tokens off;
server_name {{ exchange_domain }};
{%if exchange_use_letsencrypt %}
@@ -16,15 +13,6 @@ server {
ssl_certificate_key /etc/nginx/ssl/taler-exchange.key;
{% endif %}
-
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL:10m;
- ssl_dhparam /etc/ssl/private/dhparam.pem;
- ssl_protocols TLSv1.3 TLSv1.2;
- ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
-
- add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
-
# Bigger than default timeout to support long polling
proxy_read_timeout 6500s;
keepalive_requests 1000000;
diff --git a/roles/monitoring/templates/etc/nginx/sites-available/monitoring-nginx.conf.j2 b/roles/monitoring/templates/etc/nginx/sites-available/monitoring-nginx.conf.j2
@@ -1,22 +1,12 @@
server {
- listen 443 ssl;
- listen [::]:443 ssl;
+ include conf.d/listen.conf.inc;
- # Do not identify as nginx
- server_tokens off;
server_name monitoring.{{ domain_name }};
ssl_certificate /etc/letsencrypt/live/monitoring/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/monitoring/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/monitoring/chain.pem;
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL:10m;
- ssl_dhparam /etc/ssl/private/dhparam.pem;
- ssl_protocols TLSv1.3 TLSv1.2;
- ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
-
- add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
error_log /var/log/nginx/monitoring.{{ domain_name }}.err;
access_log /var/log/nginx/monitoring.{{ domain_name }}.log;
diff --git a/roles/webserver/files/etc/nginx/conf.d/http2-http3.conf b/roles/webserver/files/etc/nginx/conf.d/http2-http3.conf
@@ -0,0 +1,25 @@
+# Drop-in placed by Ansible.
+# Sets HTTP/2 and HTTP/3 (QUIC) globally inside the http{} context.
+# All per-server listen/quic directives live in listen.conf.inc.
+
+http2 on;
+http3 on;
+quic_retry on;
+
+ssl_early_data on;
+ssl_prefer_server_ciphers on;
+# Note: session cache is shared across all services on this server
+ssl_session_cache shared:TLS:10m;
+ssl_dhparam /etc/ssl/private/dhparam.pem;
+ssl_protocols TLSv1.3 TLSv1.2;
+ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
+
+# Dummy server because 'reuseport' must be specified, but only
+# exactly once, so we use this dummy to basically only set 'reuseport'
+# (because putting it into listen.conf.inc would not work).
+server {
+ listen 443 quic reuseport;
+ listen [::]:443 quic reuseport;
+ server_name _;
+ return 444; # drop unmatched requests silently
+}
+\ No newline at end of file
diff --git a/roles/webserver/files/etc/nginx/conf.d/listen.conf.inc b/roles/webserver/files/etc/nginx/conf.d/listen.conf.inc
@@ -0,0 +1,16 @@
+listen 443 ssl;
+listen [::]:443 ssl;
+listen 443 quic;
+listen [::]:443 quic;
+http2 on; # redundant with global, but explicit per spec
+http3 on;
+quic_retry on;
+
+# Advertise support for HTTP3
+add_header Alt-Svc 'h3=":443"; ma=86400';
+
+# Do not identify as nginx
+server_tokens off;
+
+# Enforce strict TLS for everything, always
+add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
diff --git a/roles/webserver/tasks/main.yml b/roles/webserver/tasks/main.yml
@@ -35,6 +35,22 @@
group: root
mode: "0644"
+- name: Setup global HTTP2/HTTP3 configuration
+ copy:
+ src: etc/nginx/conf.d/http2-http3.conf
+ dest: /etc/nginx/conf.d/http2-http3.conf
+ owner: root
+ group: root
+ mode: "0644"
+
+- name: Setup per-server HTTP2/HTTP3 listen options
+ copy:
+ src: etc/nginx/conf.d/listen.conf.inc
+ dest: /etc/nginx/conf.d/listen.conf.inc
+ owner: root
+ group: root
+ mode: "0644"
+
- name: Check nginx config
ansible.builtin.command: nginx -c /etc/nginx/nginx.conf -t
register: result