Icono del sitio Binario 0

Gestión de exclusiones de caché en Nginx con map en un proxy inverso multi-sitio

Artículos Guías Manuales Sistemas Linux Windows Redes MySql Binario 0 Binario Cero

Artículos Guías Manuales Sistemas Linux Windows Redes MySql Binario 0 Binario Cero

Cuando gestionamos un servidor Nginx que actúa como proxy inverso para varios sitios web y backends, es habitual implementar reglas de caché para mejorar el rendimiento. Sin embargo, no todas las peticiones deben ser cacheadas: hay URIs sensibles, peticiones POST, parámetros de tracking o recursos dinámicos que deben excluirse.

En Nginx, estas condiciones suelen gestionarse con la directiva map. Es fundamental entender que los map declarados en la configuración de Nginx tienen un alcance global dentro del bloque http { ... }. Esto significa que:

Contexto: Proxy inverso con varios sitios

Imaginemos que tenemos un Nginx con varios sitios configurados en /etc/nginx/sites-enabled/, por ejemplo:

Cada sitio puede tener políticas de caché, pero la lógica de qué debe o no debe cachearse se repite:

En lugar de duplicar esta lógica en cada sitio, lo ideal es centralizar los map en un único archivo.

Declaración de los map globales

Creamos el archivo /etc/nginx/conf.d/cache-maps.conf con el siguiente contenido:

# /etc/nginx/conf.d/cache-maps.conf
# Reglas globales para exclusión de caché

# 1. Detectar si la petición es POST
map $request_method $is_post {
    POST    1;
    default 0;
}

# 2. Detectar si hay query string
map $query_string $has_query_string {
    ""      0;
    default 1;
}

# 3. Detectar URIs sensibles (WordPress admin, xmlrpc, sitemaps, trackers…)
map $request_uri $is_sensitive_uri {
    ~*/wp-admin/|xmlrpc.php|wp-.*\.php|index.php|.*sitemap.*\.(xml|xsl|hmtl)|.*_ga.*|.*utm.*|.*gclid.*|.*fbclid.*|.*gdpr.*  1;
    default 0;
}

# 4. Detectar scripts que nunca deben cachearse (reCAPTCHA, GA, GTM…)
map $request_uri $is_excluded_js {
    ~*^/recaptcha/api\.js(\?.*)?$|^/analytics\.js(\?.*)?$|^/gtag/js$|^/gtm\.js(\?.*)?$|^/tag/js/gpt\.js(\?.*)?$|^/dist/scripts/main\.js(\?.*)?$|^/assets/js/gdpr_cc_addon\.js(\?.*)?$|^/gdpr-cookie-compliance/dist/scripts/main\.js(\?.*)?$  1;
    default 0;
}

# 5. Variable final: si cualquiera de las condiciones anteriores se cumple, saltar caché
map "$is_post$has_query_string$is_sensitive_uri$is_excluded_js" $skip_cache {
    ~*1     1;
    default 0;
}

Este archivo se incluye automáticamente porque la directiva por defecto en /etc/nginx/nginx.conf suele tener:

http {
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Uso de $skip_cache en cada vhost

Ahora, dentro de cada sitio en /etc/nginx/sites-enabled/, podemos usar directamente la variable $skip_cache sin necesidad de volver a declarar los map.

Ejemplo para undominio.com:

server {
    listen 443 ssl; 
    http2 on;
    server_name undomino.com www.undomino.com;

    ssl_certificate     /etc/letsencrypt/live/undomino.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/undomino.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    access_log /var/log/nginx/access_undomino.log;

    location / {
        proxy_pass https://192.168.2.147:443;
        include proxy_params;

        proxy_cache undomino;
        proxy_cache_key "$scheme$host$request_uri";
        proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;

        proxy_cache_bypass $skip_cache;
        proxy_no_cache    $skip_cache;

        proxy_cache_valid 200 4h;
        proxy_cache_revalidate on;
        proxy_cache_background_update on;
        proxy_cache_min_uses 1;

        add_header X-Skip-Cache   $skip_cache;
        add_header X-Cache-Status $upstream_cache_status;
    }
}

El backend recibirá normalmente todas las peticiones, pero Nginx sólo cacheará aquellas que no cumplan las condiciones de exclusión.

Validación y pruebas

  1. Validar configuración: sudo nginx -t
  2. Recargar servicio: sudo systemctl reload nginx
  3. Probar peticiones:
    • curl -I https://undomino.com/ → debería devolver X-Skip-Cache: 0 (cacheable).
    • curl -I https://undomino.com/?utm_source=test → debería devolver X-Skip-Cache: 1 (no cacheable).
    • curl -I -X POST https://undomino.com/ → también X-Skip-Cache: 1.

Conclusiones

Salir de la versión móvil