Ejemplos de redirecciones útiles y comunes con mod_rewrite para Apache

por | febrero 14, 2017

El módulo mod_rewrite da una gran flexibilidad a Apache a la hora de implementar redirecciones que modifiquen el comportamiento de nuestro servidor web: bloquear IPs, forzar tráfico HTTPS para determinados contextos, etc… Vamos a hacer un repaso de las situaciones más comunes que nos podremos encontrar como administradores de sistemas y las diversas opciones que tenemos de aplicar redirecciones para alcanzar el objetivo deseado.

Como prerrequisitos necesitaremos tener cargado y activado el módulo mod_rewrite en Apache:

LoadModule rewrite_module modules/mod_rewrite.so
RewriteEngine on

También tened en cuenta que para controlar bien qué hacemos con dicho módulo necesitaremos tener claros ciertos conceptos de expresiones regulares y determinados «flags» específicos para mod_rewrite en Apache.

Se utilizarán en los ejemplos RewriteRules o Redirect cuando sea posible, teniendo en cuenta que en ocasiones es preferible aplicar un Redirect a una RewriteRule

Las reglas son aplicables a nivel de configuración global o de VirtualHost.

Redirigir de HTTP a HTTPS

Si necesitamos redirigir un determinado contexto de HTTP a HTTPS podemos hacerlo con redirect. Esto es muy útil por ejemplo para securizar paneles de administración que siempre deben ir por HTTPS, como wp-admin y wp-login.php en el caso de WordPress:

Redirect permanent /wp-admin https://www.example.com/wp-admin
Redirect permanent /wp-login.php https://www.example.com/wp-login.php

El redirect también puede llevar a un subdominio si queremos:

Redirect permanent /secure https://secure.example.com/

Si quisiéramos implementarlo con RewriteRules:

RewriteCond %{HTTPS} !=on
RewriteRule ^/?(wp-admin/|wp-login\.php) https://%{HTTP_HOST}%{REQUEST_URI}%{QUERY_STRING} [R=301,QSA,L]

La condición inicial es suficientemente explicativa, aclaraciones sobre el resto:

  • R=301 es el código HTTP de respuesta (movido permanentemente)
  • QSA respeta cualquier string que se hubiera añadido anteriormente a la URI
  • L deja de evaluar reglas posteriores

Si quisiéramos redirigir todo el tráfico de HTTP a HTTPS podemos hacerlo de la siguiente manera:

RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

O más directo con la directiva redirect:

Redirect / https://www.example.com/

Añadir contexto de aplicación

Útil cuando tenemos un servidor de aplicaciones como backend. Imaginemos que tenemos una aplicación cuyo contexto es my-app y tenemos que añadirlo en cada petición que realice el usuario si la aplicación no expande correctamente dicho contexto. Introducimos:

ServerName   example.com
...
RewriteCond %{REQUEST_URI} ^/$ [NC]
RewriteRule $ http://example.com/my-app [NC,R,L] 

Donde NC significa No Case (no tener en cuenta mayúsculas en la petición) y R es Redirección (si no especificamos código como anteriormente con R=301, se aplica 302 por defecto)

Añadir o quitar www en nuestro nombre de dominio

Si queremos forzar que siempre se muestre www en nuestro dominio:

RewriteCond %{HTTP_HOST} !^www.example.com$ [NC] 
RewriteRule .? http://www.example.com%{REQUEST_URI} [R=301,L]

Más sencillo con redirect:

Redirect permanent / http://www.example.com/

Si por el contrario queremos quitarlo:

RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

También con redirect mucho más sencillo:

Redirect permanent / http://example.com/

Redirigir un dominio a otro

Útil cuando hacemos una migración de dominio. Por ejemplo en mi caso, anteriormente tenía el dominio juliojosesanz.com que migré a elarraydejota.com

Para ello me bastó con el siguiente redirect en el VirtualHost de juliojosesanz.com:

Redirect permanent / https://www.elarraydejota.com/

Redirigiendo de esta manera todo el tráfico a mi nuevo site.

Bloqueos

También podemos utilizar mod_rewrite para bloquear determinadas IPs:

RewriteCond %{REMOTE_ADDR} ^123\.456\.789\.1 [OR]
RewriteCond %{REMOTE_ADDR} ^456\.789\.123\.2 [OR]
RewriteCond %{REMOTE_ADDR} ^789\.123\.456\.3 [OR]
RewriteRule ^(.*)$ - [F,L]

Donde F significa Forbidden.

Bloquear rangos de IPs:

RewriteCond %{REMOTE_ADDR} ^123\. [OR]
RewriteCond %{REMOTE_ADDR} ^456\.789\. [OR]
RewriteCond %{REMOTE_ADDR} ^789\.123\.456\. [OR]
RewriteRule ^(.*)$ - [F,L]

Bloquear determinadas requests:

RewriteCond %{THE_REQUEST} etc/passwd [NC,OR]
RewriteCond %{THE_REQUEST} cgi-bin [NC]
RewriteRule .* - [F,L]

Puede que no queramos que ciertos robots indexen nuestro contenido. Esto es especialmente útil para bots que no hacen caso de las indicaciones de nuestro robots.txt:

RewriteCond %{HTTP_USER_AGENT} Foobot [NC,OR]
RewriteCond %{HTTP_USER_AGENT} HTTrack [NC,OR]
RewriteCond %{HTTP_USER_AGENT} WebCopier [NC,OR]
RewriteCond %{HTTP_USER_AGENT} WebZIP [NC,OR]
RewriteCond %{HTTP_USER_AGENT} wget [NC]
RewriteRule .* - [F,L]

Para bloquear las peticiones sin User Agent especificado:

RewriteCond %{HTTP_USER_AGENT} ^-?$
RewriteRule .* - [F,L]

Redirigir a una página de mantenimiento

Si estamos realizando tareas de mantenimiento en nuestra web, podemos crear una página sencilla a la que llamaremos mantenimiento.html con el contenido que consideremos oportuno y añadir las siguientes directivas mientras dure el tiempo de mantenimiento:

RewriteCond %{DOCUMENT_ROOT}/mantenimiento.html -f
RewriteCond %{REQUEST_FILENAME} !/mantenimiento.html
RewriteRule ^.*$	/mantenimiento.html [L] 

Donde:

  • La opción -f comprueba que el fichero exista previamente
  • %{REQUEST_FILENAME} !/maintenance.html comprueba que la petición sea maintenance.html
  • En la RewriteRule tenemos ^.*$ que viene a ser lo que empiece ^ por lo que sea . una o más veces * hasta el final $ (es decir, esta expresión coincide con cualquier ocurrencia)

Conclusión

Existen por supuesto muchas otras aplicaciones de redirecciones para Apache. Las mencionadas en el artículo son de uso bastante común. La principal dificultad a la hora de construir reglas son las expresiones regulares complejas. Siempre podremos echar mano de herramientas para probarlas como Regexpal y Regexr o incluso aprender desde lo más básico si lo necesitamos.