• Gitea และบล็อกบนเซิร์ฟเวอร์ส่วนตัวถูกทราฟฟิก scraping กดดันจนมีการแจ้งเตือนดิสก์, CPU และหน่วยความจำต่อเนื่อง ผู้ดูแลจึงตั้งรับด้วยการผสาน การวิเคราะห์ log, Nginx และ Fail2Ban
  • ตามเกณฑ์ของ Zabbix ทราฟฟิกพุ่งสูงกว่าปกติมาก โดยค่าเฉลี่ยรายเดือนของ Nginx อยู่ที่ 8 requests ต่อวินาที และช่วงเลวร้ายที่สุดขึ้นไปถึง 20+ requests ต่อวินาที
  • สาเหตุไม่ใช่การไหลเข้าจากแหล่งเดียวแบบ Reddit หรือ Hacker News แต่ใกล้เคียงกับ distributed scraping ที่ IP หลายบล็อกมากวาด URL ของ www.lambdacreate.com และ krei.lambdacreate.com
  • Nginx ส่งคืน 403 ให้ user agent อันตรายที่รู้จัก และใช้การจำกัดจำนวนคำขอต่อ IP ส่วนไคลเอนต์ที่ทำให้เกิด 403 มากเกินไปจะถูก Fail2Ban บล็อก 24 ชั่วโมง
  • ณ เวลาที่เขียน รายการบล็อกเพิ่มขึ้นรวมเป็น 735 bans และโดยเฉพาะคำขอที่พยายามสร้าง tarball สำหรับทุก commit ของ repository สาธารณะใน Gitea เป็นตัวเพิ่มภาระให้เซิร์ฟเวอร์

ทราฟฟิก scraping ที่กดดันเซิร์ฟเวอร์ส่วนตัว

  • ทราฟฟิกบอตไม่พึงประสงค์หลั่งไหลเข้าพื้นที่อินเทอร์เน็ตส่วนตัวอย่างฉับพลัน จนกระทบบริการที่ผู้อ่านจริงควรเข้าถึงได้
  • บริการที่ทำดัชนีเพื่อการเก็บรักษาเว็บไซต์อย่าง Archive.org อยู่ในกลุ่มที่อนุญาต แต่ Amazon, Facebook, OpenAI และบอตสุ่มหลายรายถูกแยกเป็นกลุ่มที่นำคอนเทนต์ไปใช้เพื่อเป้าหมายของตนเอง
  • มองว่าการเก็บข้อมูลอินเทอร์เน็ตขนาดใหญ่ของบริษัทใหญ่ และความต้องการข้อมูลสำหรับฝึกโมเดล AI ยิ่งทำให้ แรงกดดันจาก scraping เพิ่มขึ้น
  • ทราฟฟิกนี้ไม่ใช่ผู้บริโภคจริงของ Lambdacreate แต่ถูกมองเป็นสิ่งรบกวนที่ลดความสามารถในการเข้าถึงของผู้อ่านมนุษย์

Zabbix ตรวจพบสัญญาณผิดปกติก่อน

  • สิ่งแรกที่แจ้งปัญหาคือ Zabbix โดยเกิดการเตือนว่าดิสก์สำหรับคอนเทนเนอร์เต็ม
  • ในสภาพแวดล้อมที่ใช้ LXD ได้ขยาย ZFS sparse file และปิดไซต์ชั่วคราวก่อนเปิดขึ้นใหม่ แต่สาเหตุหลักยังคงอยู่
  • หลังจากนั้น instance ของ Gitea ใช้ดิสก์จนหมดทุกวัน พร้อมสร้างข้อมูลวันละ 20–30GB
  • ในช่วงแรกมองว่าเป็นปัญหาที่ Gitea ไม่ได้เปิดใช้การล้าง archive ของ repository เป็นค่าเริ่มต้น จึงตั้งค่างานล้างข้อมูลแบบเข้มงวด
  • ไม่นานก็มีการเตือน CPU และหน่วยความจำตามมา การ git pull และ git push บน Gitea ทำได้ยากขึ้น และไคลเอนต์ weechat ก็รักษาการเชื่อมต่อไว้ไม่ได้

จำนวนคำขอพุ่งขึ้นระดับ 10 เท่าจากปกติ

  • เพราะมีการมอนิเตอร์แบบ out-of-band ไว้เพื่อเปรียบเทียบตัวชี้วัดในอดีตกับสถานะปัจจุบัน จึงยืนยันรูปแบบผิดปกติได้
  • ในแดชบอร์ด Zabbix ตัวชี้วัดหลักคือ จำนวนคำขอของ Nginx และกราฟ throughput ของเครือข่าย
  • ปริมาณคำขอเฉลี่ยของ Nginx ในรอบหนึ่งเดือนอยู่ที่ประมาณ 8 requests ต่อวินาที
  • ช่วงเลวร้ายที่สุดมีคำขอเข้ามา 20+ requests ต่อวินาที แม้จะดูน้อยเมื่อเทียบกับบริการขนาดใหญ่ แต่สำหรับเซิร์ฟเวอร์ส่วนตัวถือเป็น 10 เท่า ของปกติ จึงส่งผลมาก
  • ภาระการดูแลเซิร์ฟเวอร์เพิ่มขึ้น เพราะไม่ได้มีแค่จำนวนคำขอ แต่ยังมีการใช้ดิสก์และ CPU ที่เกี่ยวกับ Gitea เพิ่มขึ้นพร้อมกัน

