Данила (Dayfing)
Жарияланымдарға оралу
2 550 сөз13 мин

Nginx және Cloudflare-да статиканы кэштеу: тақырыптар және кэшті тазалау

Атында хэші бар ассеттерге Cache-Control: public, max-age=31536000, immutable тақырыбын беріңіз, ал HTML-ді браузерлерге no-cache арқылы беріп, Cloudflare үшін бөлек қысқа edge TTL орнатыңыз. HTML-ді Cache Rule арқылы кэштеуге жарамды етіңіз, Browser Cache TTL-ді Respect Existing Headers режимінде қалдырыңыз және әр деплойдың соңғы қадамында HTML-ді тазалаңыз. Сонда браузер әр келген сайын шағын құжатты тексереді, мұндай тексерулердің көбіне edge өзі жауап береді, ал жаңа релиз purge сұранысына жауап келген бойда көрінеді.

Файлдың екі түріне арналған екі кэш саясаты

Статикалық жинақ екі түрлі файл шығарады. Саусақ ізі бар файлдардың, мысалы /_astro/index.3f9c1a.js файлының, атында мазмұн хэші болады. Мазмұн өзгерсе, URL да өзгереді, сондықтан ескі URL көшірмесі кез келген кэште бір жыл жата береді. HTML, фидтер, sitemap және robots.txt тұрақты URL-дерін сақтайды, сондықтан олардың кез келген кэштелген көшірмесі ескіруі мүмкін.

Сол себепті хэштелген файлдар ең ұзақ өмір мерзімін алады және ешқашан тазалауды қажет етпейді. Тұрақты URL-дер қайта тексерілетін браузер саясатын және тазалауға болатын edge саясатын алады. Жылдамдықтың негізгі бөлігін бірінші топ береді: қайта келген адам шағын HTML құжатын, көбіне 304 жауабы ретінде, жүктейді, ал барлық скрипттерді, стильдерді және қаріптерді жергілікті кэштен алады. Сондықтан кэштеу Time to First Byte пен Largest Contentful Paint көрсеткіштерін жақсартудың ең арзан тәсілдерінің бірі, мұны Core Web Vitals нұсқаулығы түсіндіреді.

Деплойдың екі ережесі бұл схеманы қауіпсіз етеді. HTML жаңа релизге ауыспай тұрып, жаңа хэштелген файлдарды жүктеңіз. Алдыңғы релиздің хэштелген файлдарын оларға сілтейтін HTML қандай да бір кэште тұруы мүмкін уақыт бойы сақтаңыз, өйткені деплойға дейін ашылған қойынды ескі атауларды сұрайды.

Browser TTL мен edge TTL: екі бөлек сағат

Браузер кэші келушіге тиесілі, жауап кеткеннен кейін сіздің ешбір әрекетіңіз одан жазбаны өшіре алмайды. Edge кэші Cloudflare-ға тиесілі, ал purge API оны бірнеше секундта тазалайды. Сондықтан ұзақ browser TTL тек мазмұны ешқашан өзгермейтін URL-дерге ғана жарайды. HTML үшін no-cache директивасы браузерге бетті сақтауға рұқсат береді, бірақ әр қайта қолданар алдында шартты сұранысты талап етеді.

Edge TTL s-maxage арқылы, Cloudflare-CDN-Cache-Control немесе CDN-Cache-Control арқылы, не болмаса Cache Rule арқылы беріледі. Оны тазалауға болатындықтан, HTML үшін edge TTL жаңарту механизмі емес, сақтандыру ғана. Purge сәтсіз болса, edge-тегі ең нашар ескіру уақыты жаңалық мерзімі мен stale-while-revalidate терезесінің қосындысына тең: max-age=300, stale-while-revalidate=60 үшін бұл 360 секунд.

Алдымен аймақтың бір баптауын тексеріңіз. Browser Cache TTL барлық тарифте әдепкі бойынша төрт сағатқа тең, ал Cloudflare одан кіші origin мерзімдерін қайта анықтайды. Сонда әр жолы тексерілуге тиіс HTML браузерлерде сағаттап сақталып, оған ешбір purge жетпейді. Browser Cache TTL мәнін Respect Existing Headers етіп қойыңыз, бұл edge және browser TTL құжаттамасында сипатталған.

