Saya baru saja deploy perubahan ke sebuah multi-listing site yang saya bangun, lalu seperti biasa klik "Clear Cache" di WP Rocket. Buka situs sebagai admin, semua segar: copy baru, layout baru, semua benar. Tapi klien WhatsApp saya: "Masih versi lama." Saya buka di browser incognito, dan benar saja — halaman lama, persis seperti sebelum deploy. Bukan tertinggal sedetik dua detik. Lama. Berhari-hari kalau saya diamkan.
Yang bikin saya curiga sejak awal: saya sebagai admin lihat versi baru, publik lihat versi lama. Itu pola yang sangat spesifik. Saya cek header response-nya dengan curl dari mesin yang tidak login:
curl -sI https://old-site.com/listing/ | grep -i cf-cachecf-cache-status: HITHIT. Di situ jelas: respons yang dilihat publik bukan datang dari origin WordPress saya sama sekali. Itu datang dari edge Cloudflare.
Kenapa ini terjadi
Ada Page Rule di Cloudflare dengan setting Cache Everything dan TTL yang sangat panjang — Edge Cache TTL disetel ke level tahunan. Artinya Cloudflare bukan cuma nge-cache aset statis seperti gambar, CSS, dan JS (itu memang seharusnya), tapi juga nge-cache HTML penuh dari setiap halaman, lalu menyimpannya di edge node-nya untuk waktu yang sangat lama.
Default Cloudflare itu sebenarnya sopan: dia tidak meng-cache HTML kecuali kamu menyuruhnya. Begitu kamu pasang "Cache Everything", aturan main berubah total. Cloudflare mulai memperlakukan halaman HTML dinamis seperti file statis. Sekali sebuah URL nyangkut di edge dengan HIT, origin tidak pernah disentuh lagi sampai TTL habis atau cache di-purge.
Dan inilah kenapa saya sebagai admin tertipu sendiri. Saat saya login ke WordPress, browser saya mengirim cookie login WordPress. Cloudflare punya aturan default untuk bypass cache ketika ada cookie tertentu — termasuk cookie sesi login WP. Jadi request saya sebagai admin selalu menembus langsung ke origin, kena WP Rocket yang sudah saya clear, dan menampilkan HTML segar. Sementara pengunjung publik yang tidak punya cookie itu dilayani sepenuhnya dari salinan basi di edge.
Yang krusial untuk dipahami: clear WP Rocket itu mengosongkan cache di origin. WP Rocket hidup di server WordPress. Tapi salinan basi yang dilihat publik tidak tinggal di origin — dia tinggal di Cloudflare. Jadi waktu saya klik "Clear Cache" di WP Rocket, saya membersihkan ruangan yang memang sudah bersih dan tidak pernah jadi sumber masalah. Cloudflare di depannya tidak tahu apa-apa soal itu, dan tetap melayani HTML lamanya dengan tenang.
Cara saya memvisualisasikan rantai cache-nya:
Pengunjung publik -> Cloudflare edge (HTML basi, HIT) -> [tidak pernah sampai] -> Origin (WP + WP Rocket, segar)
Admin (punya cookie WP) -> [bypass edge] -> Origin (WP + WP Rocket, segar)Origin saya benar. WP Rocket saya benar. Yang basi adalah lapisan yang bahkan tidak saya sadari ikut nge-cache HTML.
Perbaikannya
Perbaikan langsung agar klien bisa lihat versi baru saat itu juga: jalankan Purge Everything di Cloudflare. Caching → Configuration → Purge Everything. Begitu edge cache dibuang, request publik berikutnya terpaksa kembali ke origin, ambil HTML segar, lalu Cloudflare nge-cache versi baru itu. Incognito langsung menampilkan versi terbaru.
Tapi "Purge Everything manual tiap deploy" itu rapuh — cepat atau lambat pasti ada yang lupa. Jadi saya jadikan bagian dari proses deploy. Cloudflare punya API purge, dan saya panggil di akhir setiap deploy yang mengubah HTML:
# Dipanggil di akhir deploy
curl -sS -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 '{"purge_everything":true}'Kalau hanya beberapa halaman yang berubah, lebih hemat purge URL spesifik daripada membuang seluruh cache:
curl -sS -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 '{"files":["https://old-site.com/","https://old-site.com/listing/"]}'Perbaikan yang lebih mendasar adalah berhenti meng-edge-cache HTML untuk respons dinamis. Untuk situs WordPress dengan konten yang sering berubah, "Cache Everything" pada HTML lebih banyak ruginya daripada untungnya. Saya sesuaikan Page Rule-nya: biarkan aset statis (gambar, CSS, JS) tetap di-cache lama di edge — itu memang sebaiknya — tapi jangan paksa HTML masuk ke edge cache, atau setidaknya kasih Edge Cache TTL yang masuk akal (menit, bukan tahun), bukan TTL setahun. Dengan begitu, halaman dinamis tetap segar tanpa harus purge manual setiap saat, sementara WP Rocket tetap menangani caching di origin seperti yang memang jadi tugasnya.
Pelajaran
Begitu ada CDN di depan WordPress, purge cache di origin cuma setengah pekerjaan. WP Rocket membersihkan origin; Cloudflare punya salinannya sendiri di edge yang sama sekali tidak peduli kamu sudah clear WP Rocket atau belum. Kalau edge-mu meng-cache HTML penuh, kamu harus purge edge juga setiap deploy — kalau tidak, pengunjung akan terus lihat situs kemarin sementara dashboard-mu sendiri tampak sempurna.
Dan kalau kamu pernah ketemu gejala "admin segar, publik basi", langsung curiga lapisan cache yang di-bypass oleh cookie login. Cek cf-cache-status lewat curl dari mesin yang tidak login. Begitu kamu lihat HIT padahal seharusnya halaman itu dinamis, kamu sudah menemukan tersangkanya — dan kamu tahu purge harus dilakukan di mana.