ไล่ตรวจ log ด้วย lnav และ goaccess

  • เพื่อให้เซิร์ฟเวอร์อยู่ได้นานพอสำหรับตรวจ log จึงปิดคอนเทนเนอร์และ Nginx ชั่วคราวแล้วเริ่มวิเคราะห์
  • เครื่องมือที่ใช้คือ lnav และ goaccess
  • lnav แสดงไฟล์ log ในรูปแบบ TUI พร้อมสี และมีเลเยอร์ abstraction เหนือรูปแบบ log ทั่วไป ทำให้ query log ด้วย SQL ได้
  • ใน access.log ตรวจสอบโดยเน้นคำถามต่อไปนี้
    • มี IP ผู้เข้าชมทั้งหมดกี่รายการ
    • มีรูปแบบของ IP address หรือไม่
    • เป็นทราฟฟิกที่มาจาก referrer เฉพาะหรือไม่
    • ใช้ user agent ใดบ้าง
    • IP ใดเชื่อมโยงกับ user agent ใด
  • ผลการวิเคราะห์พบว่าไม่ใช่ “hug of death” ที่หลั่งไหลมาจาก referrer เดียว แต่เป็น IP หลายบล็อกที่กวาด URL ทั่วทั้งไซต์

ส่ง 403 ตาม user agent และจำกัดคำขอ

  • การรับมือแรกคือทำรายการ user agent ที่ก่อปัญหาใน Nginx แล้วส่งคืน 403
  • ตัวอย่าง configuration ใช้ map $http_user_agent $badagent เพื่อทำเครื่องหมาย agent อย่าง AdsBot-Google, Amazonbot, Amazonbot/0.1
  • ใน configuration หลักของ Nginx มีการ include กฎ user agent และตั้ง rate limit ต่อ IP ด้วย
  • ในการตั้งค่า virtual host มีพฤติกรรมดังนี้
    • ใช้การจำกัดคำขอด้วย limit_req zone=krei burst=20 nodelay;
    • หาก $badagent เป็นจริง จะบล็อกการเข้าถึงคอนเทนต์ด้วย return 403;
  • วิธีนี้ช่วยลดการประมวลผลฝั่ง backend ได้ แต่เซิร์ฟเวอร์ยังต้องรับคำขอ HTTP และจัดการ 403 ดังนั้นเมื่อมีคำขอพร้อมกันจำนวนมาก ภาระก็ยังเหลืออยู่

ทำให้การบล็อกไฟร์วอลล์อัตโนมัติด้วย Fail2Ban

  • หลังจาก log 403 สะสมแล้ว สามารถใช้ lnav ตรวจ IP ที่ไม่ซ้ำซึ่งได้รับ 403 ได้
  • goaccess ใช้วิเคราะห์ log ทั้งเก่าและปัจจุบันร่วมกัน เพื่อดูจำนวนคำขอที่เข้ามายังเซิร์ฟเวอร์และ endpoint ที่ถูกเล็งมากที่สุด
  • เพื่อปกป้องเซิร์ฟเวอร์จริง จึงเพิ่ม Fail2Ban เข้ามา
  • กฎ Fail2Ban เป็นรูปแบบง่าย ๆ ที่จับ IP ซึ่งทำให้เกิด response 403 มากเกินไปจาก Nginx access log
  • เวลาบล็อกตั้งไว้ที่ 86400 วินาที หรือ 24 ชั่วโมง
  • ผลลัพธ์ fail2ban-client status nginx-forbidden ณ เวลาที่เขียนมีดังนี้
    • ความล้มเหลวปัจจุบัน: 13
    • ความล้มเหลวรวม: 57135
    • ถูกบล็อกปัจจุบัน: 38
    • ถูกบล็อกรวม: 735

เป้าหมายจริงไม่ใช่บล็อก แต่เป็นการสร้าง tarball ของ Gitea

  • ท้ายที่สุดผู้อ่านก็กลับมาเข้าถึงบล็อกและบริการอื่นของ Lambdacreate ได้อีกครั้ง
  • ในสถานการณ์ที่ต้องกันทราฟฟิกหุ่นยนต์ แม้แต่การเขียนบทความบล็อกก็ยังทำได้ยาก
  • ทราฟฟิกที่เป็นปัญหาไม่ได้เป็นการ scrape บล็อก แต่เล็งไปที่ การสร้าง tarball ของทุก commit ใน repository สาธารณะแต่ละตัวของ instance Gitea
  • ในระยะยาวจะพิจารณาวิธีขยายรายการบล็อก หรือกำหนดข้อยกเว้นให้บริการที่ถูกต้องตามกฎหมายอย่าง Archive.org
  • จุดยืนคือไม่ต้องการให้คอนเทนต์หายไปจาก search engine แต่ก็ไม่อยากปล่อยให้กลายเป็นเชื้อเพลิงสำหรับการทำให้อินเทอร์เน็ตแย่ลงด้วย AI

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น