Cloudflare s-maxage, stale-while-revalidate және stale-if-error директиваларын қалай оқиды

Браузерлер s-maxage директивасын елемейді, сондықтан Cache-Control: public, max-age=0, s-maxage=300 HTML үшін айқын тақырып сияқты көрінеді, әрі Cloudflare оны шынымен edge TTL ретінде қолданады. Мәселе RFC 9111 құжатында: s-maxage proxy-revalidate семантикасын да қамтиды, яғни ортақ кэш алдын ала тексермей ескірген жауапты бермеуі керек.

Free, Pro және Business тарифтерінде Origin Cache Control әрқашан қосулы, ал Cloudflare бұл ережені сақтайды. Оның қайта тексеру құжаттамасы s-maxage, must-revalidate, proxy-revalidate және no-cache директиваларын ескірген көшірмені беруді өшіретін директивалар деп атайды. stale-while-revalidate қасында олар UPDATING күйін EXPIRED күйіне айналдырады, ал келуші origin-ді күтеді. Осы директивалар Cloudflare-ды stale-if-error директивасын елемеуге де мәжбүрлейді. max-age=0, s-maxage=300, stale-while-revalidate=60, stale-if-error=86400 сияқты тақырып тек 300 секундтық edge TTL береді, одан артық ештеңе бермейді.

stale-while-revalidate жұмыс істегенде қайта тексеру асинхронды болады: мерзім біткеннен кейінгі алғашқы сұраныс ескірген көшірмені cf-cache-status: UPDATING күйімен алады, ал Cloudflare оны фонда жаңартады. stale-if-error тек origin-нен келген 5xx жауаптарында іске қосылады. Always Online екі директиваны да өшіреді, ал TTL мәндері бүтін сан болуы керек.

Браузерлер мен edge үшін s-maxage-сіз әртүрлі саясат беру үшін мақсатты тақырыпты қолданыңыз. Cloudflare алдымен Cloudflare-CDN-Cache-Control, содан кейін CDN-Cache-Control, одан соң Cache-Control тақырыбын тексереді. CDN тақырыбы болса, Cache-Control браузерге өзгеріссіз жетеді және edge-ке әсер етпейді, ал Cloudflare-CDN-Cache-Control тақырыбын Cloudflare әрі қарай жібермейді. HTML үшін:

Cache-Control: no-cache
Cloudflare-CDN-Cache-Control: max-age=300, stale-while-revalidate=60, stale-if-error=86400

Браузер бетті әр жолы тексереді. Cloudflare оны бес минут сақтайды, жаңарту кезінде бір минутқа дейін ескірген көшірмені береді, ал origin істен шықса, соңғы жұмыс істейтін көшірмені бір тәулік береді. Басымдық ережелері CDN-Cache-Control құжаттамасында сипатталған.

Cache Rules: origin-ге сену немесе қайта анықтау

Әдепкі бойынша Cloudflare жауапты кэштеу-кэштемеуді файл кеңейтімі бойынша шешеді және HTML мен JSON-ды кэштемейді. /writing/post/ сияқты URL-дің кеңейтімі жоқ, сондықтан ережесіз әр бет сұранысы DYNAMIC күйін алып, origin-ге кетеді.

Eligible for cache күйіндегі Cache Rule-да Edge TTL-дің үш режимі бар. respect_origin сіздің тақырыптарыңызды орындайды, ал олар болмаса әдепкі мәндерді алады, мысалы 200 жауабы үшін 120 минут. bypass_by_default тақырыптарды орындайды, ал олар болмаса кэштемейді. override_origin тақырыптарды елемей, TTL-ді мәжбүрлеп орнатады, оның ең аз мәні тарифке байланысты: Free-де 2 сағат, Pro-да 1 сағат, Business пен Enterprise-та 1 секунд. Browser TTL-ді origin-нен алуға, қайта анықтауға немесе өшіруге болады.

