---
title: "Googlebot 500 trên Firebase Hosting: case study sự cố production Next.js"
description: "Người dùng và mọi crawler khác nhận 200, riêng Googlebot nhận 500 trên toàn site. Nguyên nhân: regression ở luồng 404, bị khuếch đại bởi bước xác minh crawler ở edge."
canonical: "https://tmtuan.dev/vi/articles/googlebot-500-firebase-hosting-nextjs"
language: "vi"
image: "https://tmtuan.dev/_img/articles/googlebot-500-firebase-hosting-nextjs/googlebot-500-firebase-hosting-nextjs-cover.adc2a628-og.jpg"
updated: "2026-09-18"
tokens: 3223
---

# Case study — Truy vết HTTP 500 chỉ xảy ra với Googlebot, xuyên Next.js, Cloud Run và hosting edge

> Case study này đã lược bỏ mã nguồn thuộc sở hữu khách hàng, thông tin repository nội bộ, mã định danh cloud project, timestamp vận hành, trao đổi nguyên văn với nhà cung cấp và dữ liệu mật của khách hàng. Nội dung giữ lại là phương pháp điều tra, chuỗi lỗi ở mức kỹ thuật và bài học vận hành.

## Bối cảnh

Một website production cho khách hàng doanh nghiệp Nhật: Next.js dùng App Router, chạy trên Cloud Run, traffic công khai phục vụ qua Firebase Hosting.

Một đặc điểm của mô hình này định hình toàn bộ quá trình điều tra. Đội dự án quan sát trực tiếp được ứng dụng và Cloud Run. Tầng edge phục vụ domain công khai thì phần lớn nằm ngoài vùng quan sát đó — không có quyền truy cập trực tiếp để xem toàn bộ hành vi bên trong của nó.

_Diagram: Googlebot gửi request tới edge Firebase Hosting, edge rewrite sang Cloud Run đang chạy Next.js. Edge nằm giữa crawler và origin._

Domain công khai đi qua một tầng edge mà ứng dụng không quan sát trực tiếp được. Vì vậy một request thành công ở origin không nói lên điều gì về thứ Googlebot nhận được trên domain công khai.

Khoảng trống đó chính là nơi sự cố xảy ra.

## Vấn đề

Search visibility giảm mạnh trong thời gian ngắn. Bản thân website vẫn hoạt động bình thường với người dùng thật.

Tổ hợp đó loại ngay những cách giải thích thông thường. Đây không phải vấn đề traffic, cũng không phải vấn đề nội dung — đây là vấn đề hạ tầng, riêng ở cách crawler được phục vụ.

## Triệu chứng

Bốn đặc điểm khiến case này khó truy vết, và đáng nêu ra vì mỗi đặc điểm vô hiệu hoá một phản xạ debug quen thuộc:

**Lỗi vô hình với người dùng và với monitoring thông thường.** Browser và các bot khác nhận HTTP 200. Uptime check kiểu phổ thông không thấy gì bất thường.

**Lỗi không để lại dấu vết ở nơi ai cũng tìm trước tiên.** Các page request lỗi của Googlebot không bao giờ tới origin, nên Cloud Run log không có stack trace và không có 5xx tương ứng.

**Nguyên nhân và hậu quả cách nhau về thời gian.** Regression phía ứng dụng đã lên từ trước thời điểm sự cố lộ ra khá lâu. Vì vậy đối chiếu với deploy gần nhất dẫn sai hướng.

**Đây là chuỗi lỗi nhiều tầng, không phải một lỗi đơn lẻ.** Chỉ nhìn ứng dụng thì thấy một response hỏng ở `/robots.txt`. Chỉ nhìn SEO thì thấy Googlebot ngừng crawl. Giá trị nằm ở chỗ nối được hai hiện tượng đó thành một chuỗi nhân quả duy nhất.

## Quá trình điều tra

Nguyên tắc xuyên suốt: mỗi bước phải **loại trừ được một nhóm giả thuyết**, không chỉ gom thêm bằng chứng cho giả thuyết đang nghiêng về nhất.

Điều này quan trọng hơn vẻ ngoài của nó. Giả thuyết ban đầu nghiêng hẳn về hạ tầng, và nếu cứ gom bằng chứng ủng hộ nó thì kết quả sẽ là một câu trả lời nghe chắc chắn nhưng thiếu — regression phía ứng dụng sẽ bị bỏ sót hoàn toàn.

