matrix.grapheneos.org/nginx/nginx.conf
Daniel Micay 087c1a6349 disable traditional stateful TLS session cache
This is useless for TLSv1.3 since there's no longer any distinction in
the protocol based on whether the server is using stateless or stateful
session resumption. OpenSSL has a non-standard anti-replay mechanism for
0-RTT based on stateful session resumption but 0-RTT still ends up being
a downgrade for the TLS security properties. nginx disables that feature
since otherwise 0-RTT wouldn't work with the default stateless approach.

Since this cache is only used for TLSv1.2 when stateless resumption
isn't disabled and nearly all TLSv1.2 clients support tickets, it isn't
getting any significant use. It provides worse forward secrecy than
tickets because we implement ticket key rotation based on the expiry
time and sessions aren't actively purged from the stateful cache when
they expire. Cached session state varies in size and nginx ends up
writing errors to the log when clearing out a session fails to make room
for a new one due to it being larger. It's best to finally get rid of
this flawed approach to session resumption.

TLSv1.3 provides the option of forward secrecy for resumed sessions and
it's the only approach that's normally enabled so we don't need to worry
about this anymore once TLSv1.2 is disabled as long as we never enable
0-RTT which weakens forward secrecy and other security properties.
2022-04-30 22:53:43 -04:00

182 lines
5.8 KiB
Nginx Configuration File

# nginx 1.20.2+
load_module modules/ngx_http_brotli_static_module.so;
worker_processes auto;
worker_rlimit_nofile 16384;
events {
worker_connections 4096;
}
http {
include mime.types;
default_type application/octet-stream;
charset utf-8;
charset_types text/css text/plain text/xml application/atom+xml application/javascript;
# sendfile + AIO is buggy without fixes from nginx master
#sendfile on;
sendfile_max_chunk 512k;
tcp_nopush on;
keepalive_timeout 3m;
server_tokens off;
msie_padding off;
client_max_body_size 1k;
client_body_buffer_size 1k;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
http2_recv_buffer_size 128k;
client_body_timeout 30s;
client_header_timeout 30s;
send_timeout 30s;
http2_max_concurrent_streams 32;
limit_conn_status 429;
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 256;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_conf_command Options PrioritizeChaCha;
ssl_certificate /etc/letsencrypt/live/matrix.grapheneos.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/matrix.grapheneos.org/privkey.pem;
# maintained by nginx-rotate-session-ticket-keys in ramfs
ssl_session_ticket_key session-ticket-keys/4.key;
ssl_session_ticket_key session-ticket-keys/3.key;
ssl_session_ticket_key session-ticket-keys/2.key;
ssl_session_ticket_key session-ticket-keys/1.key;
ssl_session_timeout 1d;
ssl_buffer_size 4k;
ssl_trusted_certificate /etc/letsencrypt/live/matrix.grapheneos.org/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;
# maintained by certbot-ocsp-fetcher
ssl_stapling_file ocsp-cache/matrix.grapheneos.org.der;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request_method $scheme://$host$request_uri $server_protocol" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/access.log main buffer=64k flush=1m;
error_log syslog:server=unix:/dev/log,nohostname;
log_not_found off;
gzip_proxied any;
gzip_vary on;
if_modified_since before;
aio threads;
aio_write on;
upstream backend {
zone backend 32k;
server [::1]:8008 max_conns=4096 fail_timeout=1s;
}
server {
listen 80 backlog=4096;
listen [::]:80 backlog=4096;
server_name matrix.grapheneos.org element.grapheneos.org;
root /var/empty;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2 backlog=4096;
listen [::]:443 ssl http2 backlog=4096;
server_name matrix.grapheneos.org;
root /var/empty;
include snippets/security-headers.conf;
add_header Cross-Origin-Resource-Policy "same-origin" always;
add_header Content-Security-Policy "font-src 'none'; manifest-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; frame-ancestors 'none'; block-all-mixed-content" always;
# obsolete and replaced with Content-Security-Policy frame-ancestors 'none'
add_header X-Frame-Options "DENY" always;
location = / {
return 301 https://grapheneos.org/articles/grapheneos-servers#matrix.grapheneos.org;
}
location ^~ /.well-known/acme-challenge/ {
root /srv/certbot;
}
location ~ ^(?:/_matrix|/_synapse/client) {
# remove security headers that are statically set to the strictest possible values below
proxy_hide_header Referrer-Policy;
proxy_hide_header X-Frame-Options;
include snippets/security-headers.conf;
add_header Cross-Origin-Resource-Policy "cross-origin" always;
add_header Content-Security-Policy "font-src 'none'; manifest-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; frame-ancestors 'none'; block-all-mixed-content" always;
# obsolete and replaced with Content-Security-Policy frame-ancestors 'none'
add_header X-Frame-Options "DENY" always;
add_header X-Robots-Tag "none";
proxy_pass http://backend;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_connect_timeout 5s;
proxy_read_timeout 600s;
client_max_body_size 100m;
client_body_buffer_size 16k;
}
location / {
return 404;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name element.grapheneos.org;
root /srv/element.grapheneos.org;
include snippets/security-headers.conf;
add_header Cross-Origin-Resource-Policy "cross-origin" always;
add_header Content-Security-Policy "font-src 'self'; manifest-src 'self'; object-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; block-all-mixed-content" always;
# obsolete and replaced with Content-Security-Policy frame-ancestors 'self'
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Robots-Tag "none";
location ^~ /.well-known/acme-challenge/ {
root /srv/certbot;
}
location ~ '\.(?:css|html|ico|js|json|map|svg|txt|wasm|xml)$' {
gzip_static on;
brotli_static on;
}
}
server {
listen [::1]:81;
root /var/empty;
location = /nginx_status {
stub_status;
access_log off;
}
location / {
return 404;
}
}
}