Contenido mixto en WordPress: por qué HTTPS sigue mostrando advertencias y cómo arreglarlo correctamente

¿Te fue útil?

Si tu sitio WordPress “tiene SSL” pero el navegador todavía muestra una advertencia, no estás solo. El candado miente—bueno, no exactamente. Está haciendo lo que fue diseñado para hacer: delatar cuando cualquier recurso en una página HTTPS se obtiene vía HTTP.

Esta es la parte en la que los equipos entran en pánico, instalan tres plugins más y accidentalmente lo empeoran. No lo hagas. El contenido mixto es un problema de sistema: la base de datos, los temas, los plugins, las CDN, los proxies, las cachés y las cabeceras todos tienen voto. Se arregla reduciendo las fuentes, cambiando la capa correcta y previniendo recaídas.

Qué es realmente el contenido mixto (y por qué les importa a los navegadores)

El contenido mixto ocurre cuando una página cargada sobre HTTPS trae cualquier subrecurso por HTTP plano. Los subrecursos incluyen imágenes, CSS, JavaScript, fuentes, iframes, vídeo, llamadas XHR/fetch e incluso imágenes de fondo referenciadas dentro de CSS.

Los navegadores tratan esto como una degradación de seguridad. TLS protege el documento de nivel superior, pero si cargas un script por HTTP, un atacante en la red puede sustituirlo. Ahora tu página “segura” puede convertirse en un kiosco para robar credenciales.

Contenido mixto activo vs pasivo

  • Contenido mixto activo (scripts, iframes, XHR) puede ejecutar código o cambiar el comportamiento de la página. Los navegadores típicamente lo bloquean por defecto.
  • Contenido mixto pasivo (imágenes, audio, vídeo) usualmente no puede ejecutar código directamente. Los navegadores pueden permitirlo pero advertir. “Puede permitirlo” no es una estrategia.

Por qué “instalé SSL” no basta

La terminación SSL solo significa que el borde puede hablar HTTPS. WordPress aún puede:

  • Almacenar URLs absolutas HTTP en la base de datos.
  • Generar enlaces HTTP cuando cree que está en HTTP (desajuste por proxy inverso).
  • Cargar activos de terceros por HTTP (tema antiguo, fragmentos de proveedores, contenido embebido).
  • Servir redirecciones de forma inconsistente (algunas rutas 301 a HTTPS, otras no).
  • Cachear HTML antiguo que contiene URLs HTTP (caché de página, caché de CDN).

Una cosa más: las advertencias del navegador no siempre tratan de un obvio http://. Pueden venir de URLs relativas al protocolo (//example.com), url() en CSS, scripts inline y endpoints codificados por plugins. El contenido mixto es una cacería del tesoro, excepto que el tesoro se esconde en tu widget de pie de página.

Hechos interesantes y un poco de historia

  1. “Contenido mixto” es anterior a los navegadores modernos. Los primeros sitios HTTPS a menudo incrustaban imágenes HTTP para ahorrar CPU—TLS solía ser caro.
  2. “HTTPS como señal de ranking” de Google (2014) convirtió el candado de algo deseable a un KPI a nivel organizacional.
  3. Let’s Encrypt (lanzamiento público 2015) hizo los certificados gratuitos y automáticos, lo que incrementó la adopción de HTTPS—y expuso décadas de URLs codificadas en HTTP.
  4. HTTP/2 (estandarizado 2015) fue efectivamente solo para HTTPS en navegadores principales, empujando sitios a migrar para aprovechar características de rendimiento.
  5. Chrome empezó a etiquetar páginas HTTP como “No seguro” (2018) especialmente en formularios, lo que obligó a empresas reticentes a limpiar el contenido mixto durante migraciones a HTTPS.
  6. HSTS puede “bloquear” un dominio en HTTPS. Excelente para seguridad, brutal cuando aún tienes subdominios solo en HTTP o activos de terceros.
  7. URLs relativas al protocolo (//) fueron una vez un truco de migración. Hoy mayormente causan confusión y deberían retirarse en sitios modernos centrados en HTTPS.
  8. WordPress guarda URLs en muchos lugares. No solo en entradas: opciones, widgets, datos de constructores, arrays serializados y a veces modificaciones del tema.
  9. Algunas CDN reintroducen contenido mixto. Puedes terminar TLS en la CDN pero aún así recuperar activos del origen por HTTP o reescribir HTML de forma inconsistente.

Guía rápida de diagnóstico: encuentra al culpable rápido

Este es el orden de triaje que uso cuando alguien dice “el candado está roto” cinco minutos antes de un lanzamiento.

1) Reproduce con una página y mira la consola del navegador

