nginx

Configuración de nginx que manda a los bots a Jazui con un proxy interno.

Markdown

nginx decide con dos map si la petición es de un bot y si es un archivo estático. Las de bots se reescriben a una ubicación interna que hace de proxy hacia https://api.jazui.com/Render; si Jazui falla, se sirve tu index.html.

Antes de empezar

  • nginx con soporte SSL para el proxy (el habitual).
  • Tu sitio verificado antes de activar la configuración: con nginx, el 403 de un sitio sin verificar llega al bot.
  • Tu token.

Instalación

Este es el archivo completo. Los dos map van en el bloque http (por ejemplo en /etc/nginx/conf.d/jazui.conf) y el server sustituye o se integra en el de tu sitio:

jazui.confDescargar
# Jazui para nginx: los bots reciben el HTML renderizado de la SPA; el resto de visitas, la SPA normal.
# Sustituye [JAZUI_TOKEN] por el token de render (Sitios web → Token del sitio) y adapta server_name y root.
# Si Jazui no responde, se pasa del límite o falla, se sirve la SPA (el bot nunca ve el error).

# Bots (bots.txt; las listas las rellena Sync-Integrations.ps1)
map $http_user_agent $jazui_bot {
    default 0;
    # BOTS:BEGIN
    "~*(googlebot|google-inspectiontool|storebot-google|adsbot-google|bingbot|bingpreview|msnbot|adidxbot|yandex|baiduspider|duckduckbot|slurp|applebot|seznambot|qwantbot|qwantify|petalbot|sogou|naver|exabot|yetibot|360spider|soso|gptbot|chatgpt|oai-searchbot|claudebot|claude-user|claude-searchbot|anthropic-ai|perplexity|google-cloudvertexbot|bytespider|ccbot|amazonbot|meta-externalagent|cohere-ai|mistralai-user|youbot|duckassistbot|yibot|qwenbot|tongyibot|erniebot|yiyanbot|doubaobot|tiktokspider|deepseekbot|pangubot|manus-user|kimi-agent|kimi-searchbot|kimi-user|kimibot|moonshotbot|hunyuan|chatglm-spider|agi agent|ai2bot|ai2bot-deepresearcheval|ai2bot-dolma|aihitbot|amazon-kendra|amazon-qbusiness|amazonbuyforme|amzn-searchbot|amzn-user|bedrockbot|novaact|andibot|claude-web|apifybot|apifywebsitecontentcrawler|atlassian-bot|awario|bigsur\.ai|brightbot|buddybot|cartai agentic commerce|terracotta|cledarabot|cloudflare-autorag|cloudflarebrowserrenderingcrawler|cohere-training-data-crawler|cragcrawler|crawlspace|datenbank crawler|diffbot|diffbot-user|anomura|echobot bot|echoboxbot|elevenlabsbot|elevenlabscrawler|exasearchbot|exauser|factset_spyderbot|firecrawlagent|geisthaus-pagefetcher|cloudvertexbot|gemini-deep-research|google-agent|google-firebase|google-notebooklm|googleagent-mariner|googleagent-urlcontext|googleother|googleother-image|googleother-video|notebooklm|iaskbot|iaskspider|imagesiftbot|img2dataset|isscyberriskcrawler|kagi-fetcher|keenablebot|klaviyoaibot|laiondownloader|linguee bot|linkupbot|aiwebindex|meta-externalfetcher|meta-webindexer|facebookbot|azureai-searchbot|mistralai-index|mistralai-training|mozilla-tabstack|nagetbot|netestate imprint crawler|icc-crawler|oai-adsbot|panscient|panscient\.com|shapbot|payhawk invoice fetching agent|phindbot|poggio-citations|poseidon research crawler|qualifiedbot|wpbot|querit-searchbot|queritbot|quillbot|quillbot\.com|reflectionbot|cotoyogi|sbintuitionsbot|scrybot|sidetrade indexer bot|tavilybot|agenttimes|thinkbot|timpibot|twinagent|velenpublicwebcrawler|wardbot|omgili|omgilibot|grok bot|grokappandroid|grokbot|addsearchbot|agentdatabot|aranet-searchbot|bixelbot|bravebot|channel3bot|friendlycrawler|henkbot|imagespider|kangaroo bot|kunatocrawler|laion-huggingface-processor|linerbot|mycentralaiscraperbot|terra cotta|wrtnbot|zanistabot|facebookexternalhit|facebot|twitterbot|linkedinbot|slackbot|whatsapp|telegrambot|discordbot|pinterest|redditbot|skypeuripreview|embedly|quora link preview|showyoubot|outbrain|developers\.google\.com\/\+\/web\/snippet|vkshare|tumblr|bitlybot|nuzzel|flipboard|snapchat|viber|mattermost|bitrix link preview|xing-contenttabreceiver|ahrefsbot|semrushbot|mj12bot|majestic-12|dotbot|rogerbot|screaming frog|sitebulb|serpstatbot|seokicks|siteimprove|lighthouse|google page speed|gtmetrix|pingdom|uptimerobot|uptimebot|w3c_validator|w3c-checklink|archive\.org_bot|paperlibot|dataprovider\.com|grapeshotcrawler|zoominfobot|feedly|newsblur|inoreader|integration-test)" 1;
    # BOTS:END
}

# Archivos que nunca se renderizan (extensions.txt)
map $uri $jazui_static {
    default 0;
    # EXTENSIONS:BEGIN
    "~*\.(js|mjs|css|less|map|json|xml|rss|txt|webmanifest|ico|png|jpg|jpeg|gif|webp|avif|svg|bmp|tif|tiff|psd|ai|woff|woff2|ttf|otf|eot|mp3|m4a|wav|ogg|mp4|m4v|webm|avi|mov|mpg|mpeg|wmv|flv|swf|pdf|doc|docx|xls|xlsx|ppt|pptx|csv|zip|gz|rar|7z|iso|torrent|exe|dmg|apk|wasm|dll|dat|blat)$" 1;
    # EXTENSIONS:END
}

server {
    listen 443 ssl;
    server_name misitio.com;
    root /var/www/misitio;

    location / {
        set $jazui $jazui_bot;
        # Esquema antiguo de Google para las SPA, con cualquier user-agent
        if ($args ~ "_escaped_fragment_") { set $jazui 1; }
        if ($jazui_static) { set $jazui 0; }
        if ($http_x_jazui) { set $jazui 0; }
        if ($request_method !~ ^(GET|HEAD)$) { set $jazui 0; }
        # El "?" final quita la query: la URL completa viaja en X-Jazui-Url
        if ($jazui = 1) { rewrite ^ /__jazui? last; }

        try_files $uri $uri/ /index.html;
    }

    location = /__jazui {
        internal;
        proxy_http_version 1.1;
        proxy_set_header Host api.jazui.com;
        proxy_set_header Authorization "Bearer [JAZUI_TOKEN]";
        proxy_set_header X-Jazui-Url $scheme://$host$request_uri;
        # Detrás de un CDN o balanceador usa su cabecera ($http_cf_connecting_ip, $http_x_forwarded_for…)
        proxy_set_header X-Jazui-Client-IP $remote_addr;
        # Las cookies del visitante no le hacen falta a Jazui: no se envían
        proxy_set_header Cookie "";
        proxy_ssl_server_name on;
        proxy_connect_timeout 5s;
        proxy_read_timeout 20s;
        # Errores de Jazui → la SPA. 404, 410, 3xx y 403 (bot bloqueado) llegan al bot tal cual.
        proxy_intercept_errors on;
        error_page 400 401 429 500 502 503 504 = @spa;
        proxy_pass https://api.jazui.com/Render;
    }

    location @spa {
        try_files /index.html =404;
    }
}

Cambia [JAZUI_TOKEN] por tu token, y server_name y root por los de tu sitio. Si ya tienes un bloque location /, añade las líneas de set e if al principio y copia las ubicaciones /__jazui y @spa. Después comprueba y recarga:

Terminal
sudo nginx -t && sudo nginx -s reload

Qué hace

  • $jazui_bot vale 1 si el agente de usuario está en la lista; $jazui_static, si la ruta es un archivo.
  • En location / se combinan con _escaped_fragment_, la cabecera X-Jazui y el método: si hay que renderizar, se reescribe a /__jazui.
  • /__jazui es interna: envía Authorization, X-Jazui-Url (la dirección completa) y X-Jazui-Client-IP, con 5 s para conectar y 20 s para responder.
  • Con proxy_intercept_errors, los códigos 400, 401, 429 y 5xx de Jazui van a @spa, que sirve tu index.html.

Mantener al día la lista de bots

Esta configuración lleva la lista de bots escrita dentro, entre las marcas BOTS:BEGIN y BOTS:END, porque el servidor no puede descargarla solo. Cuando Jazui añade bots nuevos:

  1. En el panel, ve a Sitios web y pulsa Token del sitio en cualquiera de tus sitios.
  2. En Bots en nginx, IIS y Apache, elige la pestaña de tu servidor y copia el bloque. Verás cuántos bots tiene y la fecha de la lista.
  3. Sustituye en tu configuración todo lo que hay entre BOTS:BEGIN y BOTS:END por ese bloque y recarga el servidor.

También puedes descargar la lista en texto con GET https://api.jazui.com/v2/bots.txt o los bloques ya hechos con GET https://api.jazui.com/v2/bots/config.

<p>Pide tu portada como si fueras un bot, con el agente de usuario de pruebas <code>integration-test</code>:</p><pre><code>curl -I -A "integration-test" https://misitio.com/</code></pre><p>La respuesta debe llevar <code>x-jazui: true</code> y <code>x-jazui-cache: MISS</code> la primera vez y <code>HIT</code> después. Sin agente de bot (<code>curl -I https://misitio.com/</code>) debe llegar tu web de siempre, sin <code>x-jazui</code>. En el panel, la petición aparece en <b>Tráfico de bots</b> y la página en <b>Páginas en caché</b>.</p>

Pide tu portada como si fueras un bot, con el agente de usuario de pruebas integration-test:

curl -I -A "integration-test" https://misitio.com/

La respuesta debe llevar x-jazui: true y x-jazui-cache: MISS la primera vez y HIT después. Sin agente de bot (curl -I https://misitio.com/) debe llegar tu web de siempre, sin x-jazui. En el panel, la petición aparece en Tráfico de bots y la página en Páginas en caché.

Si algo no funciona

  • Detrás de Cloudflare u otro CDN, $remote_addr es la IP del CDN: usa $http_cf_connecting_ip en X-Jazui-Client-IP o configura real_ip_header.
  • nginx -t falla en map: los map tienen que estar dentro de http, no de server.
  • Error de SSL con la API: deja proxy_ssl_server_name on y el Host api.jazui.com.
  • Los bots reciben 403: el sitio no está verificado o bloqueaste a ese bot de IA o con una regla (mira la cabecera X-Jazui-Blocked).