Redirecciones .htaccess en WordPress: 301, 302 y RewriteRule

Redirecciones .htaccess en WordPress: 301, 302 y RewriteRule

Última verificación: 15 de octubre de 2026
20 min de lectura
Referencia
500+ proyectos WP
Core Web Vitals

#Introducción a Apache mod_rewrite

El archivo .htaccess es una de las herramientas más poderosas en el arsenal de un administrador de WordPress. Este archivo de configuración te permite anular la configuración del servidor a nivel de directorio, dándote control granular sobre las redirecciones de URL, restricciones de acceso y optimizaciones de rendimiento.

#Qué es mod_rewrite en Apache

mod_rewrite es un módulo de Apache que proporciona un motor de reescritura basado en reglas para reescribir URLs solicitadas sobre la marcha. Es el motor detrás de los permalinks bonitos de WordPress y es esencial para las estructuras de URL amigables con el SEO.

Beneficios clave:

  • Preservación del SEO: Redirige URLs antiguas a nuevas sin perder posiciones en buscadores
  • Experiencia del usuario: Asegura que los visitantes siempre lleguen al contenido correcto
  • Seguridad: Fuerza HTTPS y bloquea solicitudes maliciosas
  • Rendimiento: Implementa cabeceras de caché y compresión

#Cuándo usar redirecciones 301 vs 302

Entender los códigos de estado HTTP es crucial para una implementación SEO adecuada:

Tipo de redirecciónCaso de usoImpacto SEO
301 PermanenteContenido movido permanentemente, cambios de dominio, migración HTTPSGoogle la usa como señal canónica y muestra la URL de destino en los resultados
302 EncontradoMantenimiento temporal, pruebas A/B, movimientos de contenido a corto plazoGooglebot la sigue, pero no es señal canónica: la URL original suele quedarse en los resultados
307 TemporalRedirección temporal estricta HTTP/1.1, preservación de datos POSTIgual que 302 pero preserva el método HTTP
308 PermanenteRedirección permanente estricta HTTP/1.1, preservación de datos POSTIgual que 301 pero preserva el método HTTP

Regla de oro: Si el cambio es permanente, siempre usa 301. Con una 302 en un cambio permanente, la URL antigua puede quedarse en los resultados en lugar de la nueva.


#Ejemplos de redirección 301 en .htaccess

#1. Redirigir una sola página

La forma más simple de redirección mueve una URL específica a otra:

# Redirigir una sola página (sintaxis simple)
Redirect 301 /página-antigua.html https://www.dominio.com/página-nueva.html

# Alternativa usando RewriteRule
RewriteEngine on
RewriteRule ^página-antigua\.html$ /página-nueva.html [R=301,L]

Cuándo usar cada una:

  • Usa Redirect 301 para coincidencias de URL exactas y simples
  • Usa RewriteRule cuando necesites coincidencia de patrones o condiciones

#2. Redirigir todo el sitio a un nuevo dominio

Mover todo tu sitio web a un nuevo dominio requiere un manejo cuidadoso:

# Redirigir sitio completo a nuevo dominio
Redirect 301 / https://www.nuevodominio.com/

# Preservar la estructura completa de URL
RewriteEngine on
RewriteBase /
RewriteRule (.*) https://www.nuevodominio.com/$1 [R=301,L]

Importante: Siempre prueba con algunas URLs primero antes de implementar redirecciones a nivel de sitio.

#3. Redirigir una subcarpeta a la raíz (o al revés)

Común al reestructurar contenido:

# Redirigir sitio completo a una subcarpeta (sin bucle en el mismo host)
RedirectMatch 301 ^/(?!subcarpeta/)(.*)$ https://www.dominio.com/subcarpeta/$1

# Redirigir subcarpeta a la raíz (con barra final, sin doble barra)
Redirect 301 /subcarpeta/ https://www.dominio.com/

# Usando RewriteRule con preservación de ruta completa
RewriteEngine on
RewriteRule ^subcarpeta/(.*)$ /$1 [R=301,L]

#4. Redirigir .html a .php y quitar extensiones

Al migrar de .html a .php o implementar permalinks bonitos:

# Redirigir .html a .php
RedirectMatch 301 (.*)\.html$ https://www.dominio.com$1.php