Elige una sola página problemática, abre Herramientas del desarrollador → Consola y Red. Los errores de contenido mixto usualmente incluyen la URL exacta infractora.

Decisión: Si el recurso es de tu dominio, arregla WordPress/config/base de datos. Si es de terceros, decide si reemplazarlo, proxearlo o eliminarlo.

2) Confirma qué URL cree WordPress que es la suya

Si siteurl/home están en HTTP, WordPress generará enlaces HTTP por siempre.

Decisión: Si existe desajuste, corrige en la BD o vía WP-CLI, luego purga caches.

3) Valida TLS y el comportamiento de redirección desde el borde

Comprueba si HTTP redirige a HTTPS de forma consistente y si tu proxy inverso establece las cabeceras correctas.

Decisión: Si WordPress está detrás de un balanceador/CDN, asegúrate de que vea equivalentes de HTTPS=on (típicamente X-Forwarded-Proto: https).

4) Busca http:// codificado en el HTML renderizado

No adivines. Solicita la página y haz grep. Si aparece http://, tienes un problema de reescritura/base de datos/tema.

Decisión: Si está en HTML de entradas/opciones, haz un search-replace seguro. Si está en código de tema/plugin, corrige el código o anúlalo.

5) Si es “solo a veces”, sospecha de cachés o renderizado condicional

La caché de página, caché de objetos, CDN y cachés de constructores pueden preservar URLs antiguas. Además: la salida puede diferir entre usuarios autenticados y anónimos.

Decisión: Purga las capas de caché correctas y verifica con una petición fresca que evite la caché.

De dónde viene el contenido mixto en WordPress (modos reales de fallo)

URLs absolutas almacenadas en la base de datos

El contenido de WordPress es un vertedero de URLs. Entradas y páginas almacenan enlaces absolutos. También lo hacen los widgets. También los plugins de constructores. Lo peor: algunos plugins almacenan datos como arrays PHP serializados, por lo que un search/replace ingenuo rompe las longitudes de cadena y corrompe datos.

WP-CLI moderno maneja esto correctamente. La mayoría de plugins de “search replace” también lo hacen bien, pero ejecutarlos en producción sin copia de seguridad es cómo te ganas nuevas canas.

Hardcoding en tema o plugin

Patrones comunes:

  • Scripts/estilos encolados con http:// hardcodeado.
  • Fragmentos de Google Fonts o analytics copiados de un post antiguo.
  • CSS inline con background-image: url(http://...).
  • Widgets sociales antiguos y píxeles de seguimiento obsoletos.

Confusión por proxy inverso / CDN: WordPress cree que está en HTTP

Si TLS se termina en un balanceador (AWS ALB, proxy NGINX, CDN), el backend podría recibir HTTP plano. A menos que pases las cabeceras correctas y configures WordPress para confiar en ellas, generará URLs de recursos en HTTP.

Aquí también ves bucles: redirecciones HTTP→HTTPS suceden en el proxy, pero WordPress sigue redirigiendo de vuelta o generando esquemas mezclados en enlaces canónicos.

CDN o caché sirviendo HTML obsoleto

Arreglaste la BD, pero la CDN sigue sirviendo el HTML antiguo con URLs HTTP. O un plugin de caché de página tiene un archivo HTML estático de la semana pasada. O tu caché de objetos tiene opciones desactualizadas.

Contenido de terceros: el que no puedes arreglar desde aquí

Si un script de terceros solo se sirve por HTTP, es una dependencia muerta. Reemplázalo. Si no puedes reemplazarlo, a veces puedes proxearlo por tu dominio sobre HTTPS, pero entonces tú asumes la seguridad y el comportamiento de caché. No hagas esto a la ligera.

Broma #1: El contenido mixto es como llevar cinturón de seguridad mientras dejas la puerta del coche abierta—técnicamente intentaste, prácticamente no lo hiciste.

Tareas prácticas con comandos: detectar, decidir, arreglar

Estas tareas suponen que puedes SSH al host o contenedor que ejecuta WordPress. Si no puedes, aún puedes hacer la mayoría de comprobaciones desde tu portátil, pero la realidad de ops es: la solución suele vivir en el servidor.

Regla: Cada tarea termina con una decisión. Si no decides, solo estás coleccionando registros para tu álbum de recortes.

Tarea 1: Comprueba el HTML renderizado en busca de recursos HTTP obvios

cr0x@server:~$ curl -sS https://example.com/ | grep -Eo 'http://[^"]+' | head
http://example.com/wp-content/uploads/2022/10/hero.jpg
http://fonts.googleapis.com/css?family=Open+Sans:400,700

Qué significa: El HTML de la página incluye URLs absolutas HTTP.

Decisión: Si es tu dominio (example.com), arregla BD/tema. Si es de terceros (fonts.googleapis.com), actualiza el fragmento a HTTPS o reemplaza/elimina.

Tarea 2: Usa la vista tipo navegador con cabeceras para confirmar redirecciones

cr0x@server:~$ curl -I http://example.com/
HTTP/1.1 301 Moved Permanently
Location: https://example.com/
Server: nginx

Qué significa: HTTP redirige a HTTPS en el borde.

Decisión: Bien. Si no obtienes un 301/308 a HTTPS, arregla la política de redirección del servidor web/CDN primero. Arreglar contenido mixto es inútil si los usuarios aún pueden aterrizar en HTTP.

Tarea 3: Confirma la URL canónica que WordPress emite

cr0x@server:~$ curl -sS https://example.com/ | grep -iE 'rel="canonical"|og:url' | head -n 5
<link rel="canonical" href="http://example.com/" />
<meta property="og:url" content="http://example.com/" />

Qué significa: WordPress (o un plugin SEO) cree que la URL del sitio es HTTP.

Decisión: Arregla home y siteurl en las opciones de WP y verifica las cabeceras del proxy inverso.

Tarea 4: Comprueba la configuración de URL de WordPress vía WP-CLI

cr0x@server:~$ cd /var/www/html
cr0x@server:~$ wp option get home
http://example.com
cr0x@server:~$ wp option get siteurl
http://example.com

Qué significa: Tus URLs base están en HTTP, lo que genera enlaces internos en ese esquema.

Decisión: Actualiza ambos a HTTPS (tarea siguiente), luego purga caches.

Tarea 5: Actualiza home y siteurl de forma segura

cr0x@server:~$ wp option update home 'https://example.com'
Success: Updated 'home' option.
cr0x@server:~$ wp option update siteurl 'https://example.com'
Success: Updated 'siteurl' option.

Qué significa: WordPress ahora generará URLs HTTPS por defecto.

Decisión: Vuelve a probar la página. Si aún ves HTTP en el contenido, necesitas un search/replace en entradas/opciones.

Tarea 6: Identifica URLs HTTP en la base de datos (primeramente en modo dry-run)

cr0x@server:~$ wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run
+----------------------+--------------+--------------+------+
| Table                | Column       | Replacements | Type |
+----------------------+--------------+--------------+------+
| wp_posts             | post_content | 128          | SQL  |
| wp_postmeta          | meta_value   | 42           | PHP  |
| wp_options           | option_value | 19           | PHP  |
+----------------------+--------------+--------------+------+
Success: Made 189 replacements.

Qué significa: Hay 189 ocurrencias de URLs HTTP, incluyendo datos serializados (marcados PHP).

Decisión: Si los reemplazos parecen sensatos, ejecuta el mismo comando sin --dry-run. Si el conteo es inesperadamente grande, detente y haz una copia de seguridad de la BD primero.

Tarea 7: Realiza el search/replace por real

cr0x@server:~$ wp search-replace 'http://example.com' 'https://example.com' --all-tables
+----------------------+--------------+--------------+------+
| Table                | Column       | Replacements | Type |
+----------------------+--------------+--------------+------+
| wp_posts             | post_content | 128          | SQL  |
| wp_postmeta          | meta_value   | 42           | PHP  |
| wp_options           | option_value | 19           | PHP  |
+----------------------+--------------+--------------+------+
Success: Made 189 replacements.

Qué significa: El contenido de la base de datos ahora referencia HTTPS para tu dominio.

Decisión: Purga capas de caché; luego vuelve a ejecutar la Tarea 1. Si quedan HTTP de terceros, arréglalos individualmente.

Tarea 8: Encuentra HTTP hardcodeado en código de tema/plugin

cr0x@server:~$ grep -RIn --exclude-dir=node_modules --exclude-dir=.git "http://" wp-content/themes wp-content/plugins | head
wp-content/themes/acme/header.php:44:    <script src="http://cdn.vendor.example/widget.js"></script>
wp-content/plugins/old-analytics/old-analytics.php:12:$src = 'http://stats.vendor.example/pixel.js';

Qué significa: Tienes HTTP hardcodeado en código. El search/replace en BD no tocará esto.

Decisión: Actualiza a HTTPS o elimina la dependencia. Si el proveedor no soporta HTTPS, reemplázalo. No “ignores la advertencia”.

Tarea 9: Confirma lo que el backend ve (comprobación de proxy inverso)

cr0x@server:~$ wp eval 'var_dump($_SERVER["HTTPS"] ?? null, $_SERVER["HTTP_X_FORWARDED_PROTO"] ?? null);'
NULL
string(4) "http"

Qué significa: WordPress cree que está en HTTP detrás del proxy (forwarded proto es http).

Decisión: Arregla el proxy para que establezca X-Forwarded-Proto: https en peticiones TLS, y configura WordPress para confiar en ello (a menudo vía wp-config.php o configuración del servidor). Sin esto, el contenido mixto puede reaparecer incluso después de limpiar la BD.

Tarea 10: Inspecciona cabeceras de respuesta por seguridad y pistas de esquema

cr0x@server:~$ curl -sSI https://example.com/ | grep -iE 'strict-transport-security|content-security-policy|location|x-forwarded-proto'
Strict-Transport-Security: max-age=0

Qué significa: HSTS está deshabilitado (max-age=0). No es contenido mixto directo, pero afecta cuán agresivamente los navegadores se mantienen en HTTPS.

Decisión: No actives HSTS con un max-age largo hasta que el contenido mixto esté realmente eliminado y estés seguro de que cada subdominio puede hacer HTTPS.

Tarea 11: Revisa la configuración de NGINX para cabeceras de proxy (si lo ejecutas)

cr0x@server:~$ sudo nginx -T 2>/dev/null | grep -n "X-Forwarded-Proto" | head
128:    proxy_set_header X-Forwarded-Proto $scheme;

Qué significa: NGINX pasará el esquema que recibió. Si NGINX termina TLS, $scheme debería ser https.

Decisión: Si TLS termina en otro lugar (CDN/ELB), entonces NGINX puede ver HTTP y pasar http. En ese caso, establécelo explícitamente basado en las cabeceras reenviadas entrantes, o termina TLS en NGINX.

Tarea 12: Encuentra contenido mixto en archivos CSS (las imágenes de fondo son furtivas)

cr0x@server:~$ grep -RIn "url(http://" wp-content | head
wp-content/themes/acme/assets/css/main.css:233:background-image: url(http://example.com/wp-content/uploads/2021/03/bg.png);

Qué significa: Activos estáticos referencian HTTP dentro de CSS. Los navegadores marcarán esto.

Decisión: Arregla el CSS (usa rutas relativas o HTTPS) y reconstruye/minifica si es necesario. Luego purga cachés/CDN.

Tarea 13: Verifica que las subidas se sirvan por HTTPS y no redirijan raro

cr0x@server:~$ curl -I https://example.com/wp-content/uploads/2022/10/hero.jpg
HTTP/2 200
content-type: image/jpeg
cache-control: public, max-age=31536000

Qué significa: Las subidas son accesibles vía HTTPS directamente.

Decisión: Si ves redirecciones a HTTP o a un host diferente, arregla reglas de reescritura, configuración de origen de CDN o ajustes de plugins de offload.

Tarea 14: Comprueba WordPress para ajustes de “forzar SSL” y esquema del admin

cr0x@server:~$ wp config get FORCE_SSL_ADMIN --type=constant
true

Qué significa: El admin está forzado a SSL. Bien, pero no garantiza la corrección del frontend.

Decisión: Manténlo, pero no lo confundas con una solución de contenido mixto. Los activos del frontend y el contenido aún necesitan limpieza.

Tarea 15: Comprueba que no quede HTTP en la página tras las correcciones

cr0x@server:~$ curl -sS https://example.com/ | grep -Eo 'http://[^"]+' | wc -l
0

Qué significa: El HTML de esa página ya no contiene URLs HTTP obvias.

Decisión: Si el navegador aún advierte, probablemente venga de peticiones en tiempo de ejecución (JS, llamadas a terceros) o de otra plantilla de página. Usa Herramientas del desarrollador → Red para capturarlo.

Tarea 16: Si usas una CDN, confirma que no esté reescribiendo o cacheando contenido antiguo

cr0x@server:~$ curl -sSI https://example.com/ | grep -iE 'cf-cache-status|x-cache|age|via'
Age: 8421
Via: 1.1 varnish

Qué significa: Estás alcanzando una capa de caché con contenido envejecido. Puede que aún contenga enlaces HTTP antiguos.

Decisión: Purga la caché para las rutas afectadas, o invalida todo si cambiaste URLs del sitio. Luego vuelve a probar con Cache-Control: no-cache o un bypass por query-string (según reglas de tu CDN).

Tres mini-historias corporativas (cómo sale mal)

Mini-historia 1: El incidente causado por una suposición errónea

La Compañía A movió un sitio de marketing WordPress tras un flamante balanceador de carga. TLS se terminaba en el LB; el tráfico al origen era HTTP en una red privada. Todos asintieron y dijeron: “Está bien, el tráfico interno es de confianza.” Tenían media razón, que es la peor clase de razón.

El equipo web verificó que https:// cargaba y vio el candado en la página principal. Llegó el día del lanzamiento. De pronto el tráfico pagado empezó a aterrizar en páginas de campaña que mostraban advertencias “No seguro” en algunos navegadores. La conversión cayó. Marketing culpó al tema nuevo. El equipo de temas culpó a la CDN. El SRE de turno culpó a la gravedad.

La causa raíz fue simple: WordPress pensaba que las peticiones eran HTTP porque la cabecera forwarded proto estaba mal. El LB envió X-Forwarded-Proto: http por una regla de listener mal configurada. La página principal había quedado cacheada con enlaces HTTPS correctos por una ruta de petición previa, pero varias páginas de destino se renderizaron frescas y generaron enlaces de activos en HTTP.

Arreglo: corregir el comportamiento de la cabecera del LB, añadir lógica en el backend para confiar en esa cabecera solo desde IPs de proxy conocidas, purgar cache y luego ejecutar un search/replace en la base de datos para limpiar el contenido antiguo. La “suposición errónea” fue creer que “TLS en el borde significa que la aplicación sabe que está en HTTPS.” No lo sabe. El software no es psíquico.

Mini-historia 2: La optimización que salió mal

La Compañía B quería páginas más rápidas. Alguien activó “reescritura HTML” en la CDN para minificar y “normalizar” contenido. Sonaba inofensivo. Incluso mejoró las puntuaciones de Lighthouse durante una semana.

Luego un update de plugin introdujo URLs relativas al protocolo para una inclusión de script: //vendor.example/script.js. La lógica de reescritura de la CDN intentó ser útil y “estandarizar” enlaces. Reescribió algunas URLs relativas al protocolo a http:// cuando la obtención al origen fue por HTTP (porque la conexión CDN→origen usaba HTTP por razones de rendimiento—sí, en serio).

Resultado: los navegadores comenzaron a bloquear contenido mixto activo, pero solo para usuarios que alcanzaban páginas cacheadas procesadas por esa ruta de reescritura. DevTools mostraba el script viniendo por HTTP, pero buscar en la base de datos de WordPress no lo encontraba. El equipo perdió horas haciendo search/replace en contenido que nunca fue la fuente.

La solución no fue revertir el plugin. Fue desactivar la reescritura HTML de la CDN (o configurarla para preservar el esquema), mover la conexión CDN→origen a HTTPS y fijar recursos críticos de terceros a HTTPS explícito. Optimización que salió mal, clásico. Internet siempre cobra su deuda con intereses.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

La Compañía C tenía un runbook poco emocionante para “migraciones de URL del sitio” que a nadie le gustaba. Requería: copia de seguridad de la BD, WP-CLI dry-run de search/replace, verificación con curl/grep, purga de caché y luego una página canaria en staging y producción.

Durante un rebranding, cambiaron de dominio y habilitaron HTTPS en todas partes. Debería haber aparecido contenido mixto—había años de imágenes embebidas, bloques HTML inline y un builder que guardaba blobs JSON en postmeta.

Pero el runbook los obligó a hacer las partes desagradables: un reemplazo con WP-CLI seguro para serializados, un escaneo por http:// en directorios de tema/plugin y un paso de verificación que solicitaba las 20 plantillas principales y hacía grep buscando HTTP. También ordenaba purgar la CDN después de los cambios, no antes.

El día del lanzamiento fue sin incidentes. Nadie elogió el runbook. Así sabes que funcionó. La práctica aburrida no solo arregló el contenido mixto; evitó que apareciera como una advertencia aleatoria que dañara la reputación durante un momento de alta visibilidad.

Errores comunes: síntoma → causa raíz → solución

Síntoma: La página principal muestra candado, pero algunas páginas muestran “No seguro”
Causa raíz: Página principal cacheada vs plantillas no cacheadas; contenido mixto en bloques del builder o postmeta específicos.
Solución: Usa Herramientas del desarrollador en una página fallida, luego ejecuta WP-CLI search-replace en todas las tablas, además de escanear código de tema/plugin en busca de HTTP hardcodeado.
Síntoma: La consola del navegador dice “blocked active mixed content” por un archivo JS
Causa raíz: Inclusión de script con http:// hardcodeado en tema, plugin o snippet inyectado por un tag manager.
Solución: Elimina o actualiza el snippet a HTTPS; si el tercero no soporta HTTPS, reemplaza al proveedor. No proxees JS arbitrario salvo que aceptes la responsabilidad.
Síntoma: Admin de WordPress es HTTPS, pero el frontend entrega assets en HTTP
Causa raíz: FORCE_SSL_ADMIN activado, pero home/siteurl siguen en HTTP; o desajuste de cabeceras del proxy inverso.
Solución: Actualiza home y siteurl a HTTPS; asegúrate de que X-Forwarded-Proto sea correcto; purga caches.
Síntoma: Contenido mixto aparece solo para algunos usuarios o regiones
Causa raíz: Caché edge de CDN con HTML obsoleto; POPs regionales con estados de caché diferentes; A/B testing inyectando URLs HTTP.
Solución: Purga cachés CDN; verifica claves de caché; audita sistemas de inyección; vuelve a probar desde varias regiones con cabeceras consistentes.
Síntoma: Después de “arreglar” con un plugin, el diseño se rompe o desaparece contenido
Causa raíz: Un search/replace ingenuo corrompió datos serializados o blobs JSON de constructores.
Solución: Restaura la copia de seguridad; usa WP-CLI search-replace que maneja serialización; vuelve a ejecutar con dry-run primero.
Síntoma: Las imágenes cargan, pero el navegador aún advierte sobre contenido mixto
Causa raíz: Un iframe, script, fuente o XHR sigue siendo HTTP. Las imágenes son solo el sospechoso habitual, no el único.
Solución: Revisa Herramientas del desarrollador → Red filtrando por “blocked” o “mixed content”; escanea fuente de página y CSS en busca de http://.
Síntoma: Activaste HSTS y ahora partes del sitio están rotas
Causa raíz: Algunos subrecursos (subdominios, contenido de terceros) aún requieren HTTP; HSTS fuerza HTTPS y revela brechas sin piedad.
Solución: Revierte HSTS (max-age corto), arregla dependencias, luego vuelve a habilitar gradualmente. No pre-cargues hasta estar seguro.
Síntoma: WooCommerce falla en el checkout o el iframe de pago no carga
Causa raíz: Activos del proveedor de pagos solicitados por HTTP, o endpoints de callback con esquema incorrecto detrás del proxy.
Solución: Asegura que las URLs del proveedor sean HTTPS; confirma cabeceras del proxy; valida la página de checkout en Herramientas del desarrollador y la configuración del proveedor.

Listas de verificación / plan paso a paso (hazlo una vez, hazlo bien)

Checklist A: WordPress de un solo sitio, TLS directo en el servidor web

  1. Confirma que HTTP → HTTPS redirige para / y varias rutas profundas (categoría, entrada, activo).
  2. Confirma que el certificado es válido y la cadena es correcta (chequeo en navegador + curl cabeceras).
  3. Establece home y siteurl a HTTPS vía WP-CLI.
  4. Ejecuta WP-CLI search-replace (dry-run, luego real) para tu dominio.
  5. Grep en directorios de tema/plugin buscando http://; arregla assets hardcodeados.
  6. Purga el plugin de caché de página y regenera assets minificados.
  7. Solicita plantillas principales y haz grep buscando http:// en HTML renderizado.
  8. Verifica en Herramientas del desarrollador: sin contenido mixto en Consola; sin peticiones bloqueadas en Red.

Checklist B: WordPress detrás de proxy inverso / balanceador / CDN

  1. Confirma que el borde redirige HTTP → HTTPS consistentemente.
  2. Confirma que el borde envía cabeceras reenviadas correctas (X-Forwarded-Proto: https cuando el cliente usa HTTPS).
  3. Configura el servidor backend y/o WordPress para confiar en cabeceras de proxy solo desde rangos de IPs de proxy conocidos.
  4. Establece home y siteurl a HTTPS.
  5. Ejecuta reemplazo en BD seguro para serializados.
  6. Purga cachés CDN después de los cambios de contenido (no antes).
  7. Verifica que el origen no esté generando HTTP en etiquetas canónicas/meta para páginas no cacheadas.
  8. Solo entonces considera habilitar HSTS con un max-age corto, luego extiende.

Checklist C: Escenario de migración (cambio de dominio o esquema)

  1. Haz backup de BD y uploads. Sin backup, no hagas cambios. No es dogma, es supervivencia.
  2. Etapa el cambio en un entorno staging con copia de datos de producción.
  3. Ejecuta WP-CLI dry-run search-replace; revisa conteos por tabla/columna.
  4. Ejecuta el reemplazo real; verifica páginas principales y flujos críticos (login, checkout, formularios).
  5. Cambia DNS / configuración de borde; verifica redirecciones y etiquetas canónicas.
  6. Purga cachés y calienta la CDN con un pequeño crawl de páginas importantes.
  7. Monitorea logs de error y errores en consola del cliente vía RUM si está disponible.

Prevención: evita que el contenido mixto vuelva

Establece las invariantes correctas

  • Todo es HTTPS (incluyendo subidas, llamadas API, fuentes, analytics, embeds).
  • Un host canónico (www vs apex, elige uno y redirige el otro).
  • Un esquema canónico (HTTPS, siempre).

Usa Content Security Policy (CSP) como guardarraíl, no como parche

CSP puede ayudarte a detectar regresiones reportando contenido mixto bloqueado o fuentes no permitidas. Pero CSP no arregla mágicamente URLs rotas almacenadas en la base de datos. Solo hace el fallo más ruidoso y determinista.

Si despliegas CSP, empieza en modo report-only, observa qué se bloquea y luego aprieta. Trátalo como un proceso de gestión de cambios, no como una línea de comando.

HSTS: poderoso, peligroso cuando eres descuidado

HSTS le dice a los navegadores: “Usa siempre HTTPS para este dominio.” Es bueno. También significa que cualquier dependencia HTTP restante se convierte en una falla dura. Despliega en fases: max-age corto, verifica, luego aumenta. Evita preloading hasta que tu sitio esté limpio y se mantenga limpio.

Cita operativa

La esperanza no es una estrategia. — James Cameron

Broma #2: El candado del navegador es básicamente tu auditor de seguridad, excepto que trabaja fines de semana y nunca acepta donas.

Preguntas frecuentes

¿Por qué sigo teniendo contenido mixto después de cambiar Dirección de WordPress y Dirección del sitio?

Porque esas configuraciones cambian lo que WordPress genera en adelante, no lo que ya guardaste. Entradas antiguas, widgets, datos de constructores y opciones de tema aún pueden contener URLs absolutas HTTP. Ejecuta un search-replace seguro para serializados y escanea código de tema/plugin.

¿Puedo “arreglar contenido mixto” con un plugin que fuerza HTTPS?

A veces oculta los síntomas reescribiendo la salida. Rara vez arregla las causas raíz. Úsalo solo como mitigación temporal mientras limpias la base de datos y el código. De lo contrario, introducirás un hack permanente que falla con caché, minificación o actualizaciones de plugins.

¿Cuál es la forma más segura de reemplazar HTTP por HTTPS en la base de datos?

WP-CLI wp search-replace con dry-run primero. Maneja datos serializados correctamente. Siempre haz copia de seguridad de la BD antes de la ejecución real, especialmente en sitios con constructores de páginas.

¿Por qué aparece contenido mixto solo en Chrome y no en Firefox (o al revés)?

Los navegadores difieren en lo que bloquean vs advierten, y difieren en comportamiento de caché e informes en Herramientas del desarrollador. No discutas con el navegador; usa Herramientas del desarrollador → Red/Consola para identificar la URL exacta y arréglala en la fuente.

Estoy detrás de Cloudflare (u otra CDN). ¿Por qué WordPress cree que está en HTTP?

Porque la conexión al origen puede ser HTTP, y las cabeceras reenviadas pueden no estar establecidas o ser de confianza. Asegura que la CDN envíe X-Forwarded-Proto: https y configura origen/WordPress para tratar la petición como HTTPS cuando corresponda.

¿Está bien dejar contenido mixto “pasivo” como imágenes?

No. Enseña a los usuarios a ignorar señales de seguridad y aún puede filtrar comportamiento de usuario vía metadatos de las peticiones. Además, los navegadores cada vez endurecen más las reglas. Arréglalo ahora mientras es una advertencia, no una página rota.

¿Habilitar HSTS arreglará el contenido mixto?

No. HSTS fuerza HTTPS para la navegación de nivel superior a tu dominio. No reescribe URLs de terceros, y no arreglará enlaces HTTP embebidos en HTML, CSS o scripts. Puede hacer las fallas más obvias, lo cual es útil después de limpiar.

¿Por qué WooCommerce muestra contenido mixto específicamente en checkout?

Las páginas de checkout suelen incluir scripts del proveedor de pagos, iframes y llamadas API. Un endpoint HTTP es suficiente para disparar advertencias o bloqueos. Revisa Herramientas del desarrollador para URLs de terceros y asegúrate de las cabeceras del proxy y los ajustes de URL del sitio.

¿Cómo sé que lo arreglé en todas partes y no solo en una página?

Prueba plantillas representativas: homepage, entrada de blog, categoría, búsqueda, login, carrito/checkout y algunas landing pages creadas con tu builder. Programa peticiones y haz grep buscando http:// en HTML, y usa Herramientas del desarrollador para capturar peticiones en tiempo de ejecución.

Próximos pasos que puedes enviar hoy

  1. Elige una página que falle y identifica el recurso HTTP exacto en Herramientas del desarrollador.
  2. Verifica que home y siteurl estén en HTTPS; corrige si no.
  3. Ejecuta WP-CLI search-replace (dry-run, luego real) para tu dominio.
  4. Escanea código de tema/plugin y CSS en busca de http:// hardcodeado y elimínalo.
  5. Purga todas las capas de caché (página + CDN) después de los cambios.
  6. Sólo después de que el sitio esté limpio, implementa HSTS gradualmente para prevenir recaídas.

Si sigues esos pasos en orden, el contenido mixto deja de ser un capricho del navegador y se convierte en una limpieza de ingeniería directa. Que es lo que siempre fue.

← Anterior
Docker: Escrituras lentas en overlay2 — cuándo cambiar a volúmenes y por qué
Siguiente →
pveperf de Proxmox muestra datos absurdos: cómo medir el rendimiento correctamente

Deja un comentario