ansible-taler-exchange

Ansible playbook to deploy a production Taler Exchange
Log | Files | Refs | Submodules | README | LICENSE

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:
Mroles/auditor/templates/etc/nginx/sites-available/auditor-nginx.conf.j2 | 15+--------------
Mroles/challenger/templates/etc/nginx/sites-available/email-challenger-nginx.conf.j2 | 8+-------
Mroles/challenger/templates/etc/nginx/sites-available/postal-challenger-nginx.conf.j2 | 7+------
Mroles/challenger/templates/etc/nginx/sites-available/sms-challenger-nginx.conf.j2 | 7+------
Mroles/exchange/templates/etc/nginx/sites-available/exchange-nginx.conf.j2 | 14+-------------
Mroles/monitoring/templates/etc/nginx/sites-available/monitoring-nginx.conf.j2 | 12+-----------
Aroles/webserver/files/etc/nginx/conf.d/http2-http3.conf | 26++++++++++++++++++++++++++
Aroles/webserver/files/etc/nginx/conf.d/listen.conf.inc | 16++++++++++++++++
Mroles/webserver/tasks/main.yml | 16++++++++++++++++
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