Origin ойластырылған тақырыптар берсе, соларға сеніңіз. http_request_cache_settings фазасына арналған мына ережелер жиыны хостты кэштеуге жарамды етеді, содан кейін динамикалық жолдарды шығарып тастайды. Кэш баптаулары үшін соңғы сәйкес келген ереже жеңеді, сондықтан bypass ережесі соңында тұрады.

{
  "rules": [
    {
      "description": "Cache the site according to origin headers",
      "expression": "http.host eq \"example.com\"",
      "action": "set_cache_settings",
      "action_parameters": {
        "cache": true,
        "edge_ttl": { "mode": "respect_origin" },
        "browser_ttl": { "mode": "respect_origin" }
      }
    },
    {
      "description": "Never cache API routes and previews",
      "expression": "http.host eq \"example.com\" and (starts_with(http.request.uri.path, \"/api/\") or starts_with(http.request.uri.path, \"/preview/\"))",
      "action": "set_cache_settings",
      "action_parameters": { "cache": false }
    }
  ]
}

Кэштеу ережесіне http.request.method eq "GET" шартын қоспаңыз. Cloudflare ескертуінше, ереже тек GET сұранысымен сәйкес келсе, жеке URL бойынша тазалау жұмыс істемеуі мүмкін, өйткені purge сұраныстары ішкі жағынан басқа әдісті қолданады. Параметрлердің толық тізімі Cache Rules баптауларында берілген.

add_header мұрагерлік тұзағынсыз Nginx тақырыптары

Nginx add_header директиваларын жоғарғы деңгейден ағымдағы деңгейде олар мүлде болмаған жағдайда ғана мұраға алады. location өзінің Cache-Control тақырыбын қосқан сәтте server деңгейіндегі барлық тақырып, соның ішінде қауіпсіздік тақырыптары да, онда үнсіз жоғалады.

server {
    add_header X-Content-Type-Options "nosniff" always;

    location ^~ /_astro/ {
        # X-Content-Type-Options is no longer sent for this location.
        add_header Cache-Control "public, max-age=31536000, immutable";
    }
}

Әмбебап шешім: ортақ тақырыптарды сниппетке шығарып, өз add_header директивасы бар әр блокқа include арқылы қосу. Nginx 1.29.3 және одан жаңа нұсқаларда, соның ішінде 1.30 тұрақты тармағында, add_header_inherit merge директивасы оның орнына мұраға алынған тақырыптарды қосып жазады. merge қолданғанда Cache-Control тақырыбын server блогында ұстамаңыз, әйтпесе location-дар оны екі рет жібереді.

headers модулі құжаттамасы бойынша always жоқ add_header тек 200, 201, 204, 206, 301, 302, 303, 304, 307 және 308 жауаптарына қолданылады. always параметрін қауіпсіздік тақырыптары үшін және қате беттеріндегі no-store үшін қолданыңыз, бірақ ұзақ мерзімді кэш тақырыптарына ешқашан қоспаңыз, әйтпесе ассет атауындағы қатеге қайтарылған 404 бір жылға immutable болып қалады. Сондай-ақ expires пен add_header Cache-Control директиваларын араластырмаңыз, бұл екі тақырып өрісін береді. TLS пен журналдаусыз статикалық жинаққа арналған server блогы:

server {
    listen 443 ssl;
    http2 on;
    server_name example.com;
    root /srv/example.com/current;
    index index.html;

    gzip on;
    gzip_vary on;
    gzip_static on;
    gzip_types text/css application/javascript application/json
               application/xml application/rss+xml image/svg+xml text/plain;

    location ^~ /_astro/ {
        include snippets/security-headers.conf;
        add_header Cache-Control "public, max-age=31536000, immutable";
        try_files $uri =404;
    }

    location ~* \.(?:avif|webp|png|jpe?g|gif|svg|ico|woff2)$ {
        include snippets/security-headers.conf;
        add_header Cache-Control "public, max-age=86400";
        try_files $uri =404;
    }

    location ~* \.(?:xml|txt)$ {
        include snippets/security-headers.conf;
        add_header Cache-Control "public, max-age=300";
        add_header Cloudflare-CDN-Cache-Control "max-age=3600, stale-if-error=86400";
        add_header Cache-Tag "html";
        try_files $uri =404;
    }

    location / {
        include snippets/security-headers.conf;
        add_header Cache-Control "no-cache";
        add_header Cloudflare-CDN-Cache-Control "max-age=300, stale-while-revalidate=60, stale-if-error=86400";
        add_header Cache-Tag "html";
        try_files $uri $uri/ =404;
    }

    error_page 404 /404.html;
    location = /404.html {
        internal;
        include snippets/security-headers.conf;
        add_header Cache-Control "no-store" always;
    }
}

