By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Hyper-practical, zero-fluff guide for engineers who need to deploy, troubleshoot, or pass the exam—yesterday.
You’re configuring a TLS 1.3 VPN for a remote team, or hardening an NGINX web server to pass a compliance audit. The auditor flags a warning: "Your key exchange lacks Perfect Forward Secrecy (PFS). If your private key is ever compromised, all past sessions can be decrypted."
This is a disaster waiting to happen. - Without PFS, an attacker who steals your server’s private key can decrypt all past encrypted traffic (e.g., passwords, credit card numbers, API keys). - With PFS, even if the private key is stolen, each session’s keys are ephemeral—past traffic stays secure.
Real-world scenario: You inherit a legacy Apache server using RSA key exchange (no PFS). Your CISO demands you upgrade to ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) to meet PCI DSS 4.0 requirements. You have 24 hours to:1. Generate new keys.2. Update the TLS config.3. Verify PFS is active.4. Ensure no downtime.
This guide gives you the exact steps, commands, and pitfalls to pull this off.
openssl s_client -connect example.com:443 -tls1_2 | grep "Key Exchange"
ECDHE-RSA-AES256-GCM-SHA384
RSA-AES256-GCM-SHA384
NGINX installed (tested on Ubuntu 22.04) ? OpenSSL 1.1.1+ (for TLS 1.3 support) ? Root/sudo access ? A domain with SSL cert (Let’s Encrypt or self-signed)
# Generate a private key using curve25519 (modern, fast) openssl ecparam -genkey -name prime256v1 -out /etc/ssl/private/nginx-ecdsa.key # Generate a CSR (for Let’s Encrypt or self-signed) openssl req -new -key /etc/ssl/private/nginx-ecdsa.key -out /etc/ssl/certs/nginx-ecdsa.csr
Why? - ECDSA keys are smaller and faster than RSA. - prime256v1 is widely supported (use secp384r1 for higher security).
# Install Certbot sudo apt install certbot python3-certbot-nginx -y # Request a certificate (uses ECDSA by default if key exists) sudo certbot --nginx -d example.com --key-type ecdsa
Expected output:
Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem Private key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
Edit /etc/nginx/sites-available/default (or your config file):
/etc/nginx/sites-available/default
server { listen 443 ssl http2; server_name example.com; # ECDSA certificate (modern, faster) ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # RSA fallback (for old clients) ssl_certificate /etc/ssl/certs/nginx-rsa.crt; ssl_certificate_key /etc/ssl/private/nginx-rsa.key; # Enable TLS 1.2 + 1.3 (TLS 1.3 enforces ECDHE) ssl_protocols TLSv1.2 TLSv1.3; # Prioritize ECDHE (PFS) ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'; # Enable session resumption (faster handshakes) ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # Disable for PFS (optional) }
Key settings: - ssl_protocols TLSv1.2 TLSv1.3-Enforces modern TLS. - ssl_ciphers-Prioritizes ECDHE (PFS). - ssl_session_tickets off-Disables session tickets (optional, but improves PFS).
ssl_protocols TLSv1.2 TLSv1.3
ssl_ciphers
ssl_session_tickets off
# Check if ECDHE is used (should see "ECDHE" in output) openssl s_client -connect example.com:443 -tls1_2 | grep "Key Exchange" # Expected output (PFS enabled): # Key Exchange: ECDHE-RSA-AES256-GCM-SHA384 # Check TLS 1.3 (should show "TLS_AES_256_GCM_SHA384") openssl s_client -connect example.com:443 -tls1_3 | grep "Cipher" # Expected output (TLS 1.3): # Cipher : TLS_AES_256_GCM_SHA384
? Success criteria: - TLS 1.2-Shows ECDHE in key exchange. - TLS 1.3-Shows TLS_AES_256_GCM_SHA384 (ECDHE is mandatory in TLS 1.3).
# Test config for errors sudo nginx -t # Reload NGINX sudo systemctl reload nginx # Check logs for errors sudo tail -f /var/log/nginx/error.log
? If you see errors: - "No shared cipher"-Your ssl_ciphers list is too restrictive. Add ECDHE-RSA-AES256-GCM-SHA384. - "SSL_CTX_use_PrivateKey_file failed"-Check file permissions (chmod 600 on private keys).
chmod 600
Strict-Transport-Security: max-age=31536000; includeSubDomains
RSA
openssl s_client
ssl_protocols TLSv1.2 TLSv1.3;
prime256v1
secp384r1
curve25519
sudo systemctl reload nginx
ssl_session_tickets off;
RSA, PSK
"What is the main advantage of ECDHE over DHE?"
"More secure" (both are secure, but ECDHE is more efficient)
"Why is RSA key exchange considered insecure for PFS?"
"It’s slower" (irrelevant to PFS)
"Which TLS version enforces ECDHE by default?"
"You need to configure a web server for PCI DSS compliance. Which key exchange should you use?" --ECDHE (PFS required by PCI DSS) --RSA (no PFS) --DHE (slower than ECDHE) --PSK (not suitable for web)
You’re given an Apache server with this config:
SSLCipherSuite RSA-AES256-GCM-SHA384 SSLProtocol -all +TLSv1.2
Task:1. Modify the config to enable PFS.2. Verify the change with openssl s_client.
# Update Apache config (/etc/apache2/mods-available/ssl.conf) SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384 SSLProtocol -all +TLSv1.2 +TLSv1.3 # Restart Apache sudo systemctl restart apache2 # Verify openssl s_client -connect example.com:443 -tls1_2 | grep "Key Exchange"
Key Exchange: ECDHE-RSA-AES256-GCM-SHA384
Why it works: - ECDHE replaces RSA for key exchange (PFS). - TLS 1.3 enforces ECDHE by default.
openssl s_client -connect example.com:443 -tls1_2
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:...'
openssl ecparam -genkey -name prime256v1
secp192r1
Strict-Transport-Security: max-age=31536000
includeSubDomains
Now go fix your TLS config before the auditor does. ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.