Published:
Updated:

Table of Contents

Stronger certs

Instead of the default RSA-2048, choose RSA-4096 or EC-384:

RSA-4096

sudo certbot certonly -d cyber.cafe --key-type rsa --rsa-key-size 4096

EC-384

sudo certbot certonly -d cyber.cafe --key-type ecdsa --elliptic-curve secp384r1

Template config

sudo vim /etc/nginx/conf.d/default.conf

OpenSSL 3.0 - 3.4

server {
    server_name cyber.cafe;
    root /var/www/public;
    access_log off;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # with QUIC
    listen [::]:443 quic reuseport;
    listen [::]:443 ssl;
    listen 443 quic reuseport;
    listen 443 ssl;
    http2 on;
    http3 on;
    http3_hq on;
    quic_gso on;
    quic_retry on;
    ssl_early_data off;
    add_header Alt-Svc 'h3=":443"; ma=86400';
    
    # certs
    ssl_certificate /etc/letsencrypt/live/cyber.cafe/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/cyber.cafe/privkey.pem; 

    # ciphers - 1.3 only, not AES-128, good groups only
    ssl_protocols TLSv1.3;
    ssl_conf_command Groups X25519:secp384r1;
    ssl_conf_command Options +ServerPreference;
    ssl_conf_command Options +PrioritizeChaCha;
    ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
}

With OpenSSL 3.5

    # ciphers - 1.3 only, not AES-128, good groups only with hybrid pcq
    ssl_protocols TLSv1.3;
    ssl_conf_command Groups X25519MLKEM768:SecP384r1MLKEM1024:SecP256r1MLKEM768:MLKEM1024:X25519:secp384r1;
    ssl_conf_command Options +ServerPreference;
    ssl_conf_command Options +PrioritizeChaCha;
    ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

Security Headers

don't forget these!

    add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; img-src 'self' data:; font-src 'self'; style-src 'self'; script-src 'self'; connect-src 'self'; form-action 'self'; frame-src 'none'; manifest-src 'self'; worker-src 'self'; upgrade-insecure-requests" always;
    add_header Cross-Origin-Embedder-Policy "require-corp" always;
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Cross-Origin-Resource-Policy "same-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), bluetooth=(), interest-cohort=()" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;