# Eliminar extensión .php (hacer URLs más limpias)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]

#5. Forzar HTTPS (SSL)

Esencial para seguridad y SEO:

# Forzar HTTPS - Método 1 (simple)
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Forzar HTTPS - Método 2 (con manejo de www)
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.dominio.com/$1 [L,R=301]

#6. Forzar www o sin www

La consistencia en la estructura de URL importa para el SEO:

# Forzar www
RewriteEngine on
RewriteCond %{HTTP_HOST} ^dominio.com [NC]
RewriteRule ^(.*)$ https://www.dominio.com/$1 [L,R=301]

# Forzar sin www (dominio desnudo)
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.dominio\.com [NC]
RewriteRule ^(.*)$ https://dominio.com/$1 [L,R=301]

#RewriteRule con parámetros y expresiones regulares

#Cómo redirigir URLs con parámetros de consulta

El manejo de URLs con parámetros requiere atención especial:

# Redirigir parámetro de consulta específico
RewriteEngine on
RewriteCond %{QUERY_STRING} (^|&)id=1(&|$)
RewriteRule ^index\.php$ /ruta-a-nueva-ubicación/? [R=301,L]

# Pasar el valor de un parámetro a la ruta
RewriteEngine On
RewriteCond %{QUERY_STRING} ^category=([^&]+)
RewriteRule ^index\.php$ /categoria/%1/? [R=301,L]

# Eliminar cadenas de consulta por completo
RewriteEngine On
RewriteCond %{QUERY_STRING} .
RewriteRule ^$ /? [R=301,L]

Nota: El ? final en la URL de destino elimina la cadena de consulta original. Desde Apache 2.4.0 la bandera [QSD] hace lo mismo (banderas de RewriteRule). La condición (^|&)id=1(&|$) evita que la regla capture también id=10, id=123 o pid=1.

#Coincidencia de patrones con regex en RewriteRule

Las expresiones regulares proporcionan una potente coincidencia de patrones:

# Redirigir URLs basadas en fechas
RewriteEngine On
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.+)$ /noticias/$1/$2/$3 [R=301,L]

# Redirigir con comodines
RewriteEngine On
RewriteRule ^productos/(.*)$ /tienda/$1 [R=301,L]

# Coincidencias de múltiples patrones
RewriteEngine On
RewriteRule ^(blog|noticias|artículos)/(.+)$ /contenido/$2 [R=301,L]

#Cambio de dominio con preservación de ruta

Al migrar a un dominio completamente nuevo:

# Dominio antiguo a nuevo dominio con ruta completa
RewriteEngine On
RewriteCond %{HTTP_HOST} ^dominio-antiguo.com$ [OR]
RewriteCond %{HTTP_HOST} ^www.dominio-antiguo.com$
RewriteRule (.*)$ https://www.dominio-nuevo.com/$1 [R=301,L]

# Con ajuste de subdirectorio
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/blog/(.*)$
RewriteRule ^(.*)$ https://www.nuevodominio.com/noticias/%1 [R=301,L]

#Cómo probar redirecciones antes de publicarlas

#Qué comprobar antes de publicar una redirección

  1. Usa 302 temporal primero: Prueba con redirecciones 302 antes de hacerlas permanentes
  2. Verifica cadenas de redirección: Asegúrate de no crear bucles de redirección
  3. Prueba múltiples escenarios: Verifica con y sin www, HTTP y HTTPS
  4. Válida con herramientas: Usa verificadores de redirección en línea

#Probar una redirección 301 con curl

# Usando curl para verificar cabeceras
curl -I http://tudominio.com/página-antigua

# Seguir redirecciónes con curl
curl -L http://tudominio.com/página-antigua

# Verificar códigos de estado específicos
curl -I -L http://tudominio.com/página-antigua 2>&1 | grep HTTP

#Herramientas en línea para comprobar redirecciones

  • Verificador de redirecciones y estado HTTP: httpstatus.io
  • Google Search Console: Verifica errores de rastreo después de la implementación

#Solución de problemas de bucles de redirección

#Qué causa un bucle de redirección

  1. Referencias circulares: La regla A redirige a B, la regla B redirige de vuelta a A
  2. Discrepancias de protocolo: Regla HTTP conflictuando con forzado de HTTPS
  3. Conflictos WWW: Reglas www y sin www luchando entre sí
  4. Conflictos de WordPress: Redirecciónes de plugins conflictuando con .htaccess

#Registrar mod_rewrite para encontrar el bucle

# Configuración del servidor o del virtual host (LogLevel no está permitido en .htaccess)
LogLevel alert rewrite:trace3
# Filtrar solo las entradas de mod_rewrite
tail -f error_log | fgrep '[rewrite:'

Nota: RewriteLog y RewriteLogLevel desaparecieron en Apache 2.4; ahora se usa LogLevel por módulo (mod_rewrite). La documentación advierte que los niveles por encima de trace2 ralentizan mucho el servidor: úsalos solo para depurar y quítalos después.

#Cómo detener un bucle de redirección en .htaccess

# Prevenir bucles verificando si ya fue redirigido
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]

# Manejo específico de protocolo para evitar bucles
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#Impacto en el rendimiento de las reglas .htaccess

#Cuánto cuesta .htaccess en cada petición

Según la guía de .htaccess de Apache, cuando AllowOverride permite usar .htaccess, httpd busca el archivo en cada directorio y en todos los directorios superiores en cada petición, y lo carga cada vez que se pide un documento. Para un archivo en /www/htdocs/example eso supone 4 búsquedas adicionales en el sistema de archivos. Las cadenas de redirecciones añaden además latencia para el usuario, con los límites que Google fija más abajo.

#Orden de reglas y regex para redirecciones más rápidas

  1. El orden importa: Coloca las reglas que coinciden más frecuentemente primero
  2. Usa patrones específicos: Los patrones más específicos son más rápidos
  3. Limita la complejidad del regex: Evita cuantificadores codiciosos donde sea posible
  4. Considera la configuración a nivel de servidor: Para sitios de alto tráfico, usa httpd.conf en su lugar
# Ejemplo de ordenamiento optimizado
RewriteEngine On

# Redirecciónes más comunes primero
RewriteRule ^wp-admin$ /wp-admin/ [R=301,L]

# Luego patrones específicos
RewriteRule ^producto-antiguo/(.*)$ /tienda/$1 [R=301,L]

# Patrones genéricos al final
RewriteRule ^blog/(.*)$ /noticias/$1 [R=301,L]

#Activar mod_expires y compresión

# Habilitar mod_expires para mejor caché
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 month"
</IfModule>

# Habilitar compresión
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css application/javascript
</IfModule>

#Redirección 301 en WordPress con .htaccess

#Redirecciones personalizadas antes del bloque de WordPress

WordPress usa sus propias reglas de reescritura en .htaccess. Siempre coloca las reglas personalizadas antes del bloque de WordPress:

# BEGIN Redirecciónes personalizadas
RewriteEngine On
# Tus reglas personalizadas aquí
# END Redirecciónes personalizadas

# 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

#Redirigir adjuntos, archivos de autor y de categoría

# Redirigir páginas de adjuntos a la página de inicio
RewriteEngine On
RewriteRule ^attachment/(.*)$ / [R=301,L]

# Redirigir archivos de autor a la página de inicio
RewriteEngine On
RewriteRule ^author/(.*)$ / [R=301,L]

# Redirigir archivos de categorías a una página específica
RewriteEngine On
RewriteRule ^category/categoria-antigua$ /nueva-sección/ [R=301,L]

#Proteger wp-config.php y bloquear peticiones maliciosas

#Proteger archivos sensibles de WordPress

# Bloquear acceso a archivos sensibles de WordPress
<FilesMatch "^\.">
  Require all denied
</FilesMatch>

# Proteger wp-config.php
<Files wp-config.php>
  Require all denied
</Files>

# Bloquear acceso al propio .htaccess
<Files .htaccess>
  Require all denied
</Files>

Order y Deny from son sintaxis de Apache 2.2: en 2.4 solo funcionan a través de mod_access_compat y su uso está desaconsejado (actualizar a 2.4). Require all denied es la forma actual.

#Bloquear cadenas de consulta maliciosas en .htaccess

# Bloquear intentos de inyección SQL
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ index.php [F,L]

