EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Network / AdSense บอก ads.txt "ไม่พบ" ทั้งที่ไฟล์อยู่ — ไล่ log พิสูจน์ทีละชั้น
Network

AdSense บอก ads.txt "ไม่พบ" ทั้งที่ไฟล์อยู่ — ไล่ log พิสูจน์ทีละชั้น

โดย Ton-Or ·8 ก.ค. 2026·อ่าน 9 นาที
AdSense บอก ads.txt "ไม่พบ" ทั้งที่ไฟล์อยู่ — ไล่ log พิสูจน์ทีละชั้น

"Google มองไม่เห็นไฟล์เรา" คือเคสที่เดาไปก็ผิดไป — วิธีเดียวที่ให้คำตอบชัวร์คือเดินตามเส้นทางเดียวกับ crawler แล้วเปิด access log ดูว่าเขาเคยมา แล้วได้อะไรกลับไป

พอดีหน้า Sites ของ AdSense ขึ้นสถานะ ads.txt ว่า "ไม่พบ" ทั้งที่ ssh เข้าไปดู ไฟล์อยู่ตรงนั้นชัดๆ เนื้อหาถูกต้อง คำถามแรกที่ผุดขึ้นมาคือ "หรือ firewall เราไปบล็อค crawler ของ Google?" — เซิร์ฟเวอร์ที่ผมดูแลมีทั้ง CSF, ModSecurity, ตัวกรอง bot อีกชั้น ผู้ต้องสงสัยเพียบ

แทนที่จะเดา ผมไล่พิสูจน์ทีละชั้นจนเจอคำตอบ (สปอยล์: ไม่มีใครบล็อคเลย) — วิธีไล่นี่แหละที่อยากแชร์ เอาไปใช้กับเคส "Google มองไม่เห็นไฟล์เรา" ได้ทุกแบบ IP ในบทความเป็นค่าสมมติ (203.0.113.10)

ลำดับการพิสูจน์ชั้น 1ไฟล์อยู่จริง?→ชั้น 2origin กรอง UA?→ชั้น 3ผ่าน CF edge?→ชั้น 4access log ชี้ขาด

ชั้นที่ 1: ไฟล์อยู่จริงไหม เสิร์ฟถูกไหม

cat /home/user/domains/example.org/public_html/ads.txt
# google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0
stat -c '%y' .../ads.txt   # ดูวันที่สร้างไฟล์ไว้ด้วย — จะสำคัญตอนท้าย

ชั้นที่ 2: ยิงเทสด้วย UA ของ Google

ตัวกรอง bot ส่วนใหญ่ดูที่ User-Agent เพราะฉะนั้นต้องเทสด้วย UA ที่ Google ใช้จริง:

