WordPin analiza en su garaje-oficina un problema del .htaccess donde varias URLs de WordPress redirigen a la home

El .htaccess en WordPress que redirigía todo a la home · WordPin 007

🎧 Escuchar: El .htaccess en WordPress que redirigía todo a la home · WordPin 007

La web de un ayuntamiento pequeño llevaba más de un año funcionando sin incidentes serios. Páginas de trámites, convocatorias, actas municipales, agenda cultural. Todo servido desde un WordPress con tema personalizado sobre Apache, sin grandes complicaciones. Hasta que una mañana, al hacer clic en cualquier sección interna, el navegador devolvía siempre la portada. No una página de error. No un 404. La portada, limpia, cargada correctamente, como si el sitio solo tuviera una página.

La navegación completa estaba rota. Fichas de servicio, categorías, entradas del blog institucional, incluso algunas rutas del panel de administración. Todo acababa en la home. No había un patrón parcial: era absoluto. Revisé las cabeceras y cada petición interna recibía una respuesta 301 o 302 hacia la raíz del dominio. Eso descartaba un fallo de plantilla o un error visual. El servidor estaba respondiendo con redirecciones explícitas, y el archivo .htaccess era el primer lugar donde mirar, pero también el más obvio.

Algo estaba forzando esa redirección desde un nivel que WordPress no controlaba directamente. La pregunta era si venía de una regla consciente que alguien había añadido, o de un efecto colateral que se había activado sin aviso.

Sello marcado como abierto del archivo de WordPin 007
Ficha del archivo Nº: 007

Operario: WordPin

Archivo del caso: El .htaccess en WordPress que redirigía todo a la home

Empresa o negocio: Web institucional de un ayuntamiento pequeño

Archivado en: Configuración de WordPress

Nivel: Avanzado

Lo que el .htaccess dejaba pasar sin aviso

Lo primero fue confirmar el síntoma con datos limpios. Lancé varias peticiones con cURL contra rutas internas reales del sitio: una ficha de trámite, una entrada del blog, una categoría, una página de segundo nivel. Todas devolvían lo mismo.

curl -I https://www.ayuntamiento-ejemplo.es/tramites/certificado-empadronamiento/

HTTP/1.1 301 Moved Permanently
Location: https://www.ayuntamiento-ejemplo.es/
curl -I https://www.ayuntamiento-ejemplo.es/category/cultura/

HTTP/1.1 301 Moved Permanently
Location: https://www.ayuntamiento-ejemplo.es/

La respuesta era idéntica para todas las rutas. El código de estado variaba entre 301 y 302 en algunos casos, pero el destino siempre era la raíz. No había diferencia entre contenido público y categorías. Incluso /wp-admin/edit.php sufrió la redirección en una de las pruebas, aunque el acceso al escritorio principal (/wp-admin/) sí funcionaba.

Que una página cargue no significa que la ruta esté bien resuelta.

El plugin de redirecciones como primera sospecha

El sitio tenía instalado un plugin de redirecciones. Lo habían usado meses atrás para redirigir URLs antiguas de la web anterior del ayuntamiento tras una migración de contenido. Era el sospechoso más cómodo: un plugin con capacidad de crear reglas 301 masivas, con historial de uso activo y con acceso directo al flujo de peticiones.

Accedí por FileZilla al servidor y renombré la carpeta del plugin para desactivarlo sin pasar por el escritorio. Si el plugin estaba inyectando redirecciones, al quitarlo del mapa el comportamiento debía cambiar.

mv wp-content/plugins/redirection wp-content/plugins/redirection_disabled

Repetí las pruebas con cURL. Misma respuesta. 301 hacia la home en todas las rutas internas. El plugin no tenía nada que ver. Lo restauré a su nombre original y seguí buscando.

Dentro del .htaccess: las líneas que no cuadraban

La segunda hipótesis fue un problema de permalinks. Después de una actualización menor de WordPress que había ocurrido dos semanas antes, era posible que la estructura de enlaces permanentes configurada no se correspondiera con las reglas que WordPress había escrito en el bloque de reescritura del .htaccess. Si ese bloque había quedado desactualizado, WordPress podía estar fallando al resolver las rutas.

Entré en Ajustes → Enlaces permanentes desde el escritorio, que seguía parcialmente accesible. La estructura estaba configurada como /%postname%/. Guardé sin cambiar nada, forzando la regeneración. WordPress respondió sin errores. Pero al probar de nuevo con cURL, las redirecciones seguían ahí. El mismo 301 absoluto.

Esto no encajaba. Si el problema fuera de permalinks, al menos algunas rutas deberían haber devuelto un 404 o haber cargado el contenido incorrecto. Pero una redirección activa, con cabecera Location explícita, no es algo que WordPress genere desde su bloque de reescritura estándar. Eso venía de más arriba.

El servidor puede responder bien y aun así estar entregando la respuesta equivocada.

Descargué el .htaccess del directorio raíz por FTP y lo abrí. El bloque estándar de WordPress estaba presente y parecía correcto. Pero encima de él había más líneas. Varias reglas añadidas manualmente, algunas con comentarios en castellano, otras sin ninguna referencia. Era un archivo que había pasado por varias manos a lo largo de la vida del sitio.

La regla que capturaba lo que no debía

Revisé el .htaccess línea por línea. El bloque de WordPress estaba intacto:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Eso estaba limpio. El problema no estaba en el bloque que WordPress genera, sino en lo que había por encima. Entre varias directivas de seguridad y un par de cabeceras de caché, encontré esto:

# Redirigir antiguas rutas web anterior
RewriteEngine On
RewriteRule ^(.+)$ https://www.ayuntamiento-ejemplo.es/ [R=301,L]

Ahí estaba. Una regla de reescritura que capturaba cualquier petición cuya URI tuviera al menos un carácter (^(.+)$) y la redirigía con un 301 permanente a la raíz del dominio. La flag [L] la convertía en la última regla evaluada, así que nada de lo que venía después —incluido el bloque de WordPress— llegaba a ejecutarse.

La intención original parecía clara: alguien quiso redirigir las rutas antiguas de la web anterior del ayuntamiento durante una migración. Probablemente funcionó en su momento como solución temporal. Pero nunca se retiró, y el momento en que empezó a manifestarse como problema quedó sin confirmar: no había registro de cuándo se añadió exactamente ni de qué cambio en el entorno la había convertido en activa para todo el tráfico.

El patrón ^(.+)$ no excluía archivos reales ni directorios existentes. No tenía un RewriteCond que filtrara por tipo de recurso, por extensión ni por ruta específica. Capturaba todo: fichas, categorías, entradas, archivos adjuntos, páginas de administración. Todo menos la raíz vacía, que al no tener caracteres en su URI relativa, escapaba del patrón.

Eso explicaba por qué la home cargaba bien y el escritorio principal (/wp-admin/) a veces respondía: dependía de cómo Apache resolvía la barra final frente al patrón de captura. Pero cualquier ruta con contenido explícito en la URI quedaba atrapada.

El impacto en SEO era directo. Cada URL indexada del sitio estaba devolviendo un 301 permanente hacia la home. Para un buscador, eso equivale a decir que todo el contenido se ha movido a una sola página. Si la situación se mantenía el tiempo suficiente, las URLs internas perderían su posición y el sitio quedaría reducido a una sola entrada en los resultados. Las fichas de trámites, las convocatorias, las actas: todo desindexado en la práctica.

WordPress no siempre falla donde grita. A veces falla donde todavía parece obedecer.

Reconstruir las reglas sin arrastrar el fallo

La solución más rápida habría sido borrar la línea problemática y guardar. Pero el .htaccess de este sitio no era un archivo limpio con solo el bloque de WordPress. Tenía directivas de seguridad, cabeceras personalizadas, reglas de caché del hosting y restos de configuraciones anteriores. Eliminar solo la línea sin revisar el contexto completo era arriesgado: podía haber otras reglas que dependieran indirectamente de esa posición, o condiciones que quedaran huérfanas.

Qué limpiar primero y qué dejar quieto

La tentación era reescribir el archivo de directivas desde cero: dejar solo el bloque de WordPress y las cabeceras estrictamente necesarias. Pero eso significaba descartar reglas de seguridad que alguien había añadido por un motivo, y cabeceras de caché que el hosting podía necesitar. Sin documentación clara de qué hacía cada bloque, limpiar de golpe podía resolver la redirección y crear tres problemas nuevos.

Lo que hice fue trabajar por capas. Primero, comenté la regla conflictiva sin borrarla, para poder revertir si algo fallaba:

# DESACTIVADA - regla de migración obsoleta
# RewriteRule ^(.+)$ https://www.ayuntamiento-ejemplo.es/ [R=301,L]

Subí el archivo por FTP y probé con cURL. Las rutas internas empezaron a devolver 200 OK. Las fichas cargaban, las categorías respondían, las entradas del blog institucional mostraban su contenido. La redirección había desaparecido.

Después revisé el resto de reglas del .htaccess para verificar que no hubiera otras directivas de reescritura que pudieran activarse en un escenario parecido. Encontré dos bloques más con reglas de mod_rewrite, pero ambas tenían condiciones específicas (RewriteCond) que limitaban su alcance a extensiones concretas o a un subdominio antiguo que ya no existía. Las dejé comentadas igualmente, con una nota explicativa.

El bloque de WordPress lo dejé intacto. No necesitaba regeneración porque nunca había sido el problema. Validé las prioridades: primero las directivas de seguridad, luego las cabeceras de caché, y al final el bloque de reescritura de WordPress como cierre. Sin reglas intermedias que pudieran interceptar peticiones antes de tiempo.

Para confirmar que todo estaba resuelto, recorrí las rutas críticas del sitio. Probé con la referencia de mod_rewrite abierta para verificar la sintaxis de cada regla que quedaba activa. Lancé cURL contra quince URLs distintas: trámites, categorías, entradas, páginas de segundo nivel, archivos PDF, el feed RSS y varias rutas del escritorio. Todas respondieron correctamente.

curl -I https://www.ayuntamiento-ejemplo.es/tramites/certificado-empadronamiento/

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8

Eliminé las líneas comentadas de la regla conflictiva del archivo final para no dejar código muerto en producción. Guardé una copia del .htaccess original con fecha en una carpeta de respaldo fuera del directorio público, por si alguien necesitaba consultarlo después.

Un error parcial suele ser más peligroso que una caída total, porque deja demasiadas cosas funcionando.

Le pedí al responsable del sitio que vigilara Google Search Console durante las semanas siguientes. Las URLs que habían estado devolviendo 301 necesitaban que el rastreador volviera a visitarlas y confirmara el 200. Si el 301 había estado activo menos de dos semanas, la recuperación debía ser rápida. Si había sido más tiempo, algunas páginas podrían tardar en volver al índice.

WordPin 007 sello de archivo marcado como completado

💡 Qué he aprendido

Este caso me recordó algo que debería tener siempre presente: el .htaccess no es solo el bloque de WordPress. Es un archivo compartido, acumulativo, donde conviven reglas de épocas distintas escritas por personas distintas. Una línea que funcionó durante una migración puede convertirse en una trampa meses después, cuando ya nadie recuerda que está ahí.

He confirmado que los falsos positivos más convincentes son los que tienen historial. Un plugin de redirecciones que sí se usó para redirigir URLs antiguas parecía el culpable perfecto. Los permalinks recién regenerados tras un update menor parecían otra pista sólida. Pero el fallo estaba en una capa que ninguno de los dos controlaba, en una regla de servidor escrita a mano que llevaba meses esperando para romper algo.

Aprendí a no confiar en lo que parece limpio. El bloque de WordPress estaba perfecto. Lo que lo anulaba estaba justo encima, en las líneas que nadie revisa porque llevan ahí demasiado tiempo.

Cuaderno de WordPin

Forense WordPress

Archivo Nº 007: El .htaccess en WordPress que redirigía todo a la home

🧩 Notas técnicas

⬋⬋

Web institucional de un ayuntamiento sobre WordPress y Apache. Todas las URLs internas devolvían un 301 hacia la portada, afectando fichas de trámites, categorías, entradas y parte del panel de administración. El sitio parecía funcionar porque la home cargaba correctamente.

La causa fue una regla de reescritura heredada de una migración anterior, colocada antes del bloque de WordPress en el archivo de directivas del servidor. Capturaba todas las peticiones con contenido en la URI y las redirigía a la raíz. Se eliminó la regla, se verificó la integridad del resto de directivas y se validaron las rutas críticas antes de restaurar el tráfico normal.

🔎 Pistas detectadas

⬋⬋

  • Cada URL interna devolvía un 301 o 302 con Location apuntando siempre a la raíz del dominio.
  • La home cargaba correctamente, lo que descartaba un fallo general del servidor o de WordPress.
  • Desactivar el plugin de redirecciones no alteró el comportamiento.
  • Guardar los permalinks no resolvió las redirecciones, señalando que el origen no estaba en el bloque de reescritura de WordPress.
  • El archivo de directivas del servidor contenía reglas manuales anteriores al bloque de WordPress, sin condiciones de filtrado.

🚫 Errores en WordPress detectados

⬋⬋

  • Regla RewriteRule ^(.+)$ sin condiciones previas, capturando todas las peticiones antes del bloque de WordPress e impidiendo la resolución de rutas.
  • Código 301 permanente aplicado a URLs activas, enviando al buscador la señal de que todo el contenido se había consolidado en la portada.
  • Flag [L] en la regla conflictiva, que cortaba la evaluación e impedía que el bloque estándar de WordPress se ejecutara.
  • Ausencia de RewriteCond para excluir archivos reales, directorios o rutas específicas de la captura masiva.
  • Reglas de migración obsoletas mantenidas en producción sin documentación ni fecha de caducidad prevista.

📘 Glosario de WordPress

⬋⬋

  • .htaccess: archivo de configuración de Apache que controla redirecciones, reescritura de URLs, seguridad y cabeceras a nivel de directorio.
  • mod_rewrite: módulo de Apache que permite transformar URLs mediante reglas y condiciones antes de que lleguen a WordPress.
  • RewriteRule: directiva que define un patrón de captura y una acción de reescritura o redirección sobre las URLs entrantes.
  • RewriteCond: condición que limita cuándo se aplica una RewriteRule, filtrando por host, archivo existente, variable o cabecera.
  • 301 Moved Permanently: código HTTP que indica una redirección permanente; los buscadores transfieren autoridad a la URL de destino.

📏 Mini guía práctica

⬋⬋

  1. Descarga una copia del archivo de directivas del servidor antes de modificar cualquier regla en producción.
  2. Lanza peticiones con curl -I contra varias URLs internas para confirmar qué código de estado y cabecera Location devuelve el servidor.
  3. Revisa todas las reglas de reescritura que estén por encima del bloque # BEGIN WordPress, prestando atención a patrones sin condiciones restrictivas.
  4. Comenta las reglas sospechosas en lugar de borrarlas directamente, para poder revertir si el cambio tiene efectos no previstos.
  5. Verifica en Google Search Console que las URLs afectadas empiezan a devolver 200 tras la corrección, y monitoriza la reindexación durante las semanas siguientes.

Comparte el conocimiento. Comparte la historia

Expedientes y Archivos

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Respetamos tu privacidad. Los datos que proporciones se utilizarán únicamente para gestionar y mostrar tu comentario, así como para prevenir el uso indebido o el spam. Puedes consultar más información en nuestra política de privacidad.

Subir