Saltar a contenido

dynamic-etag: módulo NGINX para agregar ETag a contenido dinámico

Instalación

Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:

  • RedHat Enterprise Linux 7, 8, 9 y 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 y Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-dynamic-etag
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-dynamic-etag

Habilita el módulo agregando lo siguiente en la parte superior de /etc/nginx/nginx.conf:

load_module modules/ngx_http_dynamic_etag_module.so;

Este documento describe nginx-module-dynamic-etag v0.2.3 lanzado el 18 de septiembre de 2025.


Coverity Scan Buy Me a Coffee

Este módulo NGINX potencia tu contenido dinámico con el encabezado automático ETag. Permite a los navegadores de los clientes emitir solicitudes GET condicionales a páginas dinámicas. ¡Y así ahorra ancho de banda y asegura un mejor rendimiento!

¡Advertencias primero!

Este módulo es un verdadero hack: llama a un filtro de encabezado desde un filtro de cuerpo, etc.

El autor original lo abandonó, teniendo que decir:

Nunca funcionó realmente.

Lo reescribí en gran medida para abordar fallos evidentes existentes, pero la parte clave con los buffers, que, siendo yo viejo, probablemente nunca entenderé, permanece intacta.

Para ser confiable, el módulo tiene que leer toda la respuesta y tomar un hash de ella. Leer toda la respuesta va en contra del diseño ligero de NGINX. No estoy seguro de si la parte del buffer espera toda la respuesta.

Dicho esto, las pruebas que agregué muestran que todo esto funciona.

Ten en cuenta que las solicitudes HEAD no tendrán ningún ETag devuelto, porque no tenemos datos con los que jugar, ya que NGINX correctamente descarta el cuerpo para este método de solicitud.

Considera esto como una característica o un error :-) Si eliminamos esto, entonces todas las solicitudes HEAD terminan teniendo el mismo ETag (hash en vacío), lo cual es definitivamente peor.

Por lo tanto, asegúrate de verificar los encabezados de esta manera:

curl -IL -X GET https://www.example.com/

Y no de esta manera:

curl -IL https://www.example.com/

Otra cosa digna de mención es que tiene poco o ningún sentido aplicar ETag dinámico en una página que cambia en cada recarga. Por ejemplo, descubrí que no estaba utilizando el ETag dinámico con beneficios, debido a <?= antispambot(get_option('admin_email')) ?>, en el header.php de mi tema de WordPress, ya que en esta función:

la selección es aleatoria y cambia cada vez que se llama a la función

Para verificar rápidamente si tu página está cambiando en la recarga, usa:

diff <(curl http://www.example.com") <(curl http://www.example.com")

Ahora que hemos terminado con el "ahora ya sabes" yada-yada, puedes proceder a probar esto :)

Sinopsis

http {
    server {
        location ~ \.php$ {
            dynamic_etag on;
            fastcgi_pass ...;
        }
    }
}

Directivas de configuración

dynamic_etag

  • sintaxis: dynamic_etag on|off|$var
  • predeterminado: off
  • contexto: http, server, location

Habilita o deshabilita la aplicación automática de ETag.

dynamic_etag_types

  • sintaxis: dynamic_etag_types <mime_type> [..]
  • predeterminado: text/html
  • contexto: http, server, location

Habilita la aplicación automática de ETag para los tipos MIME especificados además de text/html. El valor especial * coincide con cualquier tipo MIME. Las respuestas con el tipo MIME text/html siempre están incluidas.

dynamic_etag_strength

  • sintaxis: dynamic_etag_strength strong|weak|$var
  • predeterminado: strong
  • contexto: http, server, location

Controla si los ETags generados son fuertes o débiles. Los ETags débiles son útiles para contenido dinámico donde la igualdad semántica debe considerarse incluso si los bytes difieren (por ejemplo, marcas de tiempo, atributos aleatorios). Al usar $var, mapea a los valores strong o weak.

Nota: Estas directivas no son válidas en el contexto if. Prefiere usar $var con map para lograr un comportamiento condicional.

Ejemplo con map:

map $arg_w $etag_strength {
    default strong;
    1       weak;
}

location /example {
    dynamic_etag on;
    dynamic_etag_types text/html;
    dynamic_etag_strength $etag_strength;
    proxy_pass http://backend;
}

Consejos

Puedes usar la directiva map para habilitar condicionalmente ETag dinámico basado en URLs, por ejemplo:

map $request_uri $dyn_etag {
    default "off";
    /foo "on";
    /bar "on";
}
server { 
   ...
   location / {
       dynamic_etag $dyn_etag;
       fastcgi_pass ...
   }
}       

README del autor original

Intento de manejar ETag / If-None-Match en contenido proxied.

Planeo usar esto para poner delante de un servidor Varnish que usa mucho ESI.

Funciona de alguna manera, pero... ten en cuenta que este es mi primer intento de desarrollar un complemento de nginx, y lidiar con encabezados después de haber leído el cuerpo no fue exactamente parte del cómo hacerlo.

Cualquier comentario y/o mejora y/o bifurcación es bienvenida.

Gracias a http://github.com/kkung/nginx-static-etags/ por... la inspiración.

GitHub

Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-dynamic-etag.