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?
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ón | Caso de uso | Impacto SEO |
|---|---|---|
| 301 Permanente | Contenido movido permanentemente, cambios de dominio, migración HTTPS | Transfiere 90-99% del valor de enlace, los motores actualizan el índice |
| 302 Encontrado | Mantenimiento temporal, pruebas A/B, movimientos de contenido a corto plazo | No transfiere valor de enlace, la URL original permanece indexada |
| 307 Temporal | Redirección temporal estricta HTTP/1.1, preservación de datos POST | Igual que 302 pero preserva el método HTTP |
| 308 Permanente | Redirección permanente estricta HTTP/1.1, preservación de datos POST | Igual que 301 pero preserva el método HTTP |
Regla de oro: Si el cambio es permanente, siempre usa 301. Usar 302 para movimientos permanentes puede dañar significativamente tu posicionamiento SEO.
Escenarios comunes de redirección
1. Redirecciones de 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 301para coincidencias de URL exactas y simples - Usa
RewriteRulecuando necesites coincidencia de patrones o condiciones
2. Redirección de sitio completo
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. Subcarpeta a raíz (o viceversa)
Común al reestructurar contenido:
# Redirigir sitio completo a una subcarpeta
Redirect 301 / https://www.dominio.com/subcarpeta/
# Redirigir subcarpeta a otro sitio
Redirect 301 /subcarpeta https://www.dominio.com/
# Usando RewriteRule con preservación de ruta completa
RewriteEngine on
RewriteRule ^subcarpeta/(.*)$ /$1 [R=301,L]
4. Cambios de extensión de archivo
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
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 ^(.*)$ http://dominio.com/$1 [L,R=301]
Reglas de reescritura avanzadas
Redirecciones con cadenas 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-ubicacion/? [R=301,L]
# Redirigir con preservación de cadena de consulta
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.
Coincidencia de patrones con Regex
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]
Prueba de redirecciones de forma segura
Antes de publicar
- Usa 302 temporal primero: Prueba con redirecciones 302 antes de hacerlas permanentes
- Verifica cadenas de redirección: Asegúrate de no crear bucles de redirección
- Prueba múltiples escenarios: Verifica con y sin www, HTTP y HTTPS
- Válida con herramientas: Usa verificadores de redirección en línea
Métodos de prueba
# Usando curl para verificar cabeceras
curl -I http://tudominio.com/página-antigua
# Seguir redirecciones 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 de prueba en línea
- Verificador de redirecciones: httpstatus.io
- 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
Causas comunes
- Referencias circulares: La regla A redirige a B, la regla B redirige de vuelta a A
- Discrepancias de protocolo: Regla HTTP conflictuando con forzado de HTTPS
- Conflictos WWW: Reglas www y sin www luchando entre sí
- Conflictos de WordPress: Redirecciones de plugins conflictuando con .htaccess
Pasos de diagnóstico
# Añade esto temporalmente para ver qué está pasando
RewriteEngine On
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3
Nota: Esto requiere acceso a nivel de servidor y debe eliminarse después de la depuración.
Soluciónes
# 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
Comprendiendo el costo
Cada RewriteRule añade sobrecarga de procesamiento:
- Redirecciones simples: Impacto mínimo (< 1ms)
- Regex complejo: Impacto moderado (1-5ms por regla)
- Múltiples condiciones: Impacto acumulativo (5-20ms+)
Mejores prácticas de optimización
- El orden importa: Coloca las reglas que coinciden más frecuentemente primero
- Usa patrones específicos: Los patrones más específicos son más rápidos
- Limita la complejidad del regex: Evita cuantificadores codiciosos donde sea posible
- 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
# Redirecciones 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]
Consideraciones de caché
# 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>
Consideraciones específicas de WordPress
Integración con las reglas de reescritura de WordPress
WordPress usa sus propias reglas de reescritura en .htaccess. Siempre coloca las reglas personalizadas antes del bloque de WordPress:
# BEGIN Redirecciones personalizadas
RewriteEngine On
# Tus reglas personalizadas aquí
# END Redirecciones 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
Escenarios comunes de redirección en WordPress
# Redirigir páginas de adjuntos a la entrada padre
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-seccion/ [R=301,L]
Consideraciones de seguridad
Protección de archivos sensibles
# Bloquear acceso a archivos sensibles de WordPress
<FilesMatch "^\.">
Order allow,deny
Deny from all
</FilesMatch>
# Proteger wp-config.php
<Files wp-config.php>
order allow,deny
deny from all
</Files>
# Bloquear acceso al propio .htaccess
<Files .htaccess>
order allow,deny
deny from all
</Files>
Bloqueo de solicitudes maliciosas
# 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]
Referencia completa: tipos de redirección
Sintaxis de redirección simple
# 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 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 resumen
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.
Técnicas avanzadas para 2026
Consideraciones de compatibilidad con 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 Apache | Equivalente NGINX |
|---|---|
Redirect 301 /antigua /nueva | return 301 /nueva; |
RewriteRule ^antigua$ /nueva [R=301,L] | location = /antigua { return 301 /nueva; } |
RewriteCond %{HTTPS} off | if ($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;
}
}
Casos especiales y escenarios avanzados
1. Redirecciones 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]
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]
Depuración y registro
Habilitar registro detallado de reescritura:
# Para Apache 2.4+
LogLevel alert rewrite:trace6
# Registro a archivo
ErrorLog ${APACHE_LOG_DIR}/rewrite.log
Comandos comunes de depuración:
# Verificar módulos de Apache
apache2ctl -M | grep rewrite
# Probar sintaxis de .htaccess
apache2ctl configtest
# Verificar si mod_rewrite está habilitado
a2enmod rewrite
# Ver registros de error de Apache
tail -f /var/log/apache2/error.log
Lista de verificación de migración para sitios grandes
Al migrar un sitio WordPress grande con miles de redirecciones:
-
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
-
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
-
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
-
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 la transferencia de valor de enlace
-
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
- Redirecciones basadas en lista blanca
- Selección de código de estado HTTP
- Compatible con multisitio
Rank Math SEO
- Suite SEO completa
- Redirecciones 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
Manejo de 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]
Optimizaciónes de rendimiento con .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>
Escenarios de migración
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]
Técnicas avanzadas
Protección contra hotlinking
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^https://(www\.)?tudominio\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ - [F]
Forzar descarga de archivos
<FilesMatch "\.pdf$">
Header set Content-Disposition attachment
</FilesMatch>
Explora nuestra optimización de velocidad WordPress para llevar tu proyecto más lejos.

