Website trước khi lên domain thật thường có một bản demo để chủ site duyệt giao diện, đội QA kiểm thử và đo tốc độ. Bản demo chạy trên subdomain dạng *.demo.example.com, nằm cùng balancer với site thật. Một rủi ro hay bị xem nhẹ: trang demo bị Google index toàn bộ, xuất hiện trên kết quả tìm kiếm và trùng nội dung với site chính. Tài liệu này phân tích vì sao lớp chặn trong code ứng dụng dễ hỏng, so sánh ba cơ chế chặn (robots.txt, thẻ meta noindex, header X-Robots-Tag), hướng dẫn đặt lớp chặn ở tầng balancer, gỡ URL đã lỡ bị index và cân nhắc dùng Basic Auth.
1. Vì sao trang demo bị Google index
Tình huống điển hình: site demo có cơ chế chặn ở tầng code, gồm file public/robots.txt và thẻ meta robots trong layout. Vấn đề là cơ chế này nằm trong repo của ứng dụng. Chỉ cần một lần deploy ghi đè robots.txt bằng bản của production, hoặc một lập trình viên quên điều kiện "chỉ in meta noindex khi môi trường là demo", lớp bảo vệ biến mất mà không ai hay. Không có cảnh báo, không có lỗi nào cho biết site đang mở cửa cho Google index, cho tới khi chính các trang demo hiện ra trên kết quả tìm kiếm.
Hậu quả khi trang demo bị Google index không chỉ là xấu hổ:
- Nội dung trùng lặp: Google phải chọn giữa bản demo và bản thật, đôi khi chọn sai, làm site thật mất thứ hạng.
- Lộ dữ liệu thử: dữ liệu mẫu, bài viết nháp, trang chưa hoàn thiện có thể hiện ra công khai.
- Gỡ chậm: chặn xong không có nghĩa là kết quả biến mất ngay. Trang đã được Google index chỉ rời chỉ mục khi Googlebot crawl lại từng URL.
Nguyên tắc rút ra: lớp chặn index cho môi trường demo không được phụ thuộc vào code của từng app. Nó phải nằm ở nơi mọi request đều đi qua và không bị deploy ghi đè. Trong mô hình Cloud VPS ba tầng, nơi đó là balancer.
2. Ba cơ chế chặn Google index: khác nhau ở đâu
Nhiều người dùng lẫn lộn "chặn crawl" và "chặn index". Theo hướng dẫn chặn lập chỉ mục bằng noindex của Google Search Central, đây là hai việc khác nhau:
| Cơ chế | Chặn cái gì | Điểm yếu |
|---|---|---|
robots.txt với Disallow: / | Chặn crawl: bot không tải nội dung trang | Không chặn Google index. URL vẫn có thể lên kết quả tìm kiếm (không có mô tả) nếu có link từ nơi khác trỏ tới |
Thẻ <meta name=robots content="noindex"> | Chặn index trang HTML chứa thẻ | Nằm trong code app, dễ quên hoặc bị ghi đè. Không áp dụng cho PDF, ảnh |
Header HTTP X-Robots-Tag: noindex | Chặn index mọi loại response | Phải cấu hình ở web server, cần kiểm tra header có thật sự được gửi |
Điểm dễ bị bỏ qua nhất: không dùng Disallow cùng lúc với noindex. Nếu robots.txt chặn crawl, Googlebot không bao giờ tải trang, nên không đọc được chỉ dẫn noindex trong thẻ meta hay header. Trang đã lỡ bị Google index sẽ nằm lại trong chỉ mục lâu hơn. Muốn gỡ, phải cho phép crawl để bot đọc được noindex.
Vì vậy X-Robots-Tag là lựa chọn phù hợp để chặn Google index: chặn đúng việc cần chặn, áp dụng cho mọi loại file, và đặt được ở tầng hạ tầng, ngoài tầm với của deploy.
3. Đặt X-Robots-Tag ở balancer bằng map theo host
Khi mọi domain demo có chung đuôi .demo.example.com, không cần sửa từng file cấu hình site. Dùng module map của nginx để tính giá trị header dựa trên $host, đặt trong một file duy nhất trên mỗi balancer, tên bắt đầu bằng 00- để được nạp trước các file cấu hình site:
# /etc/nginx/conf.d/00-demo-noindex.conf
map $host $demo_noindex {
default "";
"~*\.demo\.example\.com$" "noindex, nofollow";
}
more_set_headers "X-Robots-Tag: $demo_noindex";Cách hoạt động:
- Request tới
shop.demo.example.comkhớp regex, biến$demo_noindexnhận giá trịnoindex, nofollow, response có headerX-Robots-Tag. - Request tới domain thật rơi vào
default, biến rỗng. Header rỗng thì không được gửi, site thật không bị ảnh hưởng. - Khi chuyển demo sang domain thật, header tự hết vì
$hostkhông còn khớp. Ngược lại, site mới tạo trên domain demo được bảo vệ ngay, kể cả khi file cấu hình site viết tay hay sinh từ template cũ.
Vì sao more_set_headers mà không phải add_header
Cách tự nhiên nhất là đặt add_header X-Robots-Tag $demo_noindex; trong khối http {}. Cú pháp đúng, nginx -t báo OK, nhưng header thường không xuất hiện. Lý do nằm ở quy tắc kế thừa của chỉ thị add_header: khối server hay location đã tự khai bất kỳ add_header nào thì không kế thừa các add_header của cấp trên. File cấu hình site trên balancer gần như luôn có add_header Strict-Transport-Security cho HSTS, nên header ở cấp http bị bỏ qua hoàn toàn mà không báo lỗi.
Module headers-more không có quy tắc này: more_set_headers khai ở cấp http áp dụng cho mọi server bên dưới. Trên Debian 12, module có sẵn trong kho chính thức:
apt-get install -y libnginx-mod-http-headers-more-filter
ls /etc/nginx/modules-enabled/
# 50-mod-http-headers-more-filter.conf
# nginx.conf phải có dòng này, nếu không module cài xong vẫn không được nạp
grep -n 'modules-enabled' /etc/nginx/nginx.conf
# include /etc/nginx/modules-enabled/*.conf;
nginx -t && systemctl reload nginxNếu nginx.conf viết tay tối giản và thiếu dòng include /etc/nginx/modules-enabled/*.conf;, nginx -t sẽ báo unknown directive "more_set_headers". Đây là lỗi tốt: nó chặn reload, nginx tiếp tục chạy cấu hình cũ và site thật không bị gián đoạn. Chỉ cần nhớ rằng khi lỗi này xảy ra, lớp chặn Google index chưa hề được bật.
Kiểm tra lớp chặn Google index bằng curl
Đừng tin vào nginx -t, hãy tin vào header thực tế. Mỗi lần thay đổi, kiểm tra cả hai chiều: domain demo phải có header, domain thật phải không có:
$ curl -sI https://shop.demo.example.com/ | grep -i x-robots
x-robots-tag: noindex, nofollow
$ curl -sI https://example.com/ | grep -i x-robots
(không có dòng nào)
# kiểm tra cả file tĩnh, vì X-Robots-Tag áp dụng cho mọi loại response
$ curl -sI https://shop.demo.example.com/robots.txt | grep -i x-robots
x-robots-tag: noindex, nofollowMột phép thử quan trọng khác: cố tình đổi public/robots.txt của app demo sang Allow: /. Header vẫn có mặt vì nó không phụ thuộc vào file nào trong code. Đó chính là tính chất cần có: deploy ghi đè gì, lớp chặn Google index vẫn còn.
4. Gỡ các trang đã bị Google index bằng Search Console
Thêm header chỉ ngăn index từ nay về sau. Các URL đã bị Google index vẫn nằm đó cho tới khi Googlebot quay lại crawl và đọc thấy noindex. Để đẩy nhanh:
- Xác minh quyền sở hữu domain demo trên Search Console (bản ghi TXT trên DNS là nhanh nhất vì không cần đụng vào code).
- Dùng công cụ Removals (Xoá URL) với tiền tố
https://shop.demo.example.com/để ẩn tạm toàn bộ URL khỏi kết quả tìm kiếm. Theo tài liệu công cụ Removals của Search Console, yêu cầu này chỉ có hiệu lực khoảng 6 tháng, nên bắt buộc phải có noindex chặn phía sau. - Không chặn robots.txt trong thời gian chờ, để Googlebot crawl lại và thấy header noindex.
- Theo dõi báo cáo Pages: các URL chuyển dần sang trạng thái "Excluded by 'noindex' tag".
Removals là thuốc giảm đau, noindex mới là thuốc chữa. Chỉ dùng Removals mà không có noindex thì hết hiệu lực các trang demo sẽ quay lại.
5. Basic Auth cho domain demo: an toàn hơn nhưng có giá
HTTP Basic Auth chặn được cả bot lẫn người lạ, không cần quan tâm Google index có tôn trọng noindex hay không:
map $host $demo_auth {
default off;
"~*\.demo\.example\.com$" "Demo - can dang nhap";
}
# trong khối server hoặc http
auth_basic $demo_auth;
auth_basic_user_file /etc/nginx/.htpasswd-demo;Hai lưu ý. Thứ nhất, muốn tắt auth_basic cho domain thật thì giá trị phải đúng là từ khoá off. Theo tài liệu module auth_basic, mọi chuỗi khác, kể cả chuỗi rỗng, đều được hiểu là tên realm và bật xác thực, tức mọi site thật trên balancer sẽ bị đòi mật khẩu. Hãy thử trên một balancer ít site trước khi áp dụng diện rộng, vì lỗi ở đây ảnh hưởng người dùng thật chứ không chỉ chuyện Google index.
Thứ hai, demo thường còn dùng để đo tốc độ trước khi bàn giao. Google PageSpeed Insights và Lighthouse chạy từ máy chủ của Google, không gửi kèm được username/password, nên khoá demo bằng Basic Auth đồng nghĩa với không đo được điểm hiệu năng. Basic Auth hợp với demo chứa dữ liệu nhạy cảm, nơi bảo mật quan trọng hơn khả năng đo đạc.
| Tiêu chí | X-Robots-Tag ở balancer | Basic Auth |
|---|---|---|
| Chặn Google index | Có (Google tôn trọng noindex) | Có (bot không vào được) |
| Người lạ xem được | Được, nếu biết URL | Không |
| PageSpeed Insights / Lighthouse | Đo bình thường | Không đo được |
| Phụ thuộc code app | Không | Không |
| Rủi ro cấu hình sai | Thấp: sai thì header không có | Cao: sai giá trị off là khoá luôn site thật |
6. Checklist chặn Google index cho môi trường demo
- Lớp chặn nằm ngoài vùng deploy: header đặt ở balancer, không trông vào robots.txt hay layout của app.
- Quy ước tên miền là cấu hình: mọi demo dùng chung một đuôi domain thì một dòng regex bảo vệ tất cả; demo đặt lệch quy ước sẽ lọt lưới.
- Đừng tin cú pháp, hãy tin curl: kiểm tra cả chiều có header (demo) và chiều không có header (site thật), cả trang HTML lẫn file tĩnh.
- Không
Disallowkhi đang cần gỡ: để bot crawl lại và đọc noindex. - Chặn và gỡ là hai việc: noindex ngăn index mới, Search Console giúp gỡ nhanh cái đã lỡ bị Google index.
Cách tổ chức file conf.d theo từng domain trên balancer có trong bài Tầng Balancer: Nginx reverse proxy, SSL offload và định tuyến domain. File 00-demo-noindex.conf chỉ là thêm một lớp dùng chung đứng trước các file đó.
Bài tiếp theo
Pipeline deploy, đổi domain, chuyển VPS có rollback database. Gói các thao tác rủi ro nhất thành pipeline có backup trước, kiểm tra sau và tự quay lui khi lỗi, cùng một cái bẫy trong khối post của Jenkins có thể xoá mất bản backup cần dùng để rollback.
