{"slug":"fix-cdn-cached-redirect-killing-google-indexing","locale":"id","isFallback":false,"translationAvailable":["en","id"],"translationUrls":{"en":"/api/posts/fix-cdn-cached-redirect-killing-google-indexing?locale=en","id":"/api/posts/fix-cdn-cached-redirect-killing-google-indexing?locale=id"},"title":"Redirect 307 Ter-cache CDN Bikin Indexing Google Ambruk Total","description":"Redirect locale berbasis cookie ter-cache di Firebase CDN tanpa Vary: Cookie, bikin Googlebot kena 307 terus. Begini cara diagnosis dan perbaikannya.","date":"2026-05-03","updated":null,"tags":["web","nextjs","seo","firebase","debugging"],"category":"Development","content":"\nMinggu lalu saya buka Google Search Console dan langsung kaget — impressions SnipGeek turun dari sekitar 180 per hari jadi hampir nol dalam tiga hari. Tidak ada deployment error, tidak ada alert downtime, tidak ada perubahan konten. Tiba-tiba saja Google berhenti menampilkan halaman saya.\n\nAwalnya saya curiga ada tag `noindex` yang tidak sengaja masuk, atau `robots.txt` yang rusak. Ternyata bukan. Penyebabnya jauh lebih halus — dan jujur, saya tidak menyangka sebuah cookie bahasa bisa bikin separah ini.\n\n## Gejalanya: Homepage Redirect ke `/id/`\n\nSaya jalankan `curl` ke homepage live untuk cek response header:\n\n```bash\ncurl -sI https://snipgeek.com/ | grep -iE 'HTTP|location|cache|cdn'\n```\n\nHasilnya bikin saya diam sejenak:\n\n```\nHTTP/2 307\nlocation: /id/\ncache-control: public, s-maxage=3600, stale-while-revalidate=86400\ncdn-cache-status: hit\nage: 2326\n```\n\nHomepage mengembalikan **307 temporary redirect ke `/id/`** — versi Bahasa Indonesia — untuk *semua pengunjung*, termasuk Googlebot. Dan CDN sudah meng-cache-nya selama lebih dari 38 menit.\n\nSaya cek halaman lain seperti `/blog` dan `/about` — semuanya normal, return 200. Tapi homepage, halaman paling penting untuk crawling, justru yang rusak.\n\n## Akar Masalahnya: Cookie + CDN = Racun\n\nSnipGeek adalah situs bilingual (English/Indonesian) yang dibangun dengan [Next.js](/blog/firebase-studio-sunset-migration-guide) dan di-deploy di Firebase App Hosting. Routing i18n-nya ada di `proxy.ts` (pengganti middleware di Next.js 16).\n\nIni kode yang menyebabkan masalah:\n\n```typescript\n// proxy.ts (SEBELUM — versi yang bermasalah)\nconst preferredLocale = request.cookies.get(\"NEXT_LOCALE\")?.value;\n\nif (pathnameIsMissingLocale) {\n  if (preferredLocale && preferredLocale !== i18n.defaultLocale) {\n    // Redirect ini di-cache CDN!\n    return NextResponse.redirect(\n      new URL(`/${preferredLocale}${pathname}`, request.url),\n    );\n  }\n  return NextResponse.rewrite(\n    new URL(`/${i18n.defaultLocale}${pathname}`, request.url),\n  );\n}\n```\n\nLogikanya kelihatan wajar: kalau pengunjung punya cookie `NEXT_LOCALE=id`, redirect ke versi Indonesia. Kalau tidak, rewrite ke locale default (English).\n\nMasalahnya ada di apa yang terjadi *setelah* response redirect itu keluar dari server.\n\n## Kenapa CDN Bikin Masalah Ini Jadi Fatal\n\nFirebase App Hosting punya CDN di depan server. Di `next.config.ts` saya menerapkan cache header ini untuk semua route halaman:\n\n```typescript\n{\n  key: \"Cache-Control\",\n  value: \"public, s-maxage=3600, stale-while-revalidate=86400\",\n}\n```\n\nArtinya CDN diminta \"cache response ini selama 1 jam, dan boleh serve yang stale sampai 24 jam.\" Yang hilang? **Tidak ada header `Vary: Cookie`.**\n\nJadi ketika *saya* (atau pengunjung manapun yang prefer bahasa Indonesia) mengakses homepage dengan cookie `NEXT_LOCALE=id`, CDN langsung meng-cache redirect 307 itu. Setiap pengunjung berikutnya — termasuk Googlebot — mendapat redirect yang ter-cache, bukan halaman HTML yang sebenarnya.\n\nGooglebot tidak mengirim cookie. Dia mengharapkan konten HTML di `snipgeek.com/`. Yang didapat malah dipantulkan ke `/id/` terus-menerus, tergantung timing cache CDN. Hasilnya: Google berhenti mempercayai homepage sebagai entry point yang stabil, dan impressions ambruk.\n\n<Callout variant=\"danger\" title=\"Pola Berbahaya\">\n  Redirect berbasis cookie + CDN caching publik tanpa `Vary: Cookie` = **cache poisoning**. Cookie pengunjung pertama menentukan apa yang dilihat semua orang sampai cache expired.\n</Callout>\n\n## Proses Diagnosis\n\nAudit yang saya lakukan cukup sistematis. Saya cek tiap layer yang bisa mempengaruhi indexing:\n\n<Steps>\n  <Step>\n\n  ### Cek robots.txt dan sitemap.xml\n\n  Keduanya bersih. `robots.txt` mengizinkan `/` untuk semua user agent, dan `sitemap.xml` berisi semua 216 URL yang published termasuk setiap blog post.\n\n  ```bash\n  curl -sS https://snipgeek.com/robots.txt | head -20\n  curl -sS https://snipgeek.com/sitemap.xml | grep -c '<url>'\n  ```\n\n  </Step>\n  <Step>\n\n  ### Cek meta robots di blog post\n\n  Saya fetch contoh blog post dan periksa HTML untuk directive `noindex`:\n\n  ```bash\n  curl -sS https://snipgeek.com/blog/disable-windows-defender-windows-11 \\\n    | grep -i 'robots'\n  ```\n\n  Hasilnya: `<meta name=\"robots\" content=\"index, follow\"/>` — benar. Tidak ada `X-Robots-Tag` header juga.\n\n  </Step>\n  <Step>\n\n  ### Test dengan user-agent Googlebot\n\n  Saya ingin memastikan Googlebot melihat hal yang sama:\n\n  ```bash\n  curl -sI -A \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\" \\\n    https://snipgeek.com/blog/disable-windows-defender-windows-11\n  ```\n\n  Blog post mengembalikan 200 dengan HTML lengkap. Tapi ketika saya test homepage — di situ 307-nya muncul.\n\n  </Step>\n  <Step>\n\n  ### Lacak asal redirect\n\n  Header `age: 2326` dan `cdn-cache-status: hit` mengonfirmasi ini bukan response segar dari server. CDN yang menyajikan redirect basi. Saya telusuri kembali ke `proxy.ts` dan menemukan branch redirect berbasis cookie.\n\n  </Step>\n</Steps>\n\n## Perbaikannya: Tiga Baris Dihapus\n\nFix-nya minimal. Saya hapus seluruh branch redirect berbasis cookie dari `proxy.ts`:\n\n```typescript\n// proxy.ts (SESUDAH — versi yang sudah diperbaiki)\nif (pathnameIsMissingLocale) {\n  return NextResponse.rewrite(\n    new URL(\n      `/${i18n.defaultLocale}${pathname.startsWith(\"/\") ? \"\" : \"/\"}${pathname}`,\n      request.url,\n    ),\n  );\n}\n```\n\nSekarang URL tanpa locale **selalu** di-rewrite ke locale default (English). Tidak ada redirect, tidak ada risiko cache poisoning.\n\nPreferensi bahasa berbasis cookie tetap berfungsi — tapi sepenuhnya di sisi client. Komponen `LanguageSwitcher` dan `LocaleSuggestionBanner` menggunakan `router.push()` untuk navigasi ke URL `/id/` saat pengguna mengganti bahasa. Cookie tetap di-set untuk logika \"jangan tampilkan lagi\" di banner, tapi proxy tidak pernah membacanya lagi.\n\n<Callout variant=\"info\" title=\"Prinsipnya\">\n  Redirect server-side yang bergantung pada cookie tidak boleh di-cache secara publik. Tambahkan `Vary: Cookie` (yang efektifnya mematikan CDN caching) atau pindahkan logikanya ke client-side.\n</Callout>\n\n## Perbaikan Tambahan\n\nSambil sudah bongkar-bongkar, saya sekalian menambah beberapa perkuatan defensif:\n\n- **Hapus redirect `/en` duplikat** dari `next.config.ts` — proxy sudah meng-handle kanonisasi `/en/*` → `/*` dengan redirect 308. Punya keduanya itu redundan.\n- **Tambah meta `robots` eksplisit** ke `generateMetadata` blog dan notes — sebelumnya mengandalkan inheritance dari layout, yang rapuh kalau metadata layout berubah.\n- **Tambah schema JSON-LD HowTo** untuk artikel bertag tutorial — ini mengaktifkan [rich results di Google Search](/blog/to-do-after-install-windows11) untuk konten step-by-step.\n\n## Pelajaran yang Saya Ambil\n\nBagian paling menakutkan dari bug ini adalah betapa tidak terlihatnya. Situs tetap bisa diakses normal di browser saya (saya punya cookie-nya, jadi saya melihat redirect dan mendarat di `/id/` — persis seperti yang didesain). Tidak ada error log, tidak ada 500, tidak ada build failure.\n\nSatu-satunya sinyal adalah grafik Search Console yang turun ke nol. Kalau saya tidak cek GSC minggu itu, bug ini bisa tidak terdeteksi jauh lebih lama.\n\nTiga poin yang saya pin untuk ke depan:\n\n- **Jangan pernah return redirect berbasis cookie dengan cache header `public`.** Kalau response bervariasi berdasarkan cookie, tandai `private` atau gunakan `Vary: Cookie`.\n- **Test homepage kamu dengan `curl`, bukan browser.** Browser membawa cookie dan cache state yang menyembunyikan masalah level CDN.\n- **Cek Search Console tiap minggu.** Itu satu-satunya early warning system untuk masalah crawl yang tidak muncul di application monitoring.\n\nKalau kamu menjalankan situs Next.js multilingual di hosting yang punya CDN di depannya (Firebase, Vercel, Cloudflare), saya sangat sarankan untuk jalankan `curl -sI homepage-kamu.com` sekarang juga. Bisa saja hasilnya mengejutkan.\n\n### References\n1. [Google tentang 307 redirect dan indexing](https://developers.google.com/search/docs/crawling-indexing/301-redirects)\n2. [Dokumentasi proxy.ts Next.js](https://nextjs.org/docs/app/api-reference/file-conventions/proxy)\n3. [HTTP Vary header — MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary)\n"}