Configurando un .htaccess perfecto

htaccess perfecto

Configurando un .htaccess perfecto

En realidad el título de este post lleva un poco de Clickbait (dicho de otro modo, ciberanzuelo) ya que probablemente no haya un archivo .htaccess perfecto. La realidad es que cada proyecto debería tener un archivo .htaccess personalizado exactamente según sus necesidades.
Aun así, sí que hay una serie de indicaciones interesantes a tener en cuenta para incluir dentro de nuestro .htaccess en el momento de la configuración inicial de nuestro WordPress.

Antes de empezar a remover el htaccess, es muy importante hacer una copia de seguridad de como lo tenemos funcionando. Por este motivo, aquí os dejamos el código del htaccess nativo por defecto de un WordPress funcionando sobre Apache con las URL amigables activadas:

.htaccess por defecto de WordPress

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

Hay que tener en cuenta que el mismo WordPress modifica el archivo htaccess para ajustarlo al funcionamiento que necesita según la arquitectura de la máquina y si (por ejemplo) está funcionando sobre Nginx, puede variar.

Habilitar la compresión GZip

Es importante habilitar la compresión gzip los recursos a descargar el fin de reducir el tiempo de carga de la página y mejorar métricas de WPO (Web Performance Optimitzation):

# BEGIN Compresión GZip
<IfModule mod_deflate.c>
    # Forzar compresión de cabeceras.
    <IfModule mod_setenvif.c>
        <IfModule mod_headers.c>
            SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
            RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
        </IfModule>
    </IfModule>
 
    <IfModule mod_filter.c>
       AddOutputFilterByType DEFLATE text/plain
       AddOutputFilterByType DEFLATE text/html
       AddOutputFilterByType DEFLATE text/xml
       AddOutputFilterByType DEFLATE text/css
       AddOutputFilterByType DEFLATE text/x-component
       AddOutputFilterByType DEFLATE application/xml
       AddOutputFilterByType DEFLATE application/xhtml+xml
       AddOutputFilterByType DEFLATE application/rss+xml
       AddOutputFilterByType DEFLATE application/javascript
       AddOutputFilterByType DEFLATE application/x-javascript
       AddType x-font/otf .otf
       AddType x-font/ttf .ttf
       AddType x-font/eot .eot
       AddType x-font/woff .woff
       AddType image/x-icon .ico
       AddType image/png .png
    </IfModule>
</IfModule>
# END Compresión GZIP

Configurar la expiración de la memoria caché

Es importante habilitar y especificar la expiración de la memoria del navegador para acelerar la carga de segundas visitas. Los servidores web bien optimizados ya lo deberían tener especificado por defecto, pero no está de más controlarlo desde nuestro htaccess:

# BEGIN Expiración de memoria cache
<IfModule mod_expires.c>
ExpiresActive On
# No generar nunca cache de textos ni datos dinámicos:
ExpiresByType text/html "access 0 seconds"
ExpiresByType text/xml "access 0 seconds"
ExpiresByType application/xml "access 0 seconds"
ExpiresByType application/json "access 0 seconds"
ExpiresByType application/ld+json "access 0 seconds"
ExpiresByType application/vnd.geo+json "access 0 seconds"

# Expiración de cache de imágenes, vídeos, componentes, fuentes, JS y CSS a 1 mes:
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType video/ogg "access 1 month"
ExpiresByType audio/ogg "access 1 month"
ExpiresByType video/mp4 "access 1 month"
ExpiresByType video/webm "access 1 month"
ExpiresByType text/css "access 1 month"
ExpiresByType text/plain "access 1 month"
ExpiresByType text/javascript "access 1 month"
ExpiresByType text/x-component "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresByType application/font-woff "access 1 month"
ExpiresByType application/font-woff2 "access 1 month"
ExpiresByType application/x-font-woff "access 1 month"
ExpiresByType application/x-font-ttf "access 1 month"
ExpiresByType font/opentype "access 1 month"
ExpiresByType image/svg+xml "access 1 month"
ExpiresByType application/vnd.ms-fontobject "access 1 month"

# Expiración por defecto de la cache no especificada a 2 días:
ExpiresDefault "access 2 days"
</IfModule>
# END Expiración de memoria cache

Seguridad desde .htaccess

Por último, siempre es importante tener en cuenta la seguridad y por ello nosotros siempre utilizamos las siguientes normas desde el .htaccess que evitan las peticiones de URL más comunes en ataques a WordPress:

# BEGIN Seguridad
# Protección del propio archivo .htaccess
<Files ~ "^.*\.([Hh][Tt][Aa])">
  order allow,deny
  deny from all
  satisfy all
</Files>

# Desactivar la navegación por directorios
Options All -Indexes
 
# Desactivar la firma del servidor
ServerSignature Off
 
### Seguridad contra Injections ###
# sacar acceso a proc/self/environ
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
# bloquear cualquier script que quiera cambiar un valor mosConfig a través d'una URL
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR] 
# bloquear cualquier script que intente inyectar código codificado en base64_encode a través de una URL
RewriteCond %{QUERY_STRING} base64_encode.*(.*) [OR] 
# bloquear cualquier script que incluya el tag <script> en la URL
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
# bloquear cualquier script que intente establecer la variable PHP GLOBALS a través de una URL
RewriteCond %{QUERY_STRING} GLOBALS(=|[|\%[0-9A-Z]{0,2}) [OR]
# bloquear cualquier script que intente modificar una variable _REQUEST a través de una URL
RewriteCond %{QUERY_STRING} _REQUEST(=|[|\%[0-9A-Z]{0,2})
 
# Enviar a todas las peticiones bloqueadas a la página principal con un error de 403 Prohibido
RewriteRule ^(.*)$ index.php [F,L]
# END Seguridad

Muestra de cómo queda nuestro .htacces perfecto

Aquí os dejamos todos los códigos recopilados a punto de hacer “copy/paste” y vemos cómo queda nuestro archivo .htaccess:

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

# BEGIN Compresión GZip
<IfModule mod_deflate.c>
    # Forzar compresión de cabeceras.
    <IfModule mod_setenvif.c>
        <IfModule mod_headers.c>
            SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
            RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
        </IfModule>
    </IfModule>
 
    <IfModule mod_filter.c>
       AddOutputFilterByType DEFLATE text/plain
       AddOutputFilterByType DEFLATE text/html
       AddOutputFilterByType DEFLATE text/xml
       AddOutputFilterByType DEFLATE text/css
       AddOutputFilterByType DEFLATE text/x-component
       AddOutputFilterByType DEFLATE application/xml
       AddOutputFilterByType DEFLATE application/xhtml+xml
       AddOutputFilterByType DEFLATE application/rss+xml
       AddOutputFilterByType DEFLATE application/javascript
       AddOutputFilterByType DEFLATE application/x-javascript
       AddType x-font/otf .otf
       AddType x-font/ttf .ttf
       AddType x-font/eot .eot
       AddType x-font/woff .woff
       AddType image/x-icon .ico
       AddType image/png .png
    </IfModule>
</IfModule>
# END Compresión GZIP

# BEGIN Expiración de memoria cache
<IfModule mod_expires.c>
ExpiresActive On
# No generar nunca cache de textos ni datos dinámicos:
ExpiresByType text/html "access 0 seconds"
ExpiresByType text/xml "access 0 seconds"
ExpiresByType application/xml "access 0 seconds"
ExpiresByType application/json "access 0 seconds"
ExpiresByType application/ld+json "access 0 seconds"
ExpiresByType application/vnd.geo+json "access 0 seconds"

# Expiración de cache de imágenes, vídeos, componentes, fuentes, JS y CSS a 1 mes:
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType video/ogg "access 1 month"
ExpiresByType audio/ogg "access 1 month"
ExpiresByType video/mp4 "access 1 month"
ExpiresByType video/webm "access 1 month"
ExpiresByType text/css "access 1 month"
ExpiresByType text/plain "access 1 month"
ExpiresByType text/javascript "access 1 month"
ExpiresByType text/x-component "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresByType application/font-woff "access 1 month"
ExpiresByType application/font-woff2 "access 1 month"
ExpiresByType application/x-font-woff "access 1 month"
ExpiresByType application/x-font-ttf "access 1 month"
ExpiresByType font/opentype "access 1 month"
ExpiresByType image/svg+xml "access 1 month"
ExpiresByType application/vnd.ms-fontobject "access 1 month"

# Expiración por defecto de la cache no especificada a 2 días:
ExpiresDefault "access 2 days"
</IfModule>
# END Expiración de memoria cache

# BEGIN Seguridad
# Protección del propio archivo .htaccess
<Files ~ "^.*\.([Hh][Tt][Aa])">
  order allow,deny
  deny from all
  satisfy all
</Files>

# Desactivar la navegación por directorios
Options All -Indexes
 
# Desactivar la firma del servidor
ServerSignature Off
 
### Seguridad contra Injections ###
# sacar acceso a proc/self/environ
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
# bloquear cualquier script que quiera cambiar un valor mosConfig a través de una URL
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR] 
# bloquear cualquier script que intente inyectar código codificado en base64_encode a través de una URL
RewriteCond %{QUERY_STRING} base64_encode.*(.*) [OR] 
# bloquear cualquier script que incluya el tag <script> en la URL
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
# bloquear cualquier script que intente establecer la variable PHP GLOBALS a través de una URL
RewriteCond %{QUERY_STRING} GLOBALS(=|[|\%[0-9A-Z]{0,2}) [OR]
# bloquear cualquier script que intente modificar una variable _REQUEST a través de una URL
RewriteCond %{QUERY_STRING} _REQUEST(=|[|\%[0-9A-Z]{0,2})
 
# Enviar a todas las peticiones bloqueadas a la página principal con un error de 403 Prohibido
RewriteRule ^(.*)$ index.php [F,L]
# END Seguridad

Cómo editar un archivo .htaccess

Para editar un archivo .htaccess podéis utilizar cualquier editor de texto de forma local o utilizando algún software de conexión remota para FTP. Pero también lo podéis hacer de forma más práctica utilizando la herramienta “Editor de ficheros” del Plugin Yoast desde donde también podéis generar y editar el archivo robots.txt pero eso se merece todo un otro post entero.

¿Utilizáis otras directrices en vuestros .htaccess?
Nos las podéis dejar en comentarios con la explicación del por qué y quizá podemos ampliar este post. ☺️

No Comments

Post A Comment