## Các phép thử chẩn đoán

### 1\. Ma trận hai chiều để định vị tầng gây lỗi

Thay vì rà từng cấu hình một, tôi test chéo giữa đường đi của request và user agent:

| Đường đi của request | UA thường | UA Googlebot |
| --- | --- | --- |
| Qua domain công khai (edge) | `200` | **`500`** |
| Trực tiếp vào origin Cloud Run | `200` | `200` |

Lỗi 500 toàn site mà Googlebot nhìn thấy **chỉ** tồn tại tại giao điểm giữa public edge và Googlebot. Điều đó loại các page request thông thường của ứng dụng khỏi vai trò nguồn lỗi trực tiếp — nhưng chưa giải thích được điều kiện nào kích hoạt hành vi ở tầng edge.

### 2\. So sánh nhiều crawler để tìm đúng ranh giới

| Crawler | Có chuỗi "Googlebot" trong UA | Sau khi sự cố bắt đầu |
| --- | --- | --- |
| Googlebot | có | ngừng crawl nội dung trang |
| AdsBot-Google | không | vẫn hoạt động |
| bingbot | không | vẫn hoạt động |
| DuckDuckBot | không | vẫn hoạt động |

AdsBot-Google là dòng cho nhiều thông tin nhất: cũng là Google, cũng crawl, nhưng không bị ảnh hưởng. Vậy đây không phải "bot bị chặn", cũng không phải "site chết". Hành vi lỗi bám theo cách các request mang chuỗi `Googlebot` trong user agent được xử lý trên đường đi công khai.

### 3\. Dựng timeline từ log thay vì suy đoán

Hoạt động crawler diễn ra đều đặn tới một thời điểm rồi dừng tuyệt đối, trong khi các bot khác tiếp tục bình thường. Một snapshot tĩnh sẽ không cho thấy điều đó. Điểm gãy sắc nét trên timeline cho thấy một ngưỡng trạng thái đã bị vượt qua, chứ không phải suy giảm dần.

### 4\. Site đối chứng

Tôi chạy cùng bộ phép thử trên một website khác cùng kiến trúc. Nó không có hành vi 500 với Googlebot, qua đó loại bỏ giả thuyết "sự cố diện rộng toàn nền tảng".

### 5\. Từ triệu chứng ở edge tới dependency thật sự

Sau khi loại các page request thông thường, tôi chuyển sang các dependency mà Googlebot kiểm tra _trước khi_ crawl — `/robots.txt` đầu tiên. Chính ở đây chuỗi lỗi lộ ra.

## Nguyên nhân gốc

Một regression phía ứng dụng **và** một cơ chế khuếch đại ở hosting edge. Không nửa nào tự nó giải thích được sự cố; chỉ khi ghép lại mới ra chuỗi lỗi hoàn chỉnh.

**Phía ứng dụng.** Sau khi site được nâng cấp sang luồng đa ngôn ngữ, các dot-path lạ như `/robots.txt` không còn rơi về 404 thuần nữa. Một phần logic i18n và 404 dùng **runtime-only request API trong ngữ cảnh render tĩnh**, khiến thứ lẽ ra là 404 bị đẩy thành HTTP 500. Đây là regression thật trong code, và tôi sửa trực tiếp phần này.

**Tại hosting edge.** Sau khi escalate lên nhà cung cấp cloud, phía họ xác nhận traffic của Googlebot đi qua một **bước xác minh crawler** bổ sung trước khi nội dung trang được crawl. Khi `/robots.txt` trả 5xx thay vì 404 hoặc 200 hợp lệ, bước xác minh đó thất bại và các page request của Googlebot nhận **synthetic 5xx sinh ra tại edge** — dù nội dung trang ở origin vẫn bình thường.

_Diagram: Chuỗi lỗi theo trình tự thời gian: một regression phía ứng dụng khiến /robots.txt trả 500; hosting edge xác minh robots.txt trước khi crawl; giai đoạn một, cache còn hiệu lực nên Googlebot vẫn crawl bình thường; cache hết hiệu lực; giai đoạn hai, edge trả synthetic 500 cho page request của Googlebot. Chuỗi rẽ hai nhánh: Googlebot thấy mọi page request thất bại và giảm crawl cho tới khi bản vá khôi phục, trong khi browser và các bot khác vẫn nhận 200 suốt thời gian đó._