#Sintaxis de Redirect, RedirectMatch y RewriteRule

#Sintaxis de la directiva Redirect

# Redirección 301 básica
Redirect 301 /antigua /nueva

# Redirección temporal 302
Redirect 302 /mantenimiento /página-temporal

# Redirección con URL completa
Redirect 301 /página http://ejemplo.com/nueva-página

#Sintaxis de RedirectMatch

# Redirección basada en patrones
RedirectMatch 301 ^/blog/(.*)$ http://ejemplo.com/noticias/$1

# Insensible a mayúsculas
RedirectMatch 301 (?i)^/carpeta-antigua/(.*)$ /carpeta-nueva/$1

#Sintaxis RewriteRule

# Estructura básica
RewriteRule Patrón Sustitución [Banderas]

# Banderas comunes:
# [R=301] - Redirección permanente
# [R=302] - Redirección temporal
# [L] - Última regla (detener procesamiento)
# [NC] - Sin mayúsculas (insensible a mayúsculas)
# [QSA] - Añadir cadena de consulta
# [NE] - Sin escape

#Lista de verificación de redirecciones .htaccess

Antes de implementar redirecciones:

  • Prueba las redirecciones con 302 antes de convertirlas en 301
  • Verifica que no existan bucles de redirección
  • Comprueba el comportamiento en móvil y escritorio
  • Prueba con URLs tanto con www como sin www
  • Verifica el forzado de HTTPS si aplica
  • Monitorea Google Search Console para errores de rastreo
  • Actualiza los enlaces internos para apuntar a las nuevas URLs
  • Crea una copia de seguridad de tu archivo .htaccess

Recuerda: Una estrategia de redirección bien planificada preserva tu posicionamiento SEO y asegura una experiencia de usuario fluida durante las migraciones o reestructuraciones del sitio.


#Redirecciones .htaccess en Nginx, registros y plugins

#Cómo convertir redirecciones .htaccess a Nginx

Aunque .htaccess es específico de Apache, entender cómo se traducen las reglas a NGINX es crucial para los desarrolladores que trabajan en múltiples plataformas:

Conversión de Apache (.htaccess) a NGINX:

Directiva ApacheEquivalente NGINX
Redirect 301 /antigua /nuevareturn 301 /nueva;
RewriteRule ^antigua$ /nueva [R=301,L]location = /antigua { return 301 /nueva; }
RewriteCond %{HTTPS} offif ($scheme != 'https')

Ejemplo de bloque de servidor NGINX:

server {
    listen 80;
    server_name ejemplo.com;

    # Redirección permanente a HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name ejemplo.com;

    # Reglas de reescritura de WordPress
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

#Redirecciones por idioma y detrás de balanceadores de carga

1. Redirecciónes para sitios multilingües

# Redirigir basándose en la cabecera Accept-Language
RewriteEngine On
RewriteCond %{HTTP:Accept-Language} ^de [NC]
RewriteRule ^$ /de/ [L,R=302]

RewriteCond %{HTTP:Accept-Language} ^fr [NC]
RewriteRule ^$ /fr/ [L,R=302]

Google desaconseja redirigir automáticamente según el idioma que supones del usuario, porque puede impedir que usuarios y buscadores lleguen a todas las versiones; es mejor enlazar a las demás versiones (sitios multirregionales).

2. Detección de HTTPS/HTTP para balanceadores de carga

# Manejar la cabecera X-Forwarded-Proto de balanceadores de carga
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#Depurar .htaccess con el registro de reescritura

Habilitar registro detallado de reescritura:

# Configuración del virtual host (no .htaccess), Apache 2.4+
LogLevel alert rewrite:trace3

# Registro a archivo
ErrorLog ${APACHE_LOG_DIR}/rewrite.log

Comandos comunes de depuración:

# Comprobar si mod_rewrite está cargado
apache2ctl -M | grep rewrite

# Probar la sintaxis de la configuración principal (no lee .htaccess)
apache2ctl configtest

# Activar mod_rewrite (Debian/Ubuntu)
a2enmod rewrite

# Ver registros de error de Apache
tail -f /var/log/apache2/error.log

apache2ctl configtest solo revisa la configuración principal. Apache lee .htaccess en cada petición, así que un error de sintaxis en ese archivo aparece como un error 500 al pedir una página (guía de .htaccess).

#Lista de verificación de migración para sitios grandes

Al migrar un sitio WordPress grande con miles de redirecciones:

  1. Fase de inventario

    • Exporta todas las URLs de Google Analytics
    • Rastrea el sitio existente con Screaming Frog
    • Exporta todas las páginas indexadas de Google Search Console
    • Documenta todos los errores 404
  2. Fase de planificación

    • Mapea las URLs antiguas a las nuevas
    • Agrupa las redirecciones por patrón
    • Prioriza las páginas de alto tráfico
    • Planifica las cadenas de redirección para minimizar saltos
  3. Fase de implementación

    • Prueba las redirecciones en el entorno de staging
    • Implementa en lotes
    • Monitorea los tiempos de respuesta del servidor
    • Verifica la ausencia de bucles de redirección
  4. Fase de verificación

    • Usa verificadores de redirección en línea
    • Monitorea Search Console para errores de rastreo
    • Verifica los tiempos de respuesta del servidor
    • Comprueba que Google muestra las URL nuevas en los resultados
  5. Fase de limpieza

    • Elimina las redirecciones temporales 302 (conviérte a 301)
    • Elimina reglas innecesarias
    • Documenta todas las redirecciones para referencia futura
    • Actualiza el sitemap XML con las nuevas URLs

#Alternativas con plugins de WordPress

Para usuarios no técnicos o gestión compleja de redirecciones:

Redirection

  • Gratuito, ampliamente utilizado
  • Soporta patrones regex
  • Registro de 404
  • Funcionalidad de importación/exportación

Yoast SEO Premium

  • Gestor de redirecciones integrado
  • Monitoreo automático de 404
  • Integración fluida con WordPress
  • Soporte de regex

Safe Redirect Manager

  • Plugin de WordPress.org
  • Redirecciónes basadas en lista blanca
  • Selección de código de estado HTTP
  • Compatible con multisitio

Rank Math SEO

  • Suite SEO completa
  • Redirecciónes 301/302/307
  • Monitoreo de 404
  • Importación masiva de 301

#Estructura predeterminada de .htaccess en WordPress

WordPress genera un archivo .htaccess predeterminado cuando habilitas los permalinks bonitos. Entender su estructura es crucial para añadir reglas personalizadas:

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

#Reglas .htaccess para WordPress Multisitio

WordPress Multisitio requiere configuración adicional:

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]

#Caché del navegador y compresión en .htaccess

#Cabeceras de caché del navegador

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
</IfModule>

# Compresión GZIP
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript
</IfModule>

#Redirecciones al migrar a HTTPS o a otro dominio

#Migración de HTTP a HTTPS

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

#Migración de dominio

RewriteEngine On
RewriteCond %{HTTP_HOST} ^dominio-antiguo\.com$ [NC]
RewriteRule (.*)$ https://www.dominio-nuevo.com/$1 [R=301,L]

#Cambios en la estructura de URL

RewriteEngine On
RewriteRule ^blog/([0-9]{4})/([0-9]{2})/(.+)$ /artículos/$3 [R=301,L]

#Bloquear hotlinking y forzar descargas con .htaccess

#Protección contra hotlinking

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?tudominio\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ - [F]

La condición !^$ deja pasar las peticiones sin cabecera Referer, así que no bloquea las visitas directas ni los navegadores que la suprimen. Ten en cuenta que Referer es opcional y se puede falsificar (cuándo no usar mod_rewrite).

#Forzar descarga de archivos

<FilesMatch "\.pdf$">
Header set Content-Disposition attachment
</FilesMatch>

#Cómo trata Google las redirecciones 301, 302, 307 y 308

La documentación de Google sobre redirecciones (Redirecciones y la Búsqueda de Google) las divide en dos grupos. Googlebot sigue las redirecciones permanentes (301 y 308), y el sistema de indexación las usa como señal de que el destino debe ser la URL canónica, de modo que en los resultados aparece la URL nueva. Las temporales (302, 303 y 307) también se siguen, pero no cuentan como señal canónica, así que la URL de origen suele quedarse en los resultados. Google ordena además los métodos según la fiabilidad con que puede interpretarlos: una redirección del lado del servidor, como la de .htaccess, va por delante de meta refresh y de JavaScript.

Esto afecta directamente a .htaccess, porque los dos módulos de Apache usan por defecto el código temporal. Redirect sin argumento de estado envía una 302 (mod_alias), y RewriteRule con la bandera [R] sin valor también envía una 302 (banderas de RewriteRule). Una migración escrita con [R,L] en lugar de [R=301,L] publica redirecciones temporales sin ningún mensaje de error.

Las cadenas también tienen un límite. Los rastreadores de Google siguen por defecto hasta 10 saltos de redirección (códigos de estado HTTP), y la guía de cambios de sitio pide no pasar de 3 saltos y quedarse por debajo de 5 como máximo, porque cada salto añade latencia (traslado de sitios con cambios de URL). La misma guía recomienda mantener las redirecciones de una migración el mayor tiempo posible, en general al menos un año.

#Por qué una RewriteRule con barra inicial no coincide en .htaccess

La causa más habitual de que una regla copiada de la configuración del servidor no haga nada en .htaccess es la barra inicial. En contexto de directorio (.htaccess y <Directory>), Apache quita la ruta del directorio, incluida la barra final, antes de comparar el patrón. La documentación de mod_rewrite lo dice claramente: esa cadena nunca empieza por barra, de modo que un patrón que empieza por ^/ nunca coincide en contexto de directorio.

# Configuración del virtual host: coincide con /pagina-antigua/
RewriteRule ^/pagina-antigua/$ /pagina-nueva/ [R=301,L]

# .htaccess en la raíz del documento: la misma redirección
RewriteRule ^pagina-antigua/$ /pagina-nueva/ [R=301,L]

El patrón tampoco ve el nombre del host ni la cadena de consulta. Para comprobarlos usa una RewriteCond sobre %{HTTP_HOST} o %{QUERY_STRING}, y %{REQUEST_URI} cuando necesites la ruta completa. Dos ajustes del servidor deciden si las reglas llegan a ejecutarse: la reescritura en .htaccess necesita Options FollowSymLinks o SymLinksIfOwnerMatch, y tanto RewriteRule como Redirect necesitan AllowOverride FileInfo. El tutorial de .htaccess de Apache propone una prueba rápida: escribe una palabra sin sentido, por ejemplo TestMe, en el archivo y recarga la página. Si no aparece un error 500, está activo AllowOverride None y Apache ignora el archivo.

#Diferencia entre las banderas L y END en .htaccess

En .htaccess, [L] solo termina la pasada actual por las reglas. La documentación de banderas explica que, en contexto de directorio, la petición reescrita puede volver a procesarse desde la primera regla, y eso puede provocar bucles. [END] detiene todo el procesamiento de reescritura para esa petición, y la documentación la considera la bandera preferible para la mayoría de las reglas de directorio. En la configuración del servidor o del virtual host las dos se comportan igual.

La misma página aclara tres detalles que explican muchas redirecciones rotas:

  • [R] sin [L] pasa la URL reescrita a la regla siguiente, lo que puede generar avisos Invalid URI in request en el registro; por eso conviene escribir [R=301,L].
  • Con un estado fuera del rango 300 a 399, por ejemplo [R=410], la sustitución se descarta y la URL de destino nunca se envía. [G] y [F] expresan esa intención con más claridad.
  • [QSD] (Apache 2.4.0 y posteriores) descarta la cadena de consulta, y si se combinan [QSD] y [QSA], prevalece [QSD].

#Cuándo recomienda Apache Redirect en lugar de RewriteRule

La guía del propio equipo de Apache, Cuándo no usar mod_rewrite, presenta mod_rewrite como último recurso y dice que las redirecciones simples de una URL o de un grupo de URL deben hacerse con Redirect o RedirectMatch. Redirect conserva la información de ruta, así que Redirect "/one/" "http://one.example.com/" también traslada /one/two.html. Solo coincide con segmentos de ruta completos: /service no captura /servicefoo.txt. Pasa los parámetros GET al destino, mientras que el cuerpo de las peticiones POST se descarta (mod_alias).

Para fijar un nombre de host canónico, la misma guía usa un bloque <If> en lugar de RewriteCond:

<If "req('Host') != 'www.example.com'">
    Redirect "/" "https://www.example.com/"
</If>

También señala que el patrón de controlador frontal que WordPress escribe en .htaccess (enviar a index.php todo archivo y directorio que no exista) puede expresarse como FallbackResource /index.php, que funciona también en .htaccess. En una instalación de WordPress deja intacto el bloque generado, porque WordPress reescribe todo lo que hay entre # BEGIN WordPress y # END WordPress. La regla práctica es usar un solo módulo por URL: no dejes que un Redirect y una RewriteRule coincidan con la misma ruta.

#Dónde guardar miles de redirecciones en lugar de .htaccess

Una lista larga de redirecciones en .htaccess se paga en cada petición. Según el tutorial de .htaccess, cuando se permiten estos archivos, httpd los busca en cada directorio y en todos los superiores, y vuelve a cargar el archivo cada vez que se pide un documento, incluidas las imágenes, el CSS y el JavaScript. La misma página recomienda la configuración principal del servidor siempre que tengas acceso a ella.

La respuesta de Apache para tablas grandes es RewriteMap. Solo puede declararse en la configuración del servidor o del virtual host, nunca en .htaccess (guía de RewriteMap). Un mapa de texto plano contiene una clave y un valor separados por un espacio en cada línea, y httpd guarda en caché las claves consultadas hasta que cambia la fecha de modificación del archivo. Un mapa dbm: generado con httxt2dbm está indexado, así que las búsquedas son más rápidas que en un archivo de texto:

# Configuración del virtual host, no .htaccess
RewriteEngine On
RewriteMap redirects "dbm:/etc/apache2/redirects.map"
RewriteCond "${redirects:%{REQUEST_URI}}" !=""
RewriteRule "^" "${redirects:%{REQUEST_URI}}" [R=301,L]
# redirects.txt: un par "ruta-antigua ruta-nueva" por línea
# /pagina-antigua/ /pagina-nueva/
httxt2dbm -i redirects.txt -o redirects.map

La condición omite la redirección cuando la ruta no está en el mapa, de modo que las URL sin entrada siguen hasta WordPress como siempre.


Explora nuestra optimización de velocidad WordPress para llevar tu proyecto más lejos.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Quieres implementar esto en tu sitio?

Si el problema está en los Core Web Vitals, en el rendering lento o en el peso de WordPress, puedo mapear e implementar la optimización.

Preguntas frecuentes

Respuestas prácticas para aplicar el tema en la ejecución real.

¿Cuál es la diferencia entre Redirect 301 y RewriteRule?#
Redirect 301 es una sintaxis más simple para redirecciones básicas. RewriteRule usa coincidencia de patrones con regex y es más potente para manipulaciones de URL complejas. Usa Redirect para casos simples, RewriteRule para redirecciones basadas en patrones.
¿Por qué obtengo un error de bucle de redirección?#
Los bucles de redirección ocurren cuando las reglas se referencian entre sí (A redirige a B, B redirige a A) o cuando existen discrepancias de protocolo. Verifica si hay reglas conflictivas y usa RewriteCond para prevenir bucles.
¿Las redirecciones .htaccess afectan la velocidad del sitio web?#
Impacto mínimo con pocas redirecciones. Sin embargo, el rendimiento se degrada con muchas directivas RewriteRule porque Apache las procesa secuencialmente para cada solicitud. Considera implementar redirecciones a nivel de configuración del servidor para sitios de alto tráfico.
¿Debo usar una redirección 301 o 302?#
Usa 301 para cambios permanentes (mudanzas de dominio, migración HTTPS, cambios permanentes de URL): Google la usa como señal de que la URL de destino debe ser la canónica y muestra el destino en los resultados. Usa 302 solo para situaciones temporales como mantenimiento o pruebas A/B; con una 302 la URL de origen suele quedarse en los resultados.
¿Cómo redirijo con cadenas de consulta?#
Usa RewriteCond %{QUERY_STRING} para hacer coincidir cadenas de consulta, luego RewriteRule con las banderas [R=301,L,QSD]. La bandera QSD (Query String Discard) elimina la cadena de consulta original del destino.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados