Solución a Error “bad cipher” en Nginx detrás de Cloudflare con OpenSSL 3.x

Artículos Guías Manuales Sistemas Linux Windows Redes MySql Binario 0 Binario Cero Artículos Guías Manuales Sistemas Linux Windows Redes MySql Binario 0 Binario Cero

Cuando se utiliza Cloudflare como proxy inverso delante de un servidor Nginx con OpenSSL 3.x, es posible encontrarse en los logs con un error como:

SSL_do_handshake() failed (SSL: error:0A0000BA:SSL routines::bad cipher) while SSL handshaking, client: 172.71.xxx.xxx, server: 0.0.0.0:443

Este mensaje indica que el cliente (Cloudflare) y el servidor (Nginx) no han encontrado ningún cifrado común para negociar la conexión TLS. Aunque el certificado esté correcto, el fallo ocurre antes de intercambiar datos, durante el “handshake”.

1. Causas comunes del “bad cipher”

  1. Lista de cifrados (ssl_ciphers) mal definida
    • Incluir solo suites TLS 1.3 dentro de ssl_ciphers (estas no aplican a TLS 1.2).
    • Lista demasiado restrictiva que no coincide con las soportadas por Cloudflare.
  2. Protocolos limitados
    • Habilitar solo TLS 1.3 y bloquear TLS 1.2, cuando Cloudflare intenta 1.2 hacia el origen.
  3. Políticas de seguridad elevadas (SECLEVEL)
    • En OpenSSL 3.x, un SECLEVEL alto puede bloquear cifrados válidos para Cloudflare.
  4. Conflictos de configuración
    • Otro bloque server {} que atiende el mismo server_name con parámetros SSL distintos.

2. Comprobar versión y compilación de OpenSSL

Antes de modificar Nginx, conviene confirmar qué versión de OpenSSL usa:

nginx -V 2>&1 | grep -o 'OpenSSL[^ ]* [^ ]*'
openssl version -a

Ejemplo de salida con OpenSSL 3.x:

OpenSSL 3.5.1 1 Jul 2025
built on: ...
platform: debian-amd64
OPENSSLDIR: "/usr/lib/ssl"

3. Configuración recomendada en Nginx

Para asegurar compatibilidad con Cloudflare y mantener buenas prácticas de seguridad, se recomienda habilitar TLS 1.2 y TLS 1.3, definiendo las suites de forma correcta.

Este bloque se puede incluir en http {} para que afecte a todos los server {}, o de forma individual en cada server de 443.

# Protocolos compatibles con Cloudflare
ssl_protocols TLSv1.2 TLSv1.3;

# TLS 1.2: suites modernas y comunes con Cloudflare
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:
             ECDHE-RSA-AES128-GCM-SHA256:
             ECDHE-ECDSA-AES256-GCM-SHA384:
             ECDHE-RSA-AES256-GCM-SHA384:
             ECDHE-ECDSA-CHACHA20-POLY1305:
             ECDHE-RSA-CHACHA20-POLY1305';

ssl_prefer_server_ciphers on;   # Controla el orden de preferencia (ver sección 5)
ssl_ecdh_curve X25519:P-256;

# TLS 1.3: se definen aparte en OpenSSL 3.x
ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;

# Opcional (rendimiento y OCSP)
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 1.0.0.1 valid=300s;
resolver_timeout 5s;

Nota: No mezclar suites TLS 1.3 en ssl_ciphers; se definen solo en ssl_conf_command.

4. Ajustes en Cloudflare

En el panel de Cloudflare para el dominio (example.com en este ejemplo):

  • SSL/TLS mode: Full (strict)
  • Minimum TLS version: 1.2
  • Certificado en el origen válido (Let’s Encrypt o Cloudflare Origin CA).
  • Si usas Cloudflare Origin CA, añadir: ssl_trusted_certificate /etc/ssl/cloudflare_origin_ca.pem;

5. Sobre ssl_prefer_server_ciphers

  • on → El servidor impone el orden de ssl_ciphers en TLS 1.2.
  • off → El cliente (Cloudflare) elige su preferida de las permitidas.
  • TLS 1.3: No se ve afectado por esta directiva.

En entornos donde se prioriza compatibilidad, off puede evitar conflictos. Si se quiere controlar la elección por motivos de rendimiento o compliance, se deja on.

6. Verificación

Tras aplicar cambios y recargar Nginx:

nginx -t && systemctl reload nginx

Pruebas desde el origen:

# Forzar TLS 1.3
openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null | grep -E 'Protocol|Cipher'

# Forzar TLS 1.2
openssl s_client -connect example.com:443 -servername example.com -tls1_2 </dev/null | grep -E 'Protocol|Cipher'

Ejemplo de resultado esperado:

Protocol  : TLSv1.3
Cipher    : TLS_AES_128_GCM_SHA256

Protocol  : TLSv1.2
Cipher    : ECDHE-RSA-AES128-GCM-SHA256

7. Conclusión

El error “bad cipher” con Cloudflare y Nginx sobre OpenSSL 3.x se debe normalmente a una falta de intersección de suites de cifrado entre ambos.
La solución pasa por:

  1. Habilitar TLS 1.2 y TLS 1.3.
  2. Definir listas de cifrados seguras y compatibles.
  3. Mantener configuraciones separadas para TLS 1.2 y TLS 1.3.
  4. Ajustar Cloudflare a Full (strict) y TLS mínimo 1.2.

Con esta configuración, el handshake TLS se establecerá correctamente y desaparecerá el “bad cipher” en los logs.

Compartir:

Binario 0
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.