Modern SSL/TLS for Nginx: A Practical Guide to Balancing TLS 1.2 and 1.3 on AlmaLinux and Ubuntu
Modern SSL/TLS for Nginx: A Practical Guide to Balancing TLS 1.2 and 1.3 on AlmaLinux and Ubuntu
The following blog post is a product of my professional experience as a Linux system administrator, enhanced and articulated with the aid of AI tools to ensure comprehensive coverage and clarity for our technical audience
In the ever-evolving landscape of cybersecurity, deploying robust and adaptable SSL/TLS configurations is paramount. System administrators and security engineers must navigate a delicate balance: embracing cutting-edge cryptographic standards like TLS 1.3 for peak security and performance, whilst ensuring continued compatibility with existing systems and clients that may still rely on the well-established TLS 1.2. This guide provides a practical, command-driven approach to troubleshooting and optimising SSL/TLS for Nginx reverse proxies on both AlmaLinux and Ubuntu platforms, explicitly addressing the nuances of both TLS 1.2 and TLS 1.3.
Imagine you’re tasked with configuring Nginx as a reverse proxy to protect your organisation's critical web applications. Your objective is to implement modern SSL/TLS, supporting both TLS 1.2 for broad compatibility and TLS 1.3 for forward-thinking security and performance gains. You aim to leverage strong cipher suites like AES-GCM and ChaCha20-Poly1305, ensuring robust encryption for all connections. However, the reality of mixed environments and potential configuration complexities can lead to SSL handshake errors, performance bottlenecks, and security vulnerabilities.
This comprehensive guide equips you with a meticulously curated toolkit of commands and platform-specific considerations to confidently diagnose, troubleshoot, and optimise your Nginx reverse proxy’s SSL/TLS configuration for both TLS 1.2 and TLS 1.3, across both AlmaLinux and Ubuntu server environments. Let's embark on this journey to master modern SSL/TLS and create resilient, secure, and performant Nginx deployments.
1. Basic Network Connectivity Check (Ping) – Foundation for Both TLS 1.2 & 1.3
Regardless of your chosen TLS protocol version, establishing fundamental network connectivity remains the essential first step. Before delving into SSL/TLS specifics, confirm that your Nginx proxy server can reach the backend server at the IP network layer using the ping command:
Bash
ping <backend_server_ip_or_hostname>
Example:
Bash
ping backend.example.comRelevance to TLS 1.2 and 1.3: Network reachability is protocol-agnostic. ping verifies basic IP-level communication, crucial for both TLS 1.2 and TLS 1.3 connections. A failed ping indicates a fundamental network problem irrespective of SSL/TLS configurations.
2. Checking Open Ports (Netcat - nc) – TCP Layer Verification for SSL/TLS
Next, ascertain that the backend server is actively listening on the designated port (typically 443 for HTTPS, or a custom port). netcat (nc) offers a swift TCP port status check, relevant for both TLS 1.2 and TLS 1.3 scenarios:
Bash
nc -zv <backend_server_ip_or_hostname> <port_number>
Example:
Bash
nc -zv backend.example.com 8443Relevance to TLS 1.2 and 1.3: nc's TCP connection test verifies that the backend port is open and accepting TCP connections, a prerequisite for both TLS 1.2 and TLS 1.3 handshakes. Like ping, nc operates below the SSL/TLS layer, confirming TCP readiness independently of the SSL/TLS protocol version in use.
3. Detailed SSL/TLS Connection Testing (OpenSSL s_client) – Targeting TLS 1.2 and TLS 1.3
For in-depth SSL/TLS diagnostics, openssl s_client is indispensable, enabling detailed inspection of handshakes and cipher negotiations for both TLS 1.2 and TLS 1.3.
Testing TLS 1.2 Connection (Compatibility Baseline):
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_2 -CAfile /path/to/ca-certificates.crt
Example:
Bash
openssl s_client -connect backend.example.com:8443 -tls1_2 -CAfile /etc/ssl/certs/ca-bundle.crtRelevance: Testing TLS 1.2 provides a crucial compatibility baseline. Ensure successful TLS 1.2 connections as a minimum security standard. This command explicitly requests TLS 1.2, allowing you to verify basic TLS connectivity and certificate validation with this widely adopted protocol version.
Testing TLS 1.3 Connection (Modern Security Focus):
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_3 -CAfile /path/to/ca-certificates.crt
Example:
Bash
openssl s_client -connect backend.example.com:8443 -tls1_3 -CAfile /etc/ssl/certs/ca-bundle.crtRelevance: Testing TLS 1.3 is essential for validating support for the latest, most secure, and performant protocol version. This command explicitly targets TLS 1.3, allowing you to assess backend server TLS 1.3 capabilities and identify any negotiation failures specific to TLS 1.3. Aim for successful TLS 1.3 connections for optimal modern security.
Testing Modern Cipher Suites with Both TLS 1.2 and TLS 1.3:
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_2 -cipher TLS_AES_256_GCM_SHA384 -CAfile /path/to/ca-certificates.crt # TLS 1.2 with AES-GCM
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_3 -cipher TLS_AES_256_GCM_SHA384 -CAfile /etc/ssl/certs/ca-bundle.crt # TLS 1.3 with AES-GCM
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_2 -cipher TLS_CHACHA20_POLY1305_SHA256 -CAfile /path/to/ca-certificates.crt # TLS 1.2 with ChaCha20
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_3 -cipher TLS_CHACHA20_POLY1305_SHA256 -CAfile /etc/ssl/certs/ca-bundle.crt # TLS 1.3 with ChaCha20
Relevance: Testing cipher suites across both TLS 1.2 and TLS 1.3 is critical for ensuring cipher compatibility and selecting optimal cipher suites for each protocol version. AES-GCM cipher suites are excellent choices for both TLS 1.2 and TLS 1.3. ChaCha20-Poly1305 is particularly advantageous in TLS 1.3. Test these ciphers explicitly under both protocol versions to verify server support and behaviour across protocol contexts.
Testing Security-Focused Cipher Lists for TLS 1.2 and TLS 1.3:
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_2 -cipher 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:HIGH:+ECDHE-RSA-AES128-GCM-SHA256' -CAfile /path/to/ca-certificates.crt # TLS 1.2 List
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_3 -cipher 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:HIGH:+ECDHE-RSA-AES128-GCM-SHA256' -CAfile /etc/ssl/certs/ca-bundle.crt # TLS 1.3 List
Relevance: Using comprehensive cipher lists, tailored for both TLS 1.2 and TLS 1.3, allows for broader testing of cipher negotiation capabilities. These lists prioritize modern, secure ciphers while including a range of HIGH strength ciphers and some RSA-based ECDHE options for compatibility. Testing these lists under both TLS 1.2 and TLS 1.3 helps ensure robust cipher support across protocol versions and identifies any cipher preference differences between the two.
Diagnostic Certificate Verification Disablement (Use with Extreme Caution, Across TLS 1.2 & 1.3):
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_2 -cipher <cipher_suite_name> -no_verify # TLS 1.2, No Verify
Bash
openssl s_client -connect <backend_server_ip_or_hostname>:<port_number> -tls1_3 -cipher <cipher_suite_name> -no_verify # TLS 1.3, No Verify
Critical Warning: -no_verify remains a highly insecure diagnostic option, equally dangerous for both TLS 1.2 and TLS 1.3. Never use in production. It is solely for temporary troubleshooting of certificate-related issues, across both protocol versions.
4. curl for HTTP/HTTPS Requests – Supporting TLS 1.2 and TLS 1.3
curl is indispensable for testing HTTP/HTTPS requests, supporting explicit TLS 1.2 and TLS 1.3 version targeting and cipher control, essential for comprehensive protocol version testing.
Basic HTTPS Request with Verbose Output (TLS 1.3 Preference, Fallback to 1.2):
Bash
curl -v --tls-max 1.3 https://<proxy_or_backend_hostname>:<port>/<api_path>
Relevance: --tls-max 1.3 allows curl to negotiate TLS 1.3 if supported, falling back to TLS 1.2 if not. This provides a flexible test for modern protocol support while maintaining backward compatibility, crucial for assessing real-world client behaviour with mixed protocol support.
Forcing TLS 1.2 and Modern Ciphers in curl:
Bash
curl -v --tlsv1.2 --cipher TLS_AES_256_GCM_SHA384 https://<proxy_or_backend_hostname>:<port>/<api_path> # TLS 1.2 with AES-GCM
Bash
curl -v --tlsv1.2 --cipher TLS_CHACHA20_POLY1305_SHA256 https://<proxy_or_backend_hostname>:<port>/<api_path> # TLS 1.2 with ChaCha20
Bash
curl -v --tlsv1.2 --ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:HIGH:+ECDHE-RSA-AES128-GCM-SHA256' https://<proxy_or_backend_hostname>:<port>/<api_path> # TLS 1.2 List
Relevance: Explicitly testing TLS 1.2 with modern cipher suites ensures that even if TLS 1.3 is not fully adopted, a strong and secure TLS 1.2 configuration is in place as a robust fallback. This is vital for maintaining security while accommodating clients that may not yet fully support TLS 1.3.
Forcing TLS 1.3 and Modern Ciphers in curl:
Bash
curl -v --tlsv1.3 --cipher TLS_AES_256_GCM_SHA384 https://<proxy_or_backend_hostname>:<port>/<api_path> # TLS 1.3 with AES-GCM
Bash
curl -v --tlsv1.3 --cipher TLS_CHACHA20_POLY1305_SHA256 https://<proxy_or_backend_hostname>:<port>/<api_path> # TLS 1.3 with ChaCha20
Bash
curl -v --tls1.3 --ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:HIGH:+ECDHE-RSA-AES128-GCM-SHA256' https://<proxy_or_backend_hostname>:<port>/<api_path> # TLS 1.3 List
Relevance: Rigorously testing TLS 1.3 with preferred cipher suites ensures optimal modern security and performance when TLS 1.3 is negotiated. These commands validate TLS 1.3 functionality and cipher compatibility in the context of real HTTP/HTTPS requests through curl.
Setting the Host Header in curl (Essential for Virtual Hosting Across TLS 1.2 & 1.3):
Bash
curl -kiH 'Host: <expected_hostname>' https://<proxy_hostname>:<port>/<api_path>
Relevance: The Host header remains protocol-independent. It’s equally critical for virtual hosting and proxy scenarios, regardless of whether TLS 1.2 or TLS 1.3 is in use, ensuring correct request routing in modern web architectures.
5. Nginx Configuration Directives – Balancing TLS 1.2 and TLS 1.3 for AlmaLinux and Ubuntu
Nginx configuration must be meticulously crafted to support both TLS 1.2 and TLS 1.3 effectively, catering to diverse client capabilities while prioritizing modern security. These directives provide a balanced and adaptable configuration applicable to both AlmaLinux and Ubuntu:
proxy_pass https://<backend_server>:<port>/;: Remains the core directive for HTTPS proxying, relevant for both TLS 1.2 and TLS 1.3 backend connections.
ssl_protocols TLSv1.2 TLSv1.3;: This directive is key to enabling support for both TLS 1.2 and TLS 1.3. By explicitly listing both protocols, you instruct Nginx to offer and accept connections using either protocol version, ensuring compatibility with clients and backends supporting either TLS 1.2 or the more modern TLS 1.3. This balanced approach maximizes both security and compatibility. Crucially, explicitly include both TLS 1.2 and TLS 1.3 to avoid unintended reliance on default protocol selections which might vary across Nginx versions or operating systems.
proxy_ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256';: This comprehensive cipher list, designed for both TLS 1.2 and TLS 1.3, ensures strong cipher selection across both protocol versions. It prioritizes TLS 1.3-optimised ciphers like ChaCha20-Poly1305 and AES-GCM, while retaining robust AES-GCM and ECDHE-RSA based ciphers that offer excellent security under TLS 1.2 and broader compatibility. This balanced cipher string ensures strong cryptography regardless of whether TLS 1.2 or TLS 1.3 is ultimately negotiated. As discussed previously, for purely TLS 1.3-centric environments, the cipher list can be streamlined further, but for mixed TLS 1.2/1.3 deployments, this broader list provides excellent coverage.
ssl_prefer_server_ciphers on;: Remains a best practice for both TLS 1.2 and TLS 1.3 configurations, ensuring server-side cipher preferences are respected, maximising the likelihood of strong cipher suite negotiation regardless of the negotiated TLS protocol version.
ssl_ecdh_curve secp384r1;: secp384r1 continues to be a recommended ECDH curve, offering strong security and broad compatibility across both TLS 1.2 and TLS 1.3. X25519 remains a TLS 1.3-optimised alternative, particularly when TLS 1.3 is the dominant protocol in your environment.
ssl_session_timeout 1d;, ssl_session_cache shared:SSL:50m;, ssl_session_tickets off;: Session management directives remain largely consistent for both TLS 1.2 and TLS 1.3, optimising session resumption and performance across both protocol versions. While TLS 1.3's inherent session resumption mechanisms are more efficient, these directives continue to provide value in mixed TLS 1.2/1.3 environments.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;: HSTS header deployment is equally critical for both TLS 1.2 and TLS 1.3 secured websites, offering essential downgrade attack protection and HTTPS enforcement across both protocol contexts.
proxy_ssl_verify on; & proxy_ssl_trusted_certificate /path/to/CA_certificate.crt; (Backend Certificate Validation): Backend certificate validation is non-negotiable for secure proxying, irrespective of whether TLS 1.2 or TLS 1.3 is employed for backend connections. Robust certificate verification remains a fundamental security control for both protocol versions.
6. System Crypto Policy Considerations for AlmaLinux and Ubuntu
AlmaLinux (System-Wide Crypto Policies – Impact on TLS 1.2 and TLS 1.3):
AlmaLinux’s crypto policies directly influence SSL/TLS behaviour system-wide, affecting both TLS 1.2 and TLS 1.3 configurations. The DEFAULT policy offers a solid foundation for supporting both modern protocols.
update-crypto-policies --show: Always verify the active1 policy to ensure your intended settings are applied, impacting both TLS 1.2 and TLS 1.3 system-wide behaviour.2
sudo update-crypto-policies --set <policy_name>: When considering policy changes, evaluate the implications for both TLS 1.2 and TLS 1.3 compatibility. DEFAULT is generally recommended for balanced TLS 1.2/1.3 support. FUTURE prioritises TLS 1.3 more aggressively but may impact TLS 1.2 compatibility. LEGACY is strongly discouraged for production in both TLS 1.2 and TLS 1.3 contexts.
sudo reboot: Reboot remains crucial after policy changes to fully apply settings for both TLS 1.2 and TLS 1.3 system-wide.
Ubuntu (Application-Centric Configuration – Consistent for TLS 1.2 and TLS 1.3):
Ubuntu relies more on application-level configurations (like Nginx directives) and OpenSSL library settings. SSL/TLS configuration for both TLS 1.2 and TLS 1.3 is primarily managed within application configurations. The Nginx server block examples provided are directly applicable to Ubuntu and provide consistent TLS 1.2 and TLS 1.3 behaviour. Ensure consistent OpenSSL library versions across your Ubuntu systems for predictable TLS 1.2 and TLS 1.3 capabilities.
Key Considerations for Balancing TLS 1.2 and TLS 1.3 in Nginx Reverse Proxies
These overarching considerations are essential for effectively balancing TLS 1.2 and TLS 1.3 support in Nginx reverse proxy environments:
Client and Backend Compatibility Assessment: Thoroughly assess the TLS protocol capabilities of your client base and backend server infrastructure. If a significant portion of your clients or backends do not yet fully support TLS 1.3, maintaining TLS 1.2 support becomes essential for compatibility. If your environment is predominantly modern and TLS 1.3-ready, you can lean more heavily towards TLS 1.3 prioritisation, potentially with TLS 1.2 as a fallback. Compatibility analysis should drive your TLS protocol version strategy.
Prioritising TLS 1.3 Where Feasible: Whenever compatibility assessments permit, actively prioritize TLS 1.3. Its inherent performance and security advantages (reduced handshake latency, enhanced forward secrecy, streamlined handshake) make it the superior protocol choice for modern deployments. Configure Nginx to prefer TLS 1.3 (e.g., using ssl_protocols TLSv1.3 TLSv1.2;, ordering TLS 1.3-optimised ciphers first in proxy_ssl_ciphers). Embrace TLS 1.3 as the future of secure web communication and actively work towards wider TLS 1.3 adoption within your infrastructure.
Maintaining Robust TLS 1.2 Configuration as Fallback: Even when prioritizing TLS 1.3, maintaining a strong TLS 1.2 configuration as a fallback remains prudent for accommodating legacy clients or backend systems. Ensure your Nginx configuration includes secure TLS 1.2 cipher suites (e.g., AES-GCM based ciphers, ECDHE-RSA for forward secrecy) and protocols (ssl_protocols TLSv1.2 TLSv1.3;). A well-configured TLS 1.2 setup acts as a security safety net for broader compatibility.
Cipher Suite Selection for Dual TLS 1.2/1.3 Support: Craft your proxy_ssl_ciphers list to effectively cater to both TLS 1.2 and TLS 1.3. Include TLS 1.3-optimised ciphers (ChaCha20-Poly1305, AES-GCM for TLS 1.3) at the beginning of your list for TLS 1.3 preference. Incorporate robust TLS 1.2 ciphers (AES-GCM, ECDHE-RSA based) later in the list to ensure strong security when TLS 1.2 is negotiated. The example cipher list provided in this guide offers a good balance for mixed TLS 1.2/1.3 environments.
Operating System-Specific Crypto Policy Awareness (AlmaLinux vs. Ubuntu): Be keenly aware of operating system-specific crypto policy mechanisms. On AlmaLinux, leverage update-crypto-policies to manage system-wide cryptographic settings, understanding its impact on both TLS 1.2 and TLS 1.3. On Ubuntu, focus on application-level configurations (Nginx directives, OpenSSL settings), ensuring consistent configurations across your Ubuntu server fleet. Recognise that AlmaLinux's crypto policies offer a centralised system-wide approach, while Ubuntu relies more on distributed application configurations for SSL/TLS control.
Performance Optimisation for Both Protocols: Apply performance optimisation techniques (HTTP/2, session resumption, hardware acceleration) to benefit both TLS 1.2 and TLS 1.3 connections. TLS 1.3 inherently offers handshake latency improvements, but optimisations for cipher selection, session management, and hardware acceleration can enhance performance across both protocol versions.
Ongoing Monitoring and Adaptive Configuration: Continuously monitor your Nginx SSL/TLS setup for both TLS 1.2 and TLS 1.3 connections. Track negotiated protocol versions, cipher suites in use, connection latency, and error rates. Regularly audit your configurations against evolving security best practices and adapt your Nginx settings and system-wide crypto policies (on AlmaLinux) to maintain a robust and up-to-date SSL/TLS posture for both TLS 1.2 and TLS 1.3 in response to the dynamic threat landscape.
By adopting this dual-protocol strategy, meticulously employing the commands and configurations outlined in this guide, and remaining vigilant in monitoring and adapting to the evolving SSL/TLS landscape, you can confidently deploy Nginx reverse proxies that offer both cutting-edge security with TLS 1.3 and broad compatibility with TLS 1.2, on both AlmaLinux and Ubuntu platforms, achieving a truly balanced and robust modern SSL/TLS infrastructure.
Sources
1. https://github.com/mycelium3/osw-devops-from-test
2. https://itpfdoc.hitachi.co.jp/manuals/3021/30213D0340/AOKG0026.HTM
Nginx Configuration Directives – Balancing TLS 1.2 and TLS 1.3 for AlmaLinux and Ubuntu (with server Block Example)
To illustrate how these directives are employed in practice, let's examine a complete Nginx server block configuration example, designed to balance TLS 1.2 and TLS 1.3 support effectively for both AlmaLinux and Ubuntu environments. Following this example, we will then dissect each directive in detail, explaining its purpose and nuances within this practical configuration:
Now, let's dissect each of the SSL/TLS related directives within this server block example, explaining their function and relevance for both TLS 1.2 and TLS 1.3 deployments on AlmaLinux and Ubuntu:
listen 443 ssl http2;: This directive instructs Nginx to listen for incoming connections on port 443, the standard port for HTTPS. The ssl parameter explicitly enables SSL/TLS termination for this listen directive, indicating that Nginx will handle the SSL/TLS handshake and encryption/decryption for connections on this port. The http2 parameter, enabled here, activates HTTP/2 protocol support for this virtual server, offering significant performance benefits for HTTPS connections if supported by both the client and the backend application. HTTP/2 is beneficial for both TLS 1.2 and TLS 1.3, improving efficiency.
server_name your_domain.com;: This essential directive defines the domain name(s) that this server block should handle. Replace your_domain.com with your actual domain name or a space-separated list of domain names. This ensures that Nginx correctly routes requests based on the hostname presented by the client in the HTTP Host header or during the TLS Server Name Indication (SNI) negotiation. Correct server_name configuration is crucial for virtual hosting scenarios and proper certificate selection.
ssl_certificate /etc/nginx/ssl/your_domain.crt; and ssl_certificate_key /etc/nginx/ssl/your_domain.key;: These directives are fundamental for configuring Nginx's own SSL/TLS certificate.
ssl_certificate: Specifies the path to your SSL/TLS certificate file. This file should typically contain the full certificate chain for your domain, including your server certificate, any intermediate certificates, and ideally the root CA certificate (though root CA inclusion is sometimes optional depending on client certificate validation behaviour). Ensure the certificate is in PEM format.
ssl_certificate_key: Specifies the path to the private key file corresponding to your SSL/TLS certificate. This file must be kept securely protected, with appropriate file permissions (typically readable only by the Nginx user). The private key must also be in PEM format.
Correctly configuring these directives with valid and matching certificate and key files is absolutely essential for Nginx to establish secure HTTPS connections. Certificate management and renewal (using tools like certbot) are critical aspects of maintaining a secure and operational HTTPS service, regardless of the TLS protocol version in use.
ssl_protocols TLSv1.2 TLSv1.3;: As previously detailed, this directive explicitly enables TLS 1.2 and TLS 1.3 for Nginx's own SSL/TLS termination (for connections to Nginx itself). By including both protocol versions, you ensure support for both modern TLS 1.3 clients and clients still relying on TLS 1.2, providing a balance of security and compatibility for connections terminating at Nginx. For AlmaLinux and Ubuntu, these directives function identically, controlling the TLS protocol versions Nginx will offer for inbound connections.
ssl_prefer_server_ciphers on;: This directive, equally relevant for both TLS 1.2 and TLS 1.3, instructs Nginx to prioritise the server's cipher order (as defined by ssl_ciphers) during cipher negotiation. This best practice maximises the likelihood of strong cipher suite selection and is crucial for enforcing server-side security preferences, regardless of the negotiated TLS protocol version or operating system (AlmaLinux or Ubuntu).
ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256';: This directive, as previously discussed, defines the cipher suites Nginx will offer for its own SSL/TLS termination. The provided cipher string is carefully crafted to support both TLS 1.2 and TLS 1.3, prioritising modern and robust ciphers like ChaCha20-Poly1305 and AES-GCM, while maintaining compatibility with a range of secure cipher suites across both protocol versions. This cipher list functions identically on both AlmaLinux and Ubuntu Nginx installations.
ssl_ecdh_curve secp384r1;: This directive specifies the preferred Elliptic Curve for Elliptic Curve Diffie-Hellman Ephemeral (ECDHE) key exchange for Nginx's own SSL/TLS connections. secp384r1 remains a highly recommended and broadly compatible curve for both TLS 1.2 and TLS 1.3 on both AlmaLinux and Ubuntu.
ssl_session_timeout 1d;, ssl_session_cache shared:SSL:50m;, and ssl_session_tickets off;: These session management directives, controlling session timeout, shared cache, and session tickets respectively, function consistently for1 both TLS 1.2 and TLS 1.3 connections and across AlmaLinux and Ubuntu Nginx deployments, optimising session2 resumption and balancing performance and forward secrecy as previously detailed.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;: The HSTS header directive is configured identically for both TLS 1.2 and TLS 1.3 and behaves consistently across AlmaLinux and Ubuntu, adding the crucial Strict-Transport-Security header to HTTPS responses to enforce HTTPS-only access and mitigate downgrade attacks.
location / { ... }: This location / block defines the configuration for all requests under the root path (/) of your domain, effectively handling the reverse proxying to the backend server. Adjust the location block as needed to match your application's URL structure and routing requirements.
proxy_pass https://backend.example.internal:8080/;: This is the core reverse proxy directive within the location / block. It instructs Nginx to forward requests received at your_domain.com to the backend server located at backend.example.internal on port 8080, using HTTPS for the proxy-to-backend connection. Ensure that backend.example.internal is resolvable by your Nginx server (e.g., via DNS or entries in /etc/hosts) and that the backend server is indeed listening for HTTPS connections on port 8080. It is critical to use https:// here to enforce encrypted communication between Nginx and the backend.
proxy_ssl_protocols TLSv1.2 TLSv1.3;: This directive, within the location block, specifically controls the TLS protocol versions that Nginx will use for its proxy-to-backend connections. Similar to the ssl_protocols directive in the main server block, this ensures that Nginx will offer and accept both TLS 1.2 and TLS 1.3 when connecting to the backend server, balancing modern security with potential backend compatibility requirements. This setting is independent of the ssl_protocols directive controlling client-to-Nginx connections.
proxy_ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:HIGH';: This directive, again within the location block, defines the cipher suites that Nginx will offer for its proxy-to-backend SSL/TLS connections. The cipher string provided is a modern, security-focused list, prioritising ChaCha20 and AES-GCM ciphers, and including a broader "HIGH" cipher category for robustness. Note that this cipher list is distinct from the ssl_ciphers directive in the main server block, allowing you to configure different cipher preferences for client-facing and proxy-to-backend connections if needed. This example shows a slightly streamlined list for proxy-to-backend, focusing on modern and high-security ciphers, but you can tailor it based on your specific backend server capabilities and security policies.
proxy_ssl_verify on; and proxy_ssl_trusted_certificate /etc/nginx/ssl/backend-ca.crt;: These directives, crucial for secure reverse proxying, enable and configure backend certificate validation.
proxy_ssl_verify on;: Enables verification of the backend server's SSL/TLS certificate. This is essential for ensuring that Nginx is connecting to the intended and legitimate backend server and for preventing man-in-the-middle attacks on the proxy-to-backend connection. Always enable proxy_ssl_verify on; in production reverse proxy configurations.
proxy_ssl_trusted_certificate /etc/nginx/ssl/backend-ca.crt;: Specifies the path to a CA certificate file that Nginx should use to verify the backend server's certificate. This file should contain the Certificate Authority certificate that signed the backend server's certificate, or a bundle of CA certificates if the backend's certificate is issued by an intermediate CA. Ensure the correct CA certificate is used for successful backend certificate validation.
proxy_set_header Host $host;, proxy_set_header X-Real-IP $remote_addr;, proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;, and proxy_set_header X-Forwarded-Proto $scheme;: These proxy_set_header directives are standard best practices for reverse proxy configurations, ensuring that essential client request information is correctly passed to the backend server:
proxy_set_header Host $host;: Preserves the original Host header from the client request and forwards it to the backend. This is crucial for virtual hosting scenarios and for backend applications that rely on the Host header for routing or application logic.
proxy_set_header X-Real-IP $remote_addr;: Passes the real client IP address to the backend server in the X-Real-IP header. The $remote_addr variable contains the IP address of the client connecting to Nginx.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;: Appends the client's IP address to the X-Forwarded-For header. If there are multiple proxies in front of the backend, this header will contain a comma-separated list of IP addresses, tracing the request's path through the proxies. $proxy_add_x_forwarded_for ensures that the current proxy's IP address is appended to any3 existing X-Forwarded-For header, preserving the full client IP chain.
proxy_set_header X-Forwarded-Proto $scheme;: Passes the original protocol used by the client to connect to Nginx (either http or https) to the backend server via the X-Forwarded-Proto header. This allows the backend application to determine if the original request was made over a secure channel, even though the proxy-to-backend connection is also HTTPS.
These proxy_set_header directives are generally applicable and recommended for both TLS 1.2 and TLS 1.3 reverse proxy configurations.
access_log /var/log/nginx/your_domain.access.log main; and error_log /var/log/nginx/your_domain.error.log warn;: These directives configure access and error logging for this server block.
access_log: Defines the path to the access log file (/var/log/nginx/your_domain.access.log) and the log format (main, which is typically a predefined Nginx log format containing common request information). Access logs record all incoming requests to your server.
error_log: Defines the path to the error log file (/var/log/nginx/your_domain.error.log) and the logging level (warn). Error logs record error conditions encountered by Nginx while processing requests.
For SSL/TLS troubleshooting, temporarily increasing the error_log level to debug (e.g., error_log /var/log/nginx/your_domain.error.log debug;) can provide much more verbose logging output, including detailed SSL handshake information, which is invaluable for diagnosing SSL/TLS connection problems. Remember to revert the error_log level back to a less verbose level like warn or error after debugging, as debug logging can be quite verbose and impact performance over extended periods in production. Logging is crucial for monitoring, security auditing, and troubleshooting both general web traffic and SSL/TLS specific issues in both TLS 1.2 and TLS 1.3 deployments.
# --- Other server block configurations ... ---: This section is a placeholder for other standard Nginx server block configurations, such as root, index, error_page, and any application-specific directives you need for your website or application. These configurations are generally independent of the SSL/TLS settings but are essential for defining the overall behaviour of your Nginx virtual server.