Hai đặc điểm khiến case này khó truy vết. Tuổi thọ cache tách regression khỏi thời điểm sự cố lộ ra, nên đối chiếu với deploy gần nhất sẽ dẫn sai hướng. Và nhánh bên phải không bao giờ lỗi — đó là lý do site trông vẫn khoẻ mạnh với tất cả mọi người trừ Googlebot.

Cùng trình tự đó diễn đạt bằng lời:

1. **`/robots.txt` bắt đầu trả 500.** Lỗi nằm sâu trong luồng 404 và i18n nên không ai để ý — trang thông thường vẫn trả 200.
2. **Giai đoạn một: cache còn hiệu lực.** Googlebot vẫn crawl bình thường, vì chưa buộc phải đánh giá lại trạng thái của `robots.txt`.
3. **Giai đoạn hai: đánh giá lại, và khuếch đại.** Khi cache hết hiệu lực, edge bắt đầu trả synthetic 500 cho các page request của Googlebot.
4. **Googlebot giảm rồi ngừng crawl.** Từ góc nhìn của nó, site đang có vấn đề availability ở quy mô toàn site.
5. **Khắc phục cả phần triệu chứng lẫn phần nguyên nhân.**

Độ trễ hai giai đoạn đó chính xác là lý do việc đối chiếu với deploy gần nhất làm lệch hướng điều tra: regression và sự cố nhìn thấy được cách nhau đúng bằng tuổi thọ của một cache entry.

Điều làm case này khó chịu là: bug phía ứng dụng có thật, nhưng triệu chứng nặng nhất của nó lại xuất hiện ở một tầng khác và chỉ với đúng một crawler. Dừng điều tra ở bất kỳ tầng đơn lẻ nào cũng sẽ cho một kết luận không đầy đủ.

## Khắc phục

- Thêm **`public/robots.txt` tĩnh**, để file này không còn phụ thuộc vào logic routing hay i18n.
- Sửa **root not-found** để nó không phụ thuộc vào runtime path của i18n.
- **Ràng buộc segment lạ** để các dot-path không quen thuộc trả về 404 đúng chuẩn.

Hai nửa này làm hai việc khác nhau: file tĩnh là biện pháp giảm thiểu, cầm máu ngay lập tức; sửa routing mới là chữa thật.

## Kết quả

- **Phục hồi.** Ứng dụng trả lại đúng semantics cho các dot-path lạ, và production có một `robots.txt` tĩnh an toàn. Googlebot fetch lại thành công gần như ngay sau deploy, crawl trang hồi phục trong vòng vài phút.
- **Xác nhận từ nhà cung cấp.** Phía cloud provider xác nhận hành vi khuếch đại lỗi ở hosting edge và thừa nhận nó gây hiểu nhầm khi troubleshoot crawler.
- **Giá trị cho dự án.** Chấm dứt tình trạng đổ qua đổ lại giữa SEO, frontend và hạ tầng, bằng cách thay ý kiến bằng một chuỗi lỗi có bằng chứng từ đầu đến cuối.
- **Giá trị vượt ra ngoài dự án.** Bài học này được dùng để thiết kế guardrail cho các site khác cùng kiến trúc, đặc biệt ở các route phục vụ SEO như `/robots.txt` và `/sitemap.xml`.

## Hệ thống phòng ngừa

Sự cố phơi ra một khoảng trống giám sát: không có gì theo dõi các route tồn tại riêng để phục vụ crawler, nên một lỗi ở đó có thể tồn tại rất lâu mà không ai biết. Ba lớp, mỗi lớp bịt điểm mù của lớp kia:

| Lớp | Cơ chế | Bắt được gì | Điểm mù |
| --- | --- | --- | --- |
| Ngăn chặn | Smoke test trong CI/CD sau mỗi deploy, kiểm `/`, `/robots.txt` và `/sitemap.xml` bằng user agent Googlebot | Lỗi do code hoặc deploy, chặn ngay tại pipeline | Không chạy khi không có deploy |
| Chủ động | Synthetic monitoring định kỳ qua domain công khai với user agent tuỳ chỉnh, kiểm cả status **và** nội dung | Mọi nguyên nhân, kể cả thay đổi hạ tầng — và cả trạng thái "không còn traffic nào" | Dùng UA giả lập, không phải crawler thật |
| Quan sát | Log-based alert trên request log của hosting edge | Crawler thật đang thực sự nhận gì tại edge | Chỉ thấy được khi vẫn còn request |

Hai quyết định thiết kế đáng nêu rõ. Thứ nhất, các phép kiểm phải đi **qua domain công khai**, không phải URL origin — test origin sẽ bỏ qua đúng tầng đã gây ra sự cố. Thứ hai, chúng validate **nội dung body, không chỉ status code**: một `robots.txt` trả 200 nhưng chứa `Disallow: /` còn nguy hiểm hơn một file trả 500.

## Bài học rút ra

**Sự vắng mặt của dữ liệu cũng là dữ liệu — nhưng chỉ khi có thứ để đối chiếu.** Thứ phá được case này không phải một stack trace. Đó là việc một loại traffic biến mất khỏi origin trong khi mọi luồng khác vẫn bình thường.

**Một phép thử được thiết kế tốt hơn mười phép thử tuỳ tiện.** Ma trận hai chiều định vị đúng tầng chịu trách nhiệm cho một triệu chứng toàn site chỉ trong vài câu lệnh.

**Một lỗi nhỏ trở thành lỗi lớn khi nó nằm trên route phục vụ crawler.** Thiếu `robots.txt` thì vô hại. `/robots.txt` trả 5xx thì không.

**Phải dám sửa kết luận ban đầu của chính mình.** Giả thuyết đầu tiên của tôi nghiêng hẳn về hạ tầng. Điều tra tử tế cho thấy regression phía ứng dụng là một mắt xích thiết yếu trong chuỗi, và báo cáo cuối cùng phải phản ánh trung thực cả hai nửa, chứ không phải nửa tôi mong tìm thấy.

**Một sự cố được xử lý tốt kết thúc bằng một hệ thống, không phải một bản vá.** Giá trị bền vững nằm ở checklist, guardrail và observability được bổ sung sau đó.

## Kỹ năng thể hiện qua case này

Điều tra sự cố production · debug routing và i18n của Next.js · GCP — Cloud Run, Cloud Logging, Monitoring · troubleshoot hosting edge và CDN · hạ tầng SEO và hành vi crawler · thiết kế observability và alert · escalate với nhà cung cấp và trình bày kỹ thuật

## Dịch vụ liên quan

- [Hạ tầng Cloud](https://tmtuan.dev/vi/services/gcp-cloud-infrastructure)
- [Xử lý sự cố Production](https://tmtuan.dev/vi/services/production-troubleshooting)

## Dự án liên quan

- [Dr.Well-B](https://tmtuan.dev/vi/projects/dr-well-b)
- [TaxPal](https://tmtuan.dev/vi/projects/taxpal)
- [GO Inc](https://tmtuan.dev/vi/projects/go-inc)
- [Wonderia](https://tmtuan.dev/vi/projects/wonderia)

## Structured data (JSON-LD)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Article","@id":"https://tmtuan.dev/vi/articles/googlebot-500-firebase-hosting-nextjs#article","headline":"Truy vết HTTP 500 chỉ xảy ra với Googlebot, xuyên Next.js, Cloud Run và hosting edge","description":"Người dùng và mọi crawler khác nhận 200, riêng Googlebot nhận 500 trên toàn site. Nguyên nhân: regression ở luồng 404, bị khuếch đại bởi bước xác minh crawler ở edge.","datePublished":"2026-09-18","dateModified":"2026-09-18","inLanguage":"vi","url":"https://tmtuan.dev/vi/articles/googlebot-500-firebase-hosting-nextjs","mainEntityOfPage":"https://tmtuan.dev/vi/articles/googlebot-500-firebase-hosting-nextjs","image":"https://tmtuan.dev/_img/articles/googlebot-500-firebase-hosting-nextjs/googlebot-500-firebase-hosting-nextjs-cover.adc2a628-og.jpg","author":{"@type":"Person","@id":"https://tmtuan.dev/#person","name":"Tran Manh Tuan","url":"https://tmtuan.dev/en"}},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Trang chủ","item":"https://tmtuan.dev/vi"},{"@type":"ListItem","position":2,"name":"Bài viết","item":"https://tmtuan.dev/vi/articles"},{"@type":"ListItem","position":3,"name":"Truy vết HTTP 500 chỉ xảy ra với Googlebot, xuyên Next.js, Cloud Run và hosting edge","item":"https://tmtuan.dev/vi/articles/googlebot-500-firebase-hosting-nextjs"}]}]}
```
