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:

  • Los map se declaran una sola vez a nivel global (http).
  • Una vez definidos, sus variables destino (ej. $skip_cache) están disponibles en todos los servidores virtuales (server {}).
  • Si intentamos definir dos map con la misma variable destino en diferentes vhosts, obtendremos un error de configuración (duplicate variable name).

Contexto: Proxy inverso con varios sitios

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

  • undominio.com → backend en 192.168.2.147
  • otrodominio.com → backend en 192.168.2.143

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

  • No cachear POST
  • No cachear peticiones con query string
  • No cachear accesos a /wp-admin/, xmlrpc.php, sitemaps, trackers (utm, gclid, fbclid, etc.)
  • No cachear ciertos scripts de terceros como Google Analytics o reCAPTCHA

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

  • Los map en Nginx son globales a todo el bloque http, no a un único server.
  • Declararlos dentro de cada vhost provoca conflictos si se repiten variables.
  • La práctica recomendada es centralizar la lógica de exclusión de caché en un archivo común (/etc/nginx/conf.d/cache-maps.conf).
  • Una vez definidos, las variables como $skip_cache se pueden reutilizar en todos los sitios, simplificando y unificando la gestión de la caché en un entorno multi-sitio.

Compartir:

Binario 0
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.