IP=203.0.113.10   # IP เซิร์ฟเวอร์เรา
for ua in 'curl/8.0' 'Mediapartners-Google' \
          'Mozilla/5.0 (compatible; Google-adstxt)' \
          'Mozilla/5.0 (compatible; Googlebot/2.1)'; do
  code=$(curl -sk --resolve example.org:443:$IP -A "$ua" \
         -o /dev/null -w '%{http_code}' https://example.org/ads.txt)
  echo "[$code] $ua"
done

ได้ 200 ทุก UA แสดงว่า origin ไม่กรอง — แต่ยังสรุปไม่ได้ เพราะเว็บอยู่หลัง Cloudflare ซึ่ง Google วิ่งผ่าน CF ไม่ได้วิ่งตรงมาหาเรา

ชั้นที่ 3: เทสผ่าน Cloudflare edge จริง

จุดพลาดคลาสสิกครับ: เทสจากเซิร์ฟเวอร์ตัวเอง DNS อาจ resolve ลัดเข้า localhost ไม่ผ่าน CF ต้องบังคับ resolve ไป IP ของ CF edge ให้เดินเส้นเดียวกับที่ Google เดิน:

dig +short example.org A          # ได้ IP CF เช่น 104.21.x.x
curl -sk --resolve example.org:443:104.21.x.x \
  -A 'Mozilla/5.0 (compatible; Googlebot/2.1)' \
  -D - https://example.org/ads.txt | head -20
# HTTP/2 200 / content-type: text/plain / cf-cache-status: DYNAMIC + เนื้อไฟล์ถูกต้อง

อย่าลืมเทส redirect ด้วย เพราะ crawler เริ่มที่ http:

curl -sk -A 'Mediapartners-Google' -o /dev/null \
  -w '%{http_code} -> %{redirect_url}\n' http://example.org/ads.txt
# 301 -> https://example.org/ads.txt   (hop เดียว โดเมนเดิม = โอเคตาม spec)

และ www / non-www ต้องได้ไฟล์เดียวกันทั้งคู่

ชั้นที่ 4: หลักฐานชี้ขาด — access log

ทุกอย่างข้างบนคือ "ตอนนี้เข้าได้" แต่คำถามจริงคือ "Google เคยมา แล้วได้อะไรกลับไป" — log ตอบได้:

zgrep -h 'ads.txt' /var/log/nginx/domains/example.org.log* | grep -i google
# 66.249.79.1  "GET /ads.txt HTTP/1.1" 301 162  Googlebot   <- เริ่มที่ http
# 66.249.79.6  "GET /ads.txt HTTP/2.0" 200 85   Googlebot   <- ตาม redirect มา ได้ไฟล์
# หา 4xx/5xx:
zgrep -h 'ads.txt' ...log* | grep -i google | awk '$9!~/200|301/'
# (ว่าง = Google ไม่เคยโดนปฏิเสธเลย)
เกร็ดที่ 1: ขนาดใน log ไม่ตรงขนาดไฟล์

response ให้ Googlebot ขนาด 85 bytes ทั้งที่ไฟล์เรา 59 bytes — อย่าเพิ่งตกใจว่าเสิร์ฟผิดไฟล์ครับ นั่นคือ gzip ของไฟล์ 59 bytes (ไฟล์เล็กมาก บีบแล้ว overhead ทำให้ใหญ่ขึ้น) crawler ส่ง Accept-Encoding: gzip มา log เลยบันทึกขนาดหลังบีบ

เกร็ดที่ 2: request เดียวโผล่สอง log

เครื่องที่รัน nginx คั่นหน้า apache — request เดียวโผล่ทั้งสอง log ฝั่ง nginx บอกส่ง 59 bytes (ไฟล์ถูก) ฝั่ง apache บอก 4738 bytes (HTML ของแอป) ไล่จนพบว่า nginx เสิร์ฟไฟล์ static ให้ client เองแล้ว ส่วนสำเนา request ที่ proxy ไป apache คำตอบถูกทิ้ง ไม่เคยถึง client — พิสูจน์ด้วยการยิง 1 request ที่ UA ไม่ซ้ำใคร (-A 'TRACE-1') แล้ว grep ทั้งสอง log เทียบกัน ถ้าไม่พิสูจน์ตรงนี้คงนั่งแก้ผีไปอีกนาน

สรุปคดี: ไม่มีใครบล็อค — มันคือ "สถานะค้าง"

หลักฐานประกอบกัน:

  • ไฟล์ ads.txt เพิ่งถูกสร้างตอน rebuild เว็บ (ดูจาก stat)
  • สถานะ "ไม่พบ" ใน AdSense ประทับเวลาก่อนหน้านั้นไม่นาน — คือผลเช็คจากรอบที่ไฟล์ยังไม่มีอยู่จริง
  • สถานะหน้า Sites ของ AdSense ไม่ใช่ realtime — refresh ห่างเป็นวันถึงหลายสัปดาห์ โดยเฉพาะไซต์ใหม่
  • log ยืนยัน Google fetch รอบใหม่ได้ 200 ไปแล้ว

รอสองสามวัน สถานะพลิกเป็นเขียวเองครับ ไม่ต้องแก้อะไรที่เซิร์ฟเวอร์เลย

ลำดับเหตุการณ์ของคดีรอบเช็คเก่าไฟล์ยังไม่มีผล: ไม่พบrebuild เว็บสร้าง ads.txtดูได้จาก statGooglebot มาเอาhttp: 301https: 200หน้า Sitesยังขึ้น ไม่พบรอพลิกเป็นเขียวป้ายสถานะค้างจากรอบแรก ไม่ใช่ realtime ส่วน access log ยืนยันว่า Google ได้ 200 แล้ว
ผลเช็ครอบเก่าตอนไฟล์ยังไม่มีค้างอยู่บนหน้า Sites ทั้งที่ Googlebot มาเอาไฟล์ใหม่ได้ 200 แล้ว คดีนี้ไม่มีใครบล็อค

บทเรียน

  1. "Google มองไม่เห็น" อย่าเพิ่งโทษ firewall — ไล่จาก log ไม่ใช่จากความกลัว
  2. เทสต้องเดินเส้นเดียวกับ crawler: ผ่าน CF edge, เริ่มที่ http, ใช้ UA จริง, เทสทั้ง www/non-www
  3. ขนาดใน log ไม่ตรงขนาดไฟล์ ไม่ได้แปลว่าเสิร์ฟผิด — คิดถึง gzip ก่อน
  4. สถานะใน dashboard ของ Google มี lag เสมอ — ให้น้ำหนักกับ access log ของเรามากกว่าป้ายสถานะของเขา

ส่วนตัวผมถือคติเดียวกับทุกเคส forensics: อย่าแก้อะไรจนกว่าจะมีหลักฐานว่ามันพังจริง เคสนี้ถ้ารีบไปรื้อ firewall ตามความกลัว ได้เสียของแน่ ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

อยากให้เราทำให้ไหม?

ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า

คุยเรื่องงานกับเรา

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย