Skip to main content
Hosting

Trucos y consejos .htaccess

Por 2 diciembre, 2016junio 16th, 2020Sin comentarios
Trucos y consejos htaccess

El archivo .htaccess, ese gran desconocido para muchos desarrolladores. Y para otros, sabiendo que existe, prefieren ni tocarlo por desconocimiento de como funciona.

Es verdad que no es imprescindible saber manejarlo para crear un web y menos si utilizas un CMS. Pero la cantidad de posibilidades que ofrece, principalmente para el SEO y la seguridad de sitio web, hace que sea vital que aprendas como funciona.

Primero, ¿como funciona?

Htaccess (Hypertext access) es un archivo compatible con servidores Apache, de configuración de directorios del servidor. Por ejemplo, redirigir a otra dirección web, personalizar páginas de error, proteger directorios o archivos con contraseña, bloquear IPs, cambiar a HTTPS, etc…
El archivo es hederitario, por lo que afecta al directorio donde se encuentra y todos los subdirectorios del mismo. Por eso, recomiendo que lo pongais en el directorio raíz.
Es importante familiarizarse con la sintaxís u asegurarse de escribir correctamente el código. Un espacio en blanco de más o un error de escritura pueden provocar un error fatal en nuestro sitio web. Por eso, también os recomiendo hacer una copia del archivo antes de hacer cambios. Para hacer comentarios utilizamos «#». Si el comentario es de varias líneas, lo ponemos al principio de cada línea:

# Este es un comentario en htaccess
# que sigue por esta segunda linea

Otras reglas de escritura en .htaccess:

[F] Forbidden (prohibido): le dice al servidor que devuelva al cliente un 403 Forbidden.
[L] Last rule (última regla): le dice al servidor que deje de hacer rewrite una vez se procese la directiva anterior.
[N] Next (siguiente): le dice a Apache que vuelva a ejecutar el rewrite hasta que todas las directivas de rewrite se hayan ejecutado.
[G] Gone (ido): le dice al servidor que entregue el mensaje de estado Gone (no longer exists).
[P] Proxy: le dice al servidor que gestione las peticiones mediante mod_proxy
[C] Chain (cadena): le dice al servidor que encadene la regla actual con la anterior.
[R] Redirect (redirigir): le dice a Apache que lance una redirección, haciendo que el navegador muestre la URL re-escrita/modificada.
[NC] No Case: define cualquier argumento al que esté asociado como no afectado por mayúsculas-minúsculas, o sea, como case-insensitive, “NC” = “No Case”.
[PT] Pass Through (pasar a través): le dice a mod_rewrite que pase la URL re-escrita de nuevo a Apache para que la procese de nuevo.
[OR] Or (o): especifica una lógica “o” que enlaza dos expresiones para que si una u otra se cumple se aplique la regla asociada a la misma.
[NE] No Escape: le dice al servidor que redistribuya la salida sin escapar caracteres.
[NS] No Subrequest (sin petición subyacente): le dice al servidor que se salte la directiva si hay peticiones internas subyacentes.
[QSA] Append Query String: insta al servidor a que añada una cadena de petición al final de la expresión (URL).
[S=x] Skip (saltar): le dice al servidor que se salte las siguientes “x” reglas si encuentra alguna coincidencia..
[E=variable:value] Environmental Variable (variable del entorno): le dice al servidor que establezca la variable del entorno (“variable”) al valor definido (“value”).
[T=MIME-type] Mime Type: declara el tipo mime del recurso al que está dirigido.
[] Especifica una clase de carácter, por el que cualquier carácter dentro de los corchetes se considerará una coincidencia, por ejemplo en [xyz], con x, y o z.
[]+ Clase de carácter en el que cualquier combinación de elementos dentro de los corchetes se considera una coincidencia; por ejemplo [zyz]+ considerará una coincidencia cualquier número de equis, y griegas o zetas, o cualquier combinación de estos caracteres.
[^] Especifica que no está dentro de una clase de carácter; por ejemplo, [^xyz] considerará una coincidencia cualquier carácter que no sea ni x, ni y, ni z.
[a-z] Un guión (-) entre dos caracteres dentro de corchetes ([]) define un rango de caracteres; por ejemplo [a-zA-Z] se refiere a todas las letras en mayúsculas y minúsculas de la a a la z.
a{n} Especifica un número exacto (n) del carácter precedente; por ejemplo x{3} se refiere exactamente a tres x.
a{n,} Especifica un número no o más del carácter precedente; por ejemplo x{3,} se refiere a tres x o más.
a{n,m} Especifica un rango de números, entre n y m, del carácter precedente; por ejemplo x{3,7} se refiere a tres, cuatro, cinco, seis o siete x.
() Se utiliza para agrupar juntos un grupo de caracteres, considerándolos como una sola unidad; por ejemplo (ayuda)?wordpress se referirá a wordpress, ya sea con o sin el prefijo ayuda.
^ Indica el comienzo de una cadena de prueba de una expresión regular (regex); por ejemplo, empezar el argumento con el carácter anterior.
$ Indica el fin de una cadena de prueba de una expresión regular; por ejemplo, terminar el argumento con el carácter anterior.
? Declara opcional el carácter precedente; por ejemplo cachopo? valdrá para cachopo y cachopos, mientras que cachopo(s)? se referirá tanto a cachopo como a cachopos; por ejemplo x? se refiere a ninguna o una x.
! Declara negación; ejemplo “!cadena” valdrá para todo menos para “cadena”.
. Un punto (o periodo) indica cualquier carácter arbitrario simple.
Indica que “no se” haga rewrite de la URL, como en “…dominio.es.* – [F]”.
+ Se refiere a uno o más caracteres del carácter precedente; por ejemplo, G+ se refiere a una o más Gs, mientras que simplemente “+” vale para uno o varios caracteres de cualquier tipo.
* Se refiere a cero o más de los caracteres precedentes; por ejemplo, puedes usar “.*” como comodín.
| Declara un operador lógico “or”; por ejemplo, (x|y) vale para x o y.
\ Escapa caracteres especiales ( ^ $ ! . * | ); por ejemplo, usa “\.” para indicar/escapar un punto literalmente.
\. Indica un punto literal (escapado).
/* Cero o más barras.
.* Cero o más caracteres arbitrarios.
^$ Define una cadena vacía.
^.*$ El patrón estándar para que valga cualquier cadena.
[^/.] Define un carácter que no es ni una barra ni un punto.
[^/.]+ Define cualquiera números o caracteres que no contengan ni barra ni punto.
http:// Esta es una declaración literal — en este caso la cadena de caracteres literal “http://”.
^domain.* Define una cadena que comienza con el término “domain”, probablemente precedido por cualquier número de caracteres.
^domain\.com$ Define la cadena exacta “domain.com”.
-d Comprueba si la cadena es un directorio existente.
-f Comprueba si la cadena es un archivo existente.
-s Comprueba si el archivo de la cadena contiene un valor que no sea cero.

Después de esto, os dejo algunos de los trucos más utilizados en htaccess. Simplemente copiad el código y sustituir las url por las de vuestro sitio web. Para que estas directrices funcionen tu servidor tiene que tener instalado el mod_rewrite. Lo podemos comprobar en el archivo httpd.config, aunque no debe preocuparnos ya que viene instalado por defecto en la mayoría de servidores Apache.

Cambiar página establecida por defecto

Cuando un usuario carga nuestro sitio web poniendo el dominio, los servidores intentan cargar una página por defecto. Esto podría bastar si la nombraramos index (index.html, index.php, etc…)
Pero también podemos forzar a que cargue otra página con otro nombre. Por ejemplo, inicio.html. Además podemos poner varias opciones porque como dije antes, estas directrices son hederitarias y afectan a todos los directorios. Solo hace falta poner esta linea:

DirectoryIndex inicio.html

Forzar urls con www

Tal vez nos interese que Google no trate nuestra web con www y sin www como páginas diferentes y reparta importancia entre ambas. Para eso forzamos una de las dos opciones. Cambiamos la dirección web por la nuestra:

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

Forzar urls sin www

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

Páginas de error personalizadas

Todos conocemos las clásicas páginas de error de servidor como el error 404 (Página no encontrada), pero la que viene por defecto es muy pobre y muy cutre. Podemos hacer una propia personalizada e indicarle al servidor que rediriga a nuestra página cuando de dicho error:

ErrorDocument 400 /directorio/error-400.html
ErrorDocument 401 /directorio/error-401.html
ErrorDocument 403 /directorio/error-403.html
ErrorDocument 404 /directorio/error-404.html
ErrorDocument 500 /directorio/error-500.html

Redireccionamientos 301

Imagínate que tenemos una página muy visitada pero queremos borrarla, sustituirla o cambiar la url. Sino queremos causar un problema a los usuarios que tuvieran guardada la dirección antigua, podemos utilizar Redirect 301 poniendo la url antigua y a la cual queremos redirigir:

Redirect 301 /pagina_antigua.html http://www.midominio.com/nueva_pagina.html
Redirect 301 /pagina_antigua_2.html http://www.midominio.com/directorio/

Si queremos redireccionar todo el sitio:

Redirect 301 / http://nuevo-dominio.com/

Bloquear por IPs

Podemos bloquear el acceso a nuestro sitio por completo. Si por ejemplo lo estamos construyendo, lo hacemos desaparecer de internet:

Deny from all

# O podemos bloquearlo parcialmente. Solo para ciertas IPs. Sustituye "xxx.xxx.xxx.xxx" por la IP correspondiente

Order deny, allow
Allow from All
Deny from XXX.XXX.XXX.XXX
Deny from XXX.XXX.XXX.XXX

# O bloquearlo para todos menos para ciertas IPs:

Order deny, allow
Deny from All
Allow from XXX.XXX.XXX.XXX

Proteger archivos y directorios con contraseña

Para ello necesitamos crear un archivo llamado.htpasswd y guardarlo en algún subdirectorio para uso privado. Declaramos el usuario en este archivo:

$ htpasswd -c /home/privado/.htpasswd nombre_usuario

Y ahora con .htaccess declaramos que archivos o directorios queremos proteger:

AuthName "Zona Protegida"
AuthType Basic
AuthUserFile /home/privado/.htpasswd
 
<Files "archivo-protegido.pdf">
Require valid-user
</Files>

Denegar acceso a archivos comprometidos

Puede que tengamos archivos delicados que guarden contraseñas o manejen directrices importantes de la web como .htaccess o .htpasswd. Si queremos que no caiga en malas manos ponemos el siguiente código:

<FilesMatch $^*(.)^ini|log|htpasswd|htaccess>
    Order allow,deny
    Deny from all
    Satisfy All
</FilesMatch>

Habilitar compresión deflate o Gzip

# Compresión deflate por tipo de archivo
<IfModule mod_deflate.c>
 AddOutputFilterByType DEFLATE text/plain
 AddOutputFilterByType DEFLATE text/html
 AddOutputFilterByType DEFLATE text/xml
 AddOutputFilterByType DEFLATE text/css
 AddOutputFilterByType DEFLATE text/javascript
 AddOutputFilterByType DEFLATE application/xml
 AddOutputFilterByType DEFLATE application/xhtml+xml
 AddOutputFilterByType DEFLATE application/rss+xml
 AddOutputFilterByType DEFLATE application/atom_xml
 AddOutputFilterByType DEFLATE application/javascript
 AddOutputFilterByType DEFLATE application/x-javascript
 AddOutputFilterByType DEFLATE application/x-shockwave-flash
</IfModule>

#Compresión por Gzip
<IfModule mod_gzip.c>
 mod_gzip_on Yes
 mod_gzip_dechunk Yes
 mod_gzip_item_include file\.(html?|txt|css|js|php|pl)$
 mod_gzip_item_include handler^cgi-script$
 mod_gzip_item_include mime^text/.*
 mod_gzip_item_include mime^application/x-javascript.*
 mod_gzip_item_exclude mime^image/.*
 mod_gzip_item_exclude rspheader^Content-Encoding:.*gzip.*
</IfModule>

Activar cabecera Expires HTTP

Con la cabecera HTTP Expires podemos limitar el tiempo en cada tipo de archivo en el que el navegador tira de la caché y vuelve a descargarlo del servidor. Es importante diferenciar entre archivos más estáticos (CSS, JS, imágenes, etc…), que tienen menos actualizaciones y archivos más dinámicos como HTML o PHP:

<IfModule mod_expires.c>
    ExpiresActive on
    ExpiresDefault                                      "access plus 1 month"
 
  # CSS
    ExpiresByType text/css                              "access plus 1 year"
 
  # Archivos relacionados con AJAX y Web Sockets
    ExpiresByType application/json                      "access plus 0 seconds"
    ExpiresByType application/xml                       "access plus 0 seconds"
    ExpiresByType text/xml                              "access plus 0 seconds"
 
  # Favicon
    ExpiresByType image/x-icon                          "access plus 1 week"
 
  # Componentes HTML (HTCs)
    ExpiresByType text/x-component                      "access plus 1 month"
 
  # HTML
    ExpiresByType text/html                             "access plus 0 seconds"
 
  # JavaScript
    ExpiresByType application/javascript                "access plus 1 year"
 
  # Manifest
    ExpiresByType application/x-web-app-manifest+json   "access plus 0 seconds"
    ExpiresByType text/cache-manifest                   "access plus 0 seconds"
 
  # Fotos, vídeos y audio
    ExpiresByType audio/ogg                             "access plus 1 month"
    ExpiresByType image/gif                             "access plus 1 month"
    ExpiresByType image/jpeg                            "access plus 1 month"
    ExpiresByType image/png                             "access plus 1 month"
    ExpiresByType video/mp4                             "access plus 1 month"
    ExpiresByType video/ogg                             "access plus 1 month"
    ExpiresByType video/webm                            "access plus 1 month"
 
  # Canales RSS y Atom
    ExpiresByType application/atom+xml                  "access plus 1 hour"
    ExpiresByType application/rss+xml                   "access plus 1 hour"
 
  # Fuentes web
    ExpiresByType application/font-woff                 "access plus 1 month"
    ExpiresByType application/vnd.ms-fontobject         "access plus 1 month"
    ExpiresByType application/x-font-ttf                "access plus 1 month"
    ExpiresByType font/opentype                         "access plus 1 month"
    ExpiresByType image/svg+xml                         "access plus 1 month"
</IfModule>

Desactivar cabecera ETag HTTP

Recomiendo desactivar esta cabecera ya que algunos navegadores o proxys pueden ignorarla. Y así forzamos el uso de cabeceras «Cache-control» o «Expires» citado anteriormente:

<IfModule mod_headers.c>
 Header unset ETag
</IfModule>
FileETag None

Forzar descarga de archivos en vez de mostrarlos

Tan solo tenemos que sustituir «.pdf» por la extensión que queramos para que esos archivos se descarguen automáticamente:

<Files *.pdf>
 ForceType application/octet-stream
 Header set Content-Disposition attachment
</Files>

Forzar uso de codificación UTF-8

# Forzar la codificación UTF-8 para html y texto plano
AddDefaultCharset utf-8
 
# Forzar la codificación UTF-8 otros tipos de archivos
AddCharset utf-8 .css .js .json .rss .xml

Eliminar extensiones html en las urls

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]

Evitar listado del contenido de un directorio

Options All -Indexes

Evitar hotlinking

El hotlink es el mal uso de nuestra web por algunos usuarios que enlazan imágenes o videos nuestros en sus webs utilizando nuestro ancho de banda. Con este código podemos evitarlo y mostrar una imagen de aviso:

# Evitar el hotlinking y mostrar imagen alternativa
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?midominio\.es/.*$ [NC]
RewriteRule .*\.(gif|jpg)$ http://www.midominio.es/norobeshombre.jpg [R,NC,L]
</IfModule>

Normalmente en un servidor Apache ya viene por defecto el archivo htaccess que podemos manipular. Sino, podemos crearlo con un block de notas mismamente y nombrandolo .htaccess (sin la extensión .txt).

Jairo Calero

Jairo Calero

Desarrollador web frontend y backend, especialista en webs app desarrolladas en PHP y Javascript. Experto en HTML, CSS3, PHP y Javascript con frameworks y librerías como jQuery, Angular y Bootstrap. Gestor de herramientas SEO como Google Analytics, Search Console, SEMrush o Hotjar. Email marketing y Big data.

Deja tu respuesta