gzip_static үшін --with-http_gzip_static_module параметрімен жиналған нұсқа керек, мұны nginx -V шығысынан көруге болады. Ешкім кэшті айналып өтпеуі үшін origin қосылымдарды тек Cloudflare-дан қабылдауы керек. Бұған қажет файрвол баптауын Linux VPS қорғау нұсқаулығы талдайды.

ETag, Last-Modified және қайта тексеру

Әдепкі бойынша қосулы etag on кезінде Nginx статикалық файлдар үшін ETag пен Last-Modified тақырыптарын жібереді және шартты сұраныстарға 304 кодымен жауап береді. Оның ETag мәні мазмұн хэшінен емес, файлдың өзгерген уақыты мен өлшемінен құралады. Сондықтан барлық файлды қайта жазатын деплой барлық ETag-ты өзгертеді, ал релизден кейінгі алғашқы қайта тексеру толық 200 жауабын қайтарады. Релизді бірнеше origin сервері таратса, олардағы файл уақыттары сәйкес болуы керек, мысалы rsync -a арқылы көшіргенде, әйтпесе қайта тексеру нәтижесі қай сервердің жауап бергеніне байланысты болады.

Көшірме жаңа тұрғанда браузерлердің қайта тексерулеріне Cloudflare өзі жауап береді. Мерзім біткен соң ол Nginx-ке шартты сұраныс жібереді, ал 304 жауабы денені жібермей-ақ TTL-ді ұзартады. Cloudflare кодтауды өзгерткенде күшті ETag-ты әлсіз W/"..." түріне айналдырады. Бұл зиянсыз, өйткені If-None-Match әлсіз салыстыруды қолданады. Respect Strong ETags баптауын клиентке байт-байтқа дәл валидаторлар шынымен керек болғанда ғана қосыңыз.

Сығу: origin-де gzip, edge-те Brotli және Zstandard

Cloudflare origin-нен accept-encoding: br, gzip сұрайды және алған жауабын қайта кодтай алады. Келушілерге ол Accept-Encoding, тариф және Compression Rules негізінде gzip, Brotli немесе Zstandard береді. Әдепкі бойынша Free аймақтары Zstandard-ты, Pro мен Business Brotli-ды таңдайды, ал Enterprise gzip қолданады. Сығу құжаттамасында көрсетілгендей, тек 200, 403 және 404 жауаптары сығылады.

Cloudflare артындағы origin үшін gzip жеткілікті. Мәтіндік файлдарды gzip_static үшін жинақ кезінде алдын ала сығыңыз немесе gzip on арқылы лезде сығуды қосыңыз. Әдепкі бойынша gzip_types тек text/html қамтиды, сондықтан қалған мәтіндік түрлерді тізіп, gzip_vary on қалдырыңыз. Brotli мен Zstandard nginx.org модульдер жиынына кірмейді және үшінші тарап модульдерін қажет етеді. Мәтіндік жауаптарға Cache-Control: no-transform қоймаңыз, өйткені онда Cloudflare сығылмаған жауапты сықпайды.

Cookies, query string және кэш кілті

Cloudflare-дың әдепкі кэш кілтінде схема, хост, жол және толық query string, сондай-ақ Origin сияқты бірнеше сұраныс тақырыбы бар. Cookies оған кірмейді, сондықтан кэштелетін URL ешқашан cookie-ге тәуелді болмауы керек. Жүйеге кірген пайдаланушыларға арналған беттерді, себеттерді, API-ды немесе агент бэкендін private не no-store арқылы bypass ережесіне шығарыңыз немесе бөлек хостқа ауыстырыңыз. Мұндай динамикалық сұраныс жолының әдетте қандай болатынын production үшін AI-агент архитектурасы нұсқаулығы көрсетеді.

Set-Cookie жауап тақырыбы кэштеуді бұзады. Eligible for cache кезінде Cloudflare cookie-ді сақтап, жауапты кэшке салмайды, сондықтан әр сұраныс MISS алады. Ешбір модуль не жүктеме теңестіргіш статикалық файлдарға cookies қоспайтынын тексеріңіз немесе оларды Cache Response Rule арқылы алып тастаңыз.

Әр жеке query string бөлек жазба құрайды, сондықтан ?utm_source= бар сілтемелер кэштен табылмаудан басталады. Бұл дұрыстыққа емес, тек сәйкестік үлесіне әсер етеді. Ignore Query String кэштеу деңгейі тек статикалық файл кеңейтімдеріне қолданылады, ал query string параметрлері бойынша жеке кілттер тарифке байланысты. Sort query string барлық тарифте қолжетімді.

Purge стратегиялары және CI-дан тазалау

2025 жылдың сәуірінен бастап purge әдістерінің бәрі кез келген тарифте қолжетімді:

  • Single URL нақты URL-дерді өшіреді, бір сұраныста 100-ге дейін (Enterprise-та 500), жинақ не өзгергенін білгенде ыңғайлы.
  • Prefix example.com/writing/ сияқты жолдың астындағының бәрін, query string нұсқаларымен қоса өшіреді.
  • Tag жауабында сәйкес Cache-Tag тақырыбы болған барлық нысанды өшіреді. Cloudflare бұл тақырыпты келуші көргенге дейін алып тастайды. HTML, фидтер мен sitemap-ты html тегімен белгілесеңіз, бір шақыру барлық тұрақты URL-ді тазалайды, ал хэштелген ассеттер кэште қалады.
  • Hostname бір хосттағының бәрін өшіреді.
  • Everything бүкіл аймақты тазалап, кэш қайта толғанша бүкіл трафикті origin-ге жібереді, сондықтан оны соңғы амал ретінде қалдырыңыз.

Hostname, tag, prefix және purge everything сұраныстары аккаунттың ортақ лимитін бөліседі: Free-де минутына 5 сұраныс, Pro-да секундына 5, Business-те секундына 10 және Enterprise-та секундына 50, бұл purge құжаттамасында көрсетілген. Бір аймаққа тек Cache Purge құқығы бар API токенін қолданып, оны CI құпиясы ретінде сақтаңыз:

#!/usr/bin/env bash
set -euo pipefail
: "${CF_API_TOKEN:?}" "${CF_ZONE_ID:?}" "${ORIGIN_HOST:?}"

# 1. Hashed assets first, without --delete, so old pages keep working.
rsync -a dist/_astro/ "deploy@${ORIGIN_HOST}:/srv/example.com/current/_astro/"

# 2. Everything else. Excluded paths are not deleted.
rsync -a --delete --exclude '/_astro/' dist/ "deploy@${ORIGIN_HOST}:/srv/example.com/current/"

# 3. Purge HTML, feeds and sitemaps at the edge.
curl -fsS --max-time 30 -X POST \
  "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/purge_cache" \
  -H "Authorization: Bearer ${CF_API_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{"tags":["html"]}' </dev/null \
  | jq -e '.success == true' >/dev/null

Үлкен сайттарға жинақты релиз каталогына жүктеп, symlink-ті атомарлы түрде ауыстырған дұрыс. Purge сұранысына келген сәтті жауап тек сұраныстың қабылданғанын білдіреді, сондықтан тапсырманы өзгерген бетті жүктеп, жинақ белгісін, мысалы коммит хэшін, тексерумен аяқтаңыз.

curl -I, cf-cache-status және Age арқылы тексеру

curl -sSI -H 'Accept-Encoding: zstd, br, gzip' https://example.com/writing/some-post/ \
  | grep -iE '^(cache-control|cf-cache-status|age|etag|content-encoding):'

Кэштелетін сұраныстар үшін Cloudflare HEAD әдісін GET әдісіне айналдырады, сондықтан curl -I да кэшті толтырады. Бірінші жауап MISS, екіншісі Age бар HIT көрсетуі керек, яғни нысан кэштелген немесе қайта тексерілген сәттен бергі секунд саны. Әр күй кэш жауаптары құжаттамасында анықталған:

  • DYNAMIC: сұраныс кэшке жарамсыз, әдетте HTML ережемен қамтылмағандықтан немесе Development Mode қосулы болғандықтан.
  • BYPASS: сұраныс жарамды, бірақ no-store, private, Set-Cookie немесе Vary: * салдарынан жауап кэштелмейді.
  • UPDATING: фондық қайта тексеру жүріп жатқанда ескірген көшірме берілді.
  • EXPIRED: ескірген көшірме синхронды түрде қайта жүктелді. Егер UPDATING күткен болсаңыз, s-maxage, must-revalidate немесе no-cache іздеңіз.
  • REVALIDATED: сұраныс күтіп тұрғанда origin көшірмені 304 жауабымен растады.
  • STALE: origin жауап бермеді және ескі көшірме берілді.

Purge-тен кейін MISS күтіңіз, ал Tiered Cache кезінде және purge everything-тен кейін EXPIRED болуы мүмкін. Тек Nginx-ті тексеру үшін рұқсат етілген хосттан origin-ге curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/ командасымен жүгініңіз, содан кейін -H 'If-None-Match: "<etag>"' қосып, 304 күтіңіз.

Файл түрлері бойынша ұсынылатын тақырыптар

Файл түрі Мысал Cache-Control Edge саясаты Деплойдан кейін
Саусақ ізі бар JS, CSS, қаріптер, суреттер /_astro/app.3f9c1a.js public, max-age=31536000, immutable Origin-нен Ештеңе
HTML беттер /writing/post/ no-cache max-age=300, stale-while-revalidate=60, stale-if-error=86400 html тегін purge
Фидтер, sitemap, robots.txt /rss.xml public, max-age=300 max-age=3600, stale-if-error=86400 html тегін purge
Хэшсіз суреттер мен белгішелер /favicon.ico public, max-age=86400 Origin-нен URL purge немесе жаңа атау
Деплойлар арасында өзгеретін JSON /data/stats.json public, max-age=60 Origin-нен немесе bypass URL purge
404 беті кез келген жоқ URL always бар no-store Кэштелмейді Ештеңе
API, превью, әкімші бөлімі /api/ private, no-store Bypass ережесі Ештеңе

max-age бар edge мәндері Cloudflare-CDN-Cache-Control тақырыбына жазылады. 404 жауаптарын edge-те кэштесеңіз, оларды html тегімен белгілеңіз, әйтпесе кейін жарияланған бет кэштелген 404-тің артында жасырын қалады.

Деплойдың бақылау тізімі

  • Ассет атауларында мазмұн хэштері бар, ал тұрақты URL-і бар ештеңе immutable деп белгіленбеген.
  • add_header бар әр Nginx блогы қауіпсіздік тақырыптарын қосады, ал always тек қауіпсіздік тақырыптары мен қате жауаптарында тұр.
  • HTML no-cache пен Cloudflare-CDN-Cache-Control тақырыптарын бірге жібереді, stale-while-revalidate қасында s-maxage жоқ.
  • gzip_types мәтіндік түрлерді қамтиды, ал статикалық жауаптарда Set-Cookie жоқ.
  • Browser Cache TTL бар тақырыптарды ескереді, ал bypass ережесі соңында тұр және тек GET-пен шектелмеген.
  • CI ассеттерді HTML-ден бұрын жүктейді, ескі хэштелген файлдарды сақтайды, html тегін тазалайды және success true болмаса құлайды.
  • Бет алдымен MISS, содан кейін Age бар HIT, ал edge TTL біткен соң UPDATING көрсетеді.
  • Origin трафикті тек Cloudflare-дан қабылдайды.

Басқа жарияланымдар