นี่คือคู่มือการติดตั้ง ตั้งค่า และดูแลรักษา Arcivéo Security Monitor เนื้อหาแบ่งเป็นกลุ่ม ได้แก่ ภาพรวมทั่วไป การติดตั้งแดชบอร์ด การเชื่อมต่อเครื่องมือ ด้านความปลอดภัย โมดูลในตัว และการวินิจฉัยปัญหา คุณคัดลอกคำสั่งได้ด้วยปุ่มทางขวา
การติดตั้งแดชบอร์ดอยู่ในหน้าคู่มือทีละขั้นตอนแยกต่างหาก เลือกวิธี:
Arcivéo Security Monitor — แดชบอร์ดความปลอดภัยของเซิร์ฟเวอร์ รวบรวมข้อมูลจากเครื่องมือที่ติดตั้งไว้ (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco และอื่น ๆ) และแสดงผลในอินเทอร์เฟซเดียว พร้อมแดชบอร์ด แผนที่การโจมตี และหน้ารายละเอียดของแต่ละเครื่องมือ
Monitor ไม่ใช่เครื่องมือป้องกันเชิงรุก — ตัวมันเองไม่ได้บล็อกการโจมตี หน้าที่ของมันคือรวบรวมข้อมูลจากเครื่องมือที่ทำงานอยู่แล้วและนำเสนอในรูปแบบที่เข้าใจง่าย
มอนิเตอร์ทำงานในเครื่องเท่านั้น — ต้องติดตั้งบนเซิร์ฟเวอร์เครื่องเดียวกับที่ตรวจสอบ ไม่มีการใช้ SSH หรือ API ระยะไกลใด ๆ
คำสั่งทั้งหมด (fail2ban-client, ufw status, ipset list ฯลฯ) แดชบอร์ดจะรันในนามผู้ใช้ของเว็บเซิร์ฟเวอร์ (โดยทั่วไปคือ www-data ส่วนบนแผงควบคุมโฮสติ้งจะเป็นบัญชีของเว็บไซต์) ด้วยชุดสิทธิ์ที่จำกัดของ sudo — เฉพาะยูทิลิตีที่ระบุเท่านั้น ไม่มีสิทธิ์ root แบบทั่วไป ผลลัพธ์จะถูกแยกวิเคราะห์และแสดงในเบราว์เซอร์
จังหวะการทำงานสองแบบ หน้าต่าง ๆ ของแผงควบคุมจะสอบถามเครื่องมือ ในขณะที่คุณเปิดหน้านั้น — คุณจึงเห็นสถานะปัจจุบันเสมอ นอกจากนี้ยังมีงานเบื้องหลังที่ทำงานตามกำหนดเวลา (cron):
รายการงานทั้งหมดอยู่ในหัวข้อ “งาน cron ทั้งหมดในที่เดียว”
คะแนนเริ่มต้นที่ค่าสูงสุดและลดลงตามแต่ละปัญหาที่ตรวจพบ:
PermitRootLogin yes) — −20PasswordAuthentication yes) — −10X11Forwarding, MaxAuthTries มากกว่า 3 หรือทุกบัญชีอ่าน sshd_config ได้ — −5TRACE อยู่ หรือไม่มีเฮดเดอร์ Strict-Transport-Security หรือ X-Frame-Options — −5สรุป: 80+ = ปลอดภัย, 60–79 = ควรระวัง, <60 = เสี่ยง
WebAuthn — มาตรฐานการยืนยันตัวตนโดยไม่ใช้รหัสผ่านผ่านคีย์ฮาร์ดแวร์ รองรับ YubiKey, Touch ID, Face ID, Windows Hello, Passkey
หลังเข้าสู่ระบบด้วยรหัสผ่าน ระบบจะขอการยืนยันผ่านคีย์ที่ลงทะเบียนไว้ แม้รหัสผ่านจะรั่วไหล ก็เข้าสู่ระบบไม่ได้หากไม่มีคีย์กายภาพหรือไบโอเมตริก
ในการตั้งค่า ให้เปิด คีย์ WebAuthn ในเมนูด้านข้าง แล้วกด “ลงทะเบียนคีย์” ควรลงทะเบียนคีย์สองอันพร้อมกัน: หากคีย์เพียงอันเดียวสูญหายหรือเสีย จะไม่สามารถเข้าสู่แดชบอร์ดด้วยคีย์นั้นได้
ช่องทางมีสี่แบบ: Telegram, Email, webhook และ พุช เข้าเบราว์เซอร์ ทั้งสี่เป็นอิสระต่อกัน — จะเปิดช่องทางใดก็ได้ หรือเปิดทั้งสี่ก็ได้ รายงานความปลอดภัยประจำวัน การแจ้งเตือนโหลด และสิ่งที่เซนเซอร์เหตุการณ์ตรวจพบ ล้วนส่งผ่านช่องทางเดียวกันนี้ ตั้งค่าเพียงครั้งเดียวที่นี่ ในส่วน “การตั้งค่า”
Telegram. ต้องใช้ โทเคนบอท และ chat id:
@BotFather → /newbot → รับ โทเคน รูปแบบ 123456:ABC...@userinfobot หรือเปิด https://api.telegram.org/bot<TOKEN>/getUpdates แล้วหา "chat":{"id":...}Email. เลือกได้สองวิธีใน “การตั้งค่า” → Email:
re_...) และโดเมนผู้ส่งที่ยืนยันแล้วWebhook ที่อยู่เดียวที่รับ POST ก็ครอบคลุม Slack, Discord, Mattermost, n8n และตัวจัดการที่คุณเขียนเอง “การตั้งค่า” → Webhook: วางที่อยู่แล้วเปิดสวิตช์
{"text": …} ส่วน Discord จะได้ {"content": …} (Discord ปฏิเสธข้อความที่ยาวเกิน 2000 อักขระ ข้อความจึงถูกตัดให้สั้นลง);text, event, severity, source, count, host, ts — ไม่ต้องมาแยกวิเคราะห์ตัวข้อความอีกการแจ้งเตือนแบบพุช ข้อความจะมาถึงเบราว์เซอร์โดยตรง และถ้าเพิ่มแผงควบคุมไว้บนหน้าจอหลักของโทรศัพท์ ก็จะแสดงเหมือนการแจ้งเตือนของแอปทั่วไป — ไม่ต้องมีบอตและไม่ต้องมีเมลเซิร์ฟเวอร์คั่นกลาง “การตั้งค่า” → การแจ้งเตือนแบบพุช: เปิดสวิตช์แล้วกด “เชื่อมต่ออุปกรณ์นี้” บนทุกอุปกรณ์ที่ต้องได้รับการแจ้งเตือน ตัวนับ “อุปกรณ์ที่เชื่อมต่อ” จะบอกว่ามีกี่เครื่อง
สถานะรายงาน: “เตือน” หรือ “ปกติ”. หัวข้อจะกลายเป็น “เตือน” เฉพาะเมื่อมีปัญหาจริงหรือมีการดำเนินการที่รออยู่: พบภัยคุกคามจาก ClamAV, ไฟล์เปลี่ยนแปลงใน AIDE, เหตุการณ์วิกฤติจาก Falco (Emergency/Alert/Critical ใน 24 ชม.ล่าสุด), บริการล่มใน Monit, ต้องรีบูต, SSL ใกล้หมดอายุ (≤14 วัน) หรือมีการอัปเดตความปลอดภัยรออยู่ ส่วนสัญญาณรบกวนพื้นหลัง — การเดารหัส SSH ของบอท, IP ที่ fail2ban แบนไว้, การแจ้งเตือนของ Suricata, คำเตือนของ Lynis และคำขอที่ ModSecurity สกัดไปแล้ว — จะไม่ ยกระดับสถานะ ดังนั้นตัวเลขเหล่านี้ในรายงานจึงไม่ได้หมายถึง “เตือน” ด้วยตัวมันเอง
โมดูลตรวจสอบแบบละเอียด (Lynis, UFW, ModSecurity, แผนที่การโจมตี, AIDE, ClamAV และอื่น ๆ) จะเปิดใช้งานได้เมื่อมีลิขสิทธิ์ที่ใช้งานได้ หากไม่มี แดชบอร์ด การตั้งค่า และบัญชีผู้ใช้จะยังทำงานได้ แต่โมดูลจะแสดงการ์ด “ต้องมีลิขสิทธิ์”
หลังจากซื้อในบัญชีผู้ใช้ คุณจะได้รับรหัสเปิดใช้งานรูปแบบ ARCIVEO-XXXX-XXXX-XXXX-XXXX คุณต้อง “เปิดใช้งาน” กับโดเมนของแผงควบคุมคุณ ซึ่งจะแปลงรหัสเป็นไฟล์ลิขสิทธิ์ที่ลงลายเซ็น (บล็อก [license]) เพื่อนำไปวางในแผงควบคุม
วิธีเปิดใช้งาน (3 ขั้นตอน):
my.arciveo.com → หัวข้อ “ลิขสิทธิ์” / “เปิดใช้งานลิขสิทธิ์” — คัดลอกรหัส ARCIVEO-…monitor.example.com) กดเปิดใช้งาน — ระบบจะสร้างไฟล์ลิขสิทธิ์ที่ผูกกับโดเมนนี้ และแสดงในช่องพร้อมปุ่ม “คัดลอก”แผงควบคุมจะตรวจสอบคีย์ด้วยการเข้ารหัส: ลายเซ็น การผูกกับโดเมน และวันหมดอายุ
APP_URL ใน config.php แล้วกรอกเฉพาะชื่อโฮสต์ — ไม่ต้องมี https:// และไม่ต้องมีคำนำหน้า www การเปิดใช้งานทำได้ครั้งเดียว: รหัสจะถูกแปลงเป็นลิขสิทธิ์สำหรับโดเมนที่กรอก และเปิดใช้งานซ้ำไม่ได้ — หากกรอกโดเมนผิด คีย์จะใช้กับแผงควบคุมของคุณไม่ได้ และรหัสจะถูกใช้ไปแล้ว จึงควรกรอกโดเมนอย่างระมัดระวัง
พารามิเตอร์หลักทั้งหมดของแดชบอร์ดถูกกำหนดไว้ในไฟล์เดียว config.php ที่อยู่ในรูท (ข้างโฟลเดอร์ public/) ในรูปค่าคงที่ define() ทั่วไป ไฟล์นี้ถูกสร้างขึ้นตอนติดตั้ง จำเป็นต้องแก้ด้วยมือน้อยครั้ง — ส่วนใหญ่เมื่อเปลี่ยนโดเมน ย้ายเซิร์ฟเวอร์ หรือเชื่อมต่อฐานข้อมูลใหม่ หลังแก้ไขทุกครั้งให้ รีสตาร์ท PHP-FPM (มิฉะนั้นการเปลี่ยนแปลงจะไม่มีผลเพราะ OPcache)
ใส่ค่าของคุณลงในจุดที่ไฮไลต์ไว้ ส่วนที่เหลือให้คงเดิม:
ฐานข้อมูล. ข้อมูลการเชื่อมต่อ MySQL/MariaDB:
DB_HOST — โฮสต์ของ DBMS เกือบทุกครั้งคือ localhost;DB_NAME — ชื่อฐานข้อมูลของแดชบอร์ด;DB_USER — ผู้ใช้ฐานข้อมูล (เข้าถึงได้เฉพาะฐานข้อมูลของตัวเอง);DB_PASS — รหัสผ่านของผู้ใช้รายนี้;DB_CHARSET — การเข้ารหัสของการเชื่อมต่อ ให้คงไว้ที่ utf8mb4.แอปพลิเคชัน.
APP_URL — ที่อยู่เต็มของแดชบอร์ด (เช่น https://monitor.example.com) ต้องตรงกับโดเมนที่เปิดใช้งานลิขสิทธิ์ไว้ มิฉะนั้นคีย์จะถูกปฏิเสธ (ดูหัวข้อ “ลิขสิทธิ์”);TIMEZONE — เขตเวลาของ PHP: มีผลเฉพาะกับวิธีที่แดชบอร์ดแสดงวันที่และเวลาเท่านั้น ไม่มีผลต่อเวลาที่รันงาน cron — ตรงนั้นใช้เขตเวลาของระบบ (ดู “งาน cron ทั้งหมด”).เวลาเซสชัน. SESSION_LIFETIME — เวลาหมดอายุของเซสชันขณะไม่มีการใช้งาน หน่วยวินาที (แบบเลื่อน: รีเซ็ตเมื่อมีกิจกรรม) ค่าเริ่มต้น 28800 = 8 ชั่วโมง หลังจากไม่มีการใช้งานเกินเวลานี้ แดชบอร์ดจะขอให้ล็อกอินใหม่ ตัวอย่างเช่น 3600 = 1 ชั่วโมง, 86400 = หนึ่งวัน.
การบันทึกข้อผิดพลาด. ข้อผิดพลาดจะไม่แสดงต่อผู้เข้าชมเด็ดขาด แต่จะถูกเขียนลงใน logs/php_errors.log — ดูได้ที่หน้า “บันทึกแอปพลิเคชัน” บรรทัดเหล่านี้ (display_errors=0, log_errors=1, พาธ error_log) โดยทั่วไปไม่จำเป็นต้องแก้ — ค่าถูกกำหนดไว้ในไฟล์โดยตรงและไม่ขึ้นกับ php.ini.
public/) และแดชบอร์ดนี้มีเว็บรูท (DocumentRoot) เป็นรูทของแดชบอร์ดเอง ไม่ใช่ public/ ตัวไฟล์เองไม่ “รั่ว”: ใน .htaccess ที่รูทมีการห้ามเข้าถึงไฟล์นี้อย่างชัดเจน (Require all denied) — เซิร์ฟเวอร์จะตอบ 403 แม้ไม่มีกฎนี้ ซอร์สก็ไม่รั่วอยู่ดี: นี่คือ PHP — เซิร์ฟเวอร์จะประมวลผลมัน ไม่ใช่ส่งออกเป็นข้อความ เผื่อไว้: อย่าอัปโหลดขึ้น repository สาธารณะ และอย่าส่งให้ฝ่ายสนับสนุนพร้อมรหัสผ่านจริง สิทธิ์ของไฟล์คือ 640.
แผงควบคุมถูกปิดด้วยการเข้าสู่ระบบด้วยรหัสผ่าน และถ้าเปิดใช้ ก็ยังมีตัวกรอง IP อีกชั้น แต่โปรแกรมใช้ทั้งสองอย่างนั้นไม่ได้ ระบบภายนอกจึงมีทางเข้าของตัวเอง — ที่อยู่สองรายการ สำหรับอ่านอย่างเดียว ป้องกันด้วยโทเคน โทเคนไม่เปลี่ยนแปลงอะไรบนเซิร์ฟเวอร์ ใช้ได้เพียงดึงค่าตัวเลขออกมา
การเปิดใช้งาน — “การตั้งค่า” → “API สำหรับอ่านอย่างเดียว”: สวิตช์ “เปิด API” โทเคนจะถูกสร้างอัตโนมัติเมื่อบันทึกครั้งแรก ปุ่ม “โทเคนใหม่” จะออกโทเคนอีกอัน และในขณะเดียวกันก็ตัดทุกคนที่ใช้โทเคนเดิมออกทันที
/api/status.php — JSON: คะแนนความปลอดภัย, สถานะของโมดูล, การวัดโหลดครั้งล่าสุดพร้อมโปรเซสที่กินทรัพยากรมากที่สุด และเหตุการณ์ด้านความปลอดภัยใน 24 ชั่วโมง;/api/metrics.php — ตัวเลขชุดเดียวกันในรูปแบบข้อความของ Prometheus (เมตริก arciveo_*: arciveo_security_score, arciveo_fail2ban_banned, arciveo_cpu_busy_pct เป็นต้น)หากไคลเอนต์ของคุณตั้งส่วนหัวไม่ได้ ระบบก็รับโทเคนเป็นพารามิเตอร์ได้เช่นกัน — ?token=… แต่พึงทราบว่าในรูปแบบนี้โทเคนจะไปปรากฏในบันทึกการเข้าถึงของเว็บเซิร์ฟเวอร์ การใช้ส่วนหัวจึงดีกว่า
Prometheus บล็อกสำเร็จรูปสำหรับ scrape_configs:
api disabled — API ถูกปิดในการตั้งค่า คำขอที่ถูกปฏิเสธจะถูกบันทึกลงบันทึกแอปพลิเคชันพร้อม IP ของผู้ส่ง การไล่เดาโทเคนจึงมองเห็นได้ในหน้า “บันทึกแอปพลิเคชัน”
แผงควบคุมติดตั้งแยกกันบนแต่ละเซิร์ฟเวอร์ และตอบคำถาม “เครื่องนี้เป็นอย่างไร” ได้ดี แต่ไม่ตอบคำถาม “เครื่องทั้งหมดของฉันเป็นอย่างไร” — ด้วยเหตุนี้ แผงควบคุมแต่ละชุดจึงสามารถส่งสรุปสั้น ๆ ไปยังบัญชีผู้ใช้ ซึ่งจะเห็นเซิร์ฟเวอร์ทั้งหมดในรายการเดียว
สิ่งที่ต้องนำมาจากบัญชีผู้ใช้ my.arciveo.com → หัวข้อ “เซิร์ฟเวอร์ของฉัน”: ที่นั่นจะออก โทเคน (รูปแบบ fk_…) และระบุที่อยู่ผู้รับไว้ว่า https://my.arciveo.com/api/fleet.php โทเคนมีหนึ่งอันต่อหนึ่งบัญชี — ใช้ร่วมกันได้กับทุกเซิร์ฟเวอร์ของคุณ
สิ่งที่ต้องตั้งค่าในแผงควบคุม — “การตั้งค่า” → “ภาพรวมเซิร์ฟเวอร์”: ที่อยู่ผู้รับ, โทเคน, ชื่อเซิร์ฟเวอร์ (ชื่อที่จะปรากฏในรายการ ถ้าเว้นว่างจะใช้โดเมนของแผงควบคุม) และสวิตช์ “ส่งสรุป” ปุ่ม “ส่งเดี๋ยวนี้” จะตรวจการเชื่อมต่อทันทีโดยไม่ต้องรอกำหนดเวลา
จากนั้นสรุปจะถูกส่งผ่าน cron ทุก 15 นาที:
สิ่งที่ถูกส่งออกไปมีอะไรบ้าง: ชื่อและโดเมนของเซิร์ฟเวอร์, ระบบปฏิบัติการ, เวลาทำงาน, เวอร์ชัน PHP; คะแนนความปลอดภัย; สถานะของโมดูล (UFW, จำนวน jail ของ Fail2ban, การแบนวันนี้, CrowdSec, Suricata และ Falco ทำงานอยู่หรือไม่, ภัยคุกคามจาก ClamAV, การเปลี่ยนแปลงของ AIDE, ดัชนี Lynis, การอัปเดตที่รออยู่, ต้องรีบูตหรือไม่, จำนวนวันก่อนใบรับรอง SSL หมดอายุ, จำนวนพอร์ตเปิดที่อันตราย); การวัดโหลดครั้งล่าสุด (load, CPU, RAM, ดิสก์, inodes); ตัวนับเหตุการณ์ใน 24 ชั่วโมง และเหตุการณ์วิกฤตล่าสุด ในสรุปไม่มีบันทึก ไม่มีรหัสผ่าน และไม่มีเนื้อหาของไฟล์
sudo crontab -l) และคำตอบของปุ่ม “ส่งเดี๋ยวนี้” ข้อผิดพลาดในการส่งจะถูกบันทึกลงบันทึกแอปพลิเคชันด้วยป้าย FLEET — ตรงนั้นจะเห็นว่าโทเคนถูกปฏิเสธ (HTTP 401) หรือการเชื่อมต่อไม่สำเร็จตั้งแต่ต้น
UFW (Uncomplicated Firewall) — อินเทอร์เฟซแบบง่ายสำหรับ nftables/iptables ปิดพอร์ตขาเข้าทั้งหมด ยกเว้นที่อนุญาตไว้อย่างชัดเจน หน้า “ไฟร์วอลล์ UFW” แสดงสถานะและกฎต่าง ๆ
ufw enable ต้องอนุญาต SSH (ufw allow OpenSSH) ก่อนเสมอ ไม่เช่นนั้นคุณจะเข้าถึงเซิร์ฟเวอร์ไม่ได้
deny จะไม่ถือว่าเข้าถึงได้จากภายนอก
Skipping adding existing rule — ไม่ใช่ข้อผิดพลาด UFW แจ้งแบบนี้เพื่อบอกว่ามีกฎเดียวกันนี้อยู่แล้ว จึงไม่เพิ่มซ้ำ เมื่อรันการตั้งค่าอัตโนมัติซ้ำ (ซึ่งเป็นแบบ idempotent) ข้อความนี้เป็นเรื่องปกติ — ไม่ต้องดำเนินการใด ๆ
บล็อก IP โดยอัตโนมัติเมื่อจำนวนครั้งที่พยายามเข้าสู่ระบบล้มเหลวเกินกำหนด วิเคราะห์ล็อกของ SSH, nginx, Apache และบริการอื่น ๆ
การติดตั้งพื้นฐานอยู่ด้านบน ตรงนี้คือคอนฟิกใช้งานจริงที่ให้ jail ทำงานหลายสิบตัวและบล็อกได้หลายพันรายการ ได้แก่ การตั้งค่าทั่วไป jail สำคัญ ๆ และการแบน IP อันตรายอัตโนมัติจากรายการ ipsum
ไฟล์ /etc/fail2ban/jail.local — การตั้งค่าทั่วไปและ jail ที่สำคัญที่สุด:
ignoreip ต้องใส่ IP ของคุณและเครือข่ายที่เชื่อถือได้ ไม่เช่นนั้นอาจแบนตัวเองได้ หลังแก้ไข: sudo fail2ban-client reload
โหลดบล็อกลิสต์ ipsum อัตโนมัติผ่าน root-cron (sudo crontab -e): level 1 (IP กว่า 100,000 รายการ) จะโหลดเข้าเซ็ต ipsum ซึ่งถูกตัดที่ไฟร์วอลล์ (รายละเอียดอยู่ในหัวข้อ “บล็อกลิสต์ IPset”):
ipsum เพราะเป็นชื่อที่แดชบอร์ดอ่าน (การ์ด “IPset ipsum”) ระดับ: levels/1.txt — ครอบคลุมสูงสุด, levels/3.txt — แม่นยำกว่า (3+ แหล่งข้อมูล)
ทำไม “Monitor ความปลอดภัย” จึงแบ่งเป็นสองโซน การป้องกันทำงานสองระดับ และแดชบอร์ดไม่ปนกัน:
sshd, apache-*, nginx-* ฯลฯ) และ ผู้กระทำผิดซ้ำร้ายแรง (jail recidive — ผู้ที่โดนแบนมาแล้วหลายครั้ง) นี่คือ IP ที่บุกเข้ามาหาคุณ จริง ๆ — อยู่บนแผนที่การโจมตีและ “ไทม์ไลน์”ipset ipsum ตัดทิ้ง ที่ไฟร์วอลล์ ด้วยกฎ DROP ที่อยู่เหล่านี้ส่วนใหญ่ไม่เคยแตะเซิร์ฟเวอร์ของคุณเลย — ถูกตัดล่วงหน้า ตัวนับ “IPset ipsum” แสดงจำนวนที่ตัดไปเชิงป้องกันความต่างง่าย ๆ: เชิงรับ — “พวกนี้โจมตีแล้วโดนแบน”, เชิงรุก — “พวกนี้ถูกบล็อกก่อนจะได้ลงมือ” เมื่อก่อนใน recidive จะยัด list-3 ipsum เข้าไปแบบเทียม (จึงมีการแบ่งแบบเก่า “recidive จากรายการ”); ตอนนี้ recidive มีเฉพาะผู้กระทำผิดซ้ำจริง ๆ ส่วนเชิงรุกอยู่ที่ไฟร์วอลล์ทั้งหมด
ipsum — รายการ IP อันตรายสาธารณะที่อัปเดตทุกวัน มอนิเตอร์จะแสดงจำนวนที่อยู่ที่โหลดมาบนแดชบอร์ดและแผนที่การโจมตี และนำมาคิดในคะแนนความปลอดภัย (−10 หากยังไม่ได้โหลดชุดนี้)
ตัวเลือกขั้นต่ำที่ไม่ใช้ fail2ban — ชุด ipsum แยกต่างหากพร้อมการบล็อกผ่าน iptables:
@reboot พร้อมกันนั้นคำสั่ง create … -exist จะกำหนดลิมิต maxelem 300000 (ค่าเริ่มต้น 65536 — level 1 ใส่ไม่พอ จะขึ้น “Hash is full”):
ipsum และหากไฟร์วอลล์ถูกจัดการโดยตัวติดตั้ง (VPS ใหม่ — โปรไฟล์ “เต็มรูปแบบ”/“แบบเบา”) ก็จะเชื่อมชุดนี้เข้ากับ UFW ด้วยกฎ DROP — ทราฟฟิกจาก IP เหล่านี้จะถูกบล็อกจริง กฎนี้อยู่ หลัง ESTABLISHED,RELATED ดังนั้นการเชื่อมต่อปัจจุบัน (รวมถึง SSH ของคุณ) จะไม่ขาด — จะตัดเฉพาะการเชื่อมต่อใหม่จากรายการเท่านั้น ชุดจะถูกกู้คืนเมื่อบริการ ipsum-load.service โหลด ก่อน ไฟร์วอลล์ (มิฉะนั้น UFW จะไม่ทำงาน) และอัปเดตด้วยครอนเวลา 04:00 บน เซิร์ฟเวอร์ที่ตั้งค่าไว้แล้ว (มีแผงควบคุม, ไฟร์วอลล์ของตัวเอง) ตัวติดตั้งจะไม่ยุ่งกับไฟร์วอลล์ — ตรงนั้น ipsum จะยังเป็นเพียงรายการสำหรับแดชบอร์ดและแผนที่การโจมตี ส่วนกฎ DROP หากต้องการก็เพิ่มเองได้ (ตัวเลือกขั้นต่ำด้วย iptables … --match-set ipsum … -j DROP — ด้านบน) เมื่อติดตั้งอัตโนมัติไม่ต้องทำอะไรเองเลย
ตัวแทน Fail2ban สมัยใหม่ที่มาพร้อม threat intelligence แบบรวมกลุ่ม: ทั้งการบล็อกจากชุมชนและกฎของคุณเอง ต้องใช้ bouncer แยกต่างหากเพื่อนำการบล็อกไปใช้กับไฟร์วอลล์
systemctl is-active crowdsec) เริ่มด้วย: sudo systemctl enable --now crowdsec; หากล้มให้ดู sudo journalctl -u crowdsec -n 30 ใช้กฎเดียวกันนี้กับทุกเซอร์วิสที่มีสถานะ “ไม่ทำงาน” (Suricata, Falco, Monit, MySQL)
stream halted / การบล็อกไม่ถูกนำไปใช้ นี่คือ api-key ที่ไร้เจ้าของ: bouncer ถูกลบออกจาก cscli bouncers list แล้ว แต่คีย์เก่าของมันยังค้างอยู่ใน /etc/crowdsec/bouncers/*.yaml ให้ลงทะเบียน bouncer ใหม่และใส่คีย์ล่าสุด:
AIDE (Advanced Intrusion Detection Environment) จะสร้างสแนปช็อตของระบบไฟล์และรายงานการเปลี่ยนแปลงใน /etc, /bin, /usr ในทุกครั้งที่ตรวจสอบ หลังการติดตั้งต้องเริ่มต้นฐานข้อมูล (aideinit) เสมอ
aideinit เทอร์มินัลจะค้างที่บรรทัด Running aide --init... นาน 5–15 นาที — เป็นเรื่องปกติ (การแฮชทั้งระบบไฟล์ ทำให้ดิสก์ทำงานหนัก) อย่ากด Ctrl+C หยุด หากกระบวนการ “ค้าง” แต่ไม่แสดงอะไร — อาจกำลังรอคำตอบต่อคำถามที่ซ่อนอยู่ Overwrite existing aide.db.new [Yn]? (ให้กด Y) ตรวจสอบการทำงานจากอีกเซสชัน: pgrep -af aide
aideinit: “21_aide_spamassassin … printf: invalid number” (return code 20) — เป็นบั๊กที่รู้จักกันของส่วน config ของ AIDE ใน Ubuntu 22.04 ฐานข้อมูลจะไม่ถูกสร้าง ให้ย้ายสนิปเปตที่เสียออกแล้วลองใหม่:
aideinit หรือ (Ubuntu 24.04) ไดเรกทอรี /var/lib/aide ถูกสร้างในโหมด 700 และ www-data เข้าถึงไม่ได้ — แก้ด้วย sudo chmod 755 /var/lib/aide (ดูบล็อกด้านบน) “ยังไม่มีการตรวจสอบ” = มีฐานข้อมูลแล้ว แต่ยังไม่เคยตรวจสอบ — ไม่ใช่ข้อผิดพลาด มอนิเตอร์อ่านผลลัพธ์จาก /var/log/aide/aide.log
/etc/cron.daily/aide มาตรฐานบน Ubuntu/Debian ใหม่อาจไม่เขียน /var/log/aide/aide.log ในรูปแบบที่ต้องการ (และ aide.wrapper ก็ไม่มีอยู่ในนั้นแล้ว) วิธีที่แน่นอนกว่าคือเพิ่ม cron ของคุณเองพร้อมระบุ --config อย่างชัดเจน — มันจะเขียนล็อกในนาม root ในโหมด 644 และมอนิเตอร์อ่านได้โดยไม่ต้องเพิ่มกลุ่ม:
chmod 755 /var/lib/aide และ cron ตรวจสอบเวลา 02:00 — ไม่ต้องทำอะไรด้วยตนเอง
sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
โปรแกรมสแกนไวรัสสำหรับ Linux มีประโยชน์อย่างยิ่งในการตรวจสอบ /var/www เพื่อหา PHP-shell และโค้ดอันตราย
enable --now หรือไม่? สาเหตุที่พบบ่อยสามข้อ:
1. ยังมีบรรทัด Example ค้างอยู่ในไฟล์ตั้งค่า — clamd จะไม่ยอมเริ่มทำงานตราบใดที่ยังมีบรรทัดนี้:
2. ยังไม่ได้ดาวน์โหลดฐานข้อมูลลายเซ็น — clamd จะไม่เริ่มทำงานหากไม่มีมัน:
3. กำลังโหลดอยู่ — clamd โหลดลายเซ็นราว 8 ล้านรายการเข้าหน่วยความจำใช้เวลา 30–60 วินาที รอสักครู่แล้วตรวจสอบ: systemctl is-active clamav-daemon (สถานะ activating → ยังโหลดอยู่)
sudo journalctl -u clamav-daemon -n 30 --no-pager
clamd เพียงเก็บลายเซ็นไว้ในหน่วยความจำเท่านั้น ตัวมันเองไม่ได้สแกนอะไรตามกำหนดเวลา แดชบอร์ดแสดงผลลัพธ์ของการสแกนตามกำหนด จึงต้องมี cron ที่คอยสแกนและเขียนบันทึก การติดตั้งอัตโนมัติจะติดตั้งตัวห่อ /usr/local/bin/clamav-scan.sh และ cron เวลา 01:30 — หลังจากรันครั้งแรก “ไฟล์ที่ตรวจสอบ” และ “สแกนล่าสุด” จะมีข้อมูล รันทันทีโดยไม่ต้องรอกำหนดเวลา: sudo /usr/local/bin/clamav-scan.sh
Linux Malware Detect (LMD) — โปรแกรมสแกนมัลแวร์ที่เน้นภัยคุกคามบนเว็บ: PHP shell, เว็บแบ็คดอร์, ตัวดาวน์โหลด ใช้เอนจินของ ClamAV และเสริมด้วยลายเซ็นของตัวเอง
maldet --report
update-rc.d: error: unable to read /etc/init.d/maldet — ซึ่งไม่เป็นอันตราย maldet ไม่ได้ใช้ init.d การอัปเดตลายเซ็นและการสแกนจะทำงานผ่าน /etc/cron.daily/maldet หากด้านล่างเห็น installation completed แสดงว่าติดตั้งเรียบร้อยแล้ว
apt แต่อยู่ที่ /usr/local/maldetect และเมื่อเปิด open_basedir การตรวจสอบว่ามีอยู่จะทำผ่าน shell — ดูหัวข้อ “หน้าเว็บว่างเปล่าทั้งที่มีข้อมูลบนเซิร์ฟเวอร์”
ระบบตรวจจับการบุกรุกบนเครือข่าย: วิเคราะห์ทราฟฟิกในระดับแพ็กเก็ตและรู้จักลายเซ็นการโจมตีนับพันรูปแบบ เสริมการทำงานของ ModSecurity (ตัวนั้นทำงานที่ระดับ HTTP ส่วน Suricata ทำงานที่ระดับ TCP/IP)
/var/log/suricata/eve.json ในสิทธิ์ root โดยตั้งไดเรกทอรีเป็นโหมด 750 ทำให้เว็บเซิร์ฟเวอร์ (www-data) อ่านไม่ได้ ให้เปิดสิทธิ์เข้าถึงไดเรกทอรี ส่วนไฟล์ภายในยังคงถูกป้องกันอยู่:
ดักจับ system call ผ่าน eBPF/kernel module และตรวจจับความผิดปกติแบบเรียลไทม์: shell จาก nginx, การอ่าน /etc/passwd โดยเว็บโปรเซส, การเขียนลง /bin เป็นต้น
journalctl -u falco (ไม่ต้องใช้ sudo — ผ่านกลุ่ม systemd-journal) ตรวจสอบว่า www-data อยู่ในกลุ่มนี้ — ดู “การตั้งค่า sudo” (ข้อ 2) ในหน้าการติดตั้งด้วยตนเอง
/etc/passwd, การเขียนลงไดเรกทอรีระบบ) ศูนย์เหตุการณ์วิกฤตในหนึ่งวันบนเซิร์ฟเวอร์ที่สงบ คือสภาวะที่ปกติดี
journalctl ต้องมีสิทธิ์เข้าถึง journal; เพื่อให้แดชบอร์ดเห็นเหตุการณ์ได้อย่างเสถียร การติดตั้งอัตโนมัติจะเปิด file_output ของ Falco → /var/log/falco/falco.log และตั้งค่า UMask=0022 ให้บริการ (เว็บเซิร์ฟเวอร์อ่านล็อกได้) สำหรับการติดตั้งใหม่ ไม่จำเป็นต้องตั้งค่านี้ด้วยตนเอง
ModSecurity — เว็บไฟร์วอลล์ (WAF) สำหรับ Apache หรือ Nginx บล็อกการโจมตีในระดับแอปพลิเคชัน: SQL injection, XSS, การเดินย้อนพาธ, สแกนเนอร์
IncludeOptional /etc/modsecurity/*.conf แต่แพ็กเกจวางไว้เฉพาะ modsecurity.conf-recommended เท่านั้น ซึ่งไม่เข้าเงื่อนไข *.conf หากไม่คัดลอกไปเป็น modsecurity.conf ค่า SecRuleEngine จะยังคงเป็น Off: โมดูลถูกโหลด กฎ CRS ถูกโหลด แต่ทราฟฟิกไม่ถูกตรวจสอบและไม่มีการสร้างล็อกการตรวจสอบ โหมดกลาง DetectionOnly จะเพียงบันทึกเหตุการณ์ลงล็อกโดยไม่บล็อกคำขอ — แดชบอร์ดจะแสดงเป็นสีเหลือง
การเข้าถึงล็อกการตรวจสอบของแดชบอร์ด ล็อก /var/log/apache2/modsec_audit.log เป็นของ root (สิทธิ์ 640) เว็บยูสเซอร์อ่านไม่ได้ แดชบอร์ดดึงข้อมูลผ่านตัวห่อ (wrapper) — ให้สร้างมันขึ้นมา:
SecRuleEngine ตัวสุดท้าย ที่ไม่มีการเยื้อง: บรรทัดที่เยื้องอยู่ภายในบล็อก <LocationMatch>/<Directory> (เช่น การปิด WAF สำหรับ phpMyAdmin) และไม่ได้กำหนดโหมดโดยรวมwww-data ส่วนใน HestiaCP พูลของไซต์ทำงานจากเจ้าของไซต์ (เช่น admin) — ตรวจสอบด้วย grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.confX-Forwarded-For เฉพาะทรานแซกชันที่มีกฎทำงานเท่านั้นที่จะเข้าสถิติ: ไดเรกทีฟ SecAuditLogRelevantStatus จะเขียนคำตอบ 4xx/5xx ทุกรายการลงล็อกการตรวจสอบ ดังนั้น 403/500 ธรรมดาก็จะถูกบันทึกไปด้วย — แดชบอร์ดจะไม่นับว่าเป็นเหตุการณ์ WAF---RULES--- จำเป็นสำหรับส่วน “กฎที่ใช้งานอยู่ทั้งหมด” — แดชบอร์ดจะแสดงไม่เพียงกฎที่ทำงาน แต่กฎ CRS ที่โหลดทั้งหมด + กฎกำหนดเอง สามพาธในลูป for f in … คือตำแหน่งทั่วไปของกฎ CRS และส่วนเพิ่มเติมในเครื่อง หากคุณจัดวางต่างออกไป (แพ็กเกจวางไฟล์ในไดเรกทอรีของตัวเอง หรือกฎกำหนดเองไม่ได้อยู่ใน /etc/modsecurity/custom-rules.conf) ให้ค้นหาพาธจริงด้วยคำสั่ง sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null แล้วเติมลงในรายการ หากตัวห่อเป็นเวอร์ชันเก่า (ไม่มีส่วนนี้) — ส่วนดังกล่าวจะแสดงเพียงคำเตือนว่า “ไม่พร้อมใช้งาน” ส่วนที่เหลือของหน้ายังทำงานเหมือนเดิม
Auditd (Linux Audit Daemon) บันทึกการเรียกใช้ระบบในระดับเคอร์เนล: การเข้าและออกจากระบบ, คำสั่ง sudo, ความพยายามยืนยันตัวตนที่ล้มเหลว, การเปลี่ยนแปลงไฟล์ Monitor จะแสดงการเข้าสู่ระบบ, ความพยายามที่ล้มเหลว และคำสั่ง sudo ของวันนี้
ausearch (/usr/sbin/ausearch) และเมื่อจำเป็นจะอ่านจาก /var/log/audit/audit.log ด้วยคำสั่ง tail ทั้งสองต้องอยู่ใน sudoers
เฝ้าดูบริการต่าง ๆ (nginx, php-fpm, mysql ฯลฯ) และรีสตาร์ตให้เมื่อบริการล่ม สามารถส่งการแจ้งเตือนทางอีเมลได้
monit status ใน /etc/monit/monitrc ต้องเปิดใช้อินเทอร์เฟซ HTTP (บล็อก set httpd พร้อม allow localhost) มิฉะนั้น monit status จะคืนค่าเป็นข้อผิดพลาด
monitrc บรรทัด set httpd ถูกคอมเมนต์ไว้ (ค่าเริ่มต้นมาเป็น # set httpd port 2812 …) ให้ยกเลิกคอมเมนต์บล็อกนี้และอนุญาต localhost (2) การเปิด httpd เพียงอย่างเดียวไม่ได้เฝ้าดูอะไรเลย — Monit จะนับเฉพาะสิ่งที่ระบุด้วยสแตนซา check เท่านั้น หากไม่มี รายการจะว่างเปล่าแม้อินเทอร์เฟซจะทำงานอยู่ก็ตาม คอนฟิกขั้นต่ำที่ใช้งานได้:
conf.d ที่พร้อมใช้พร้อม httpd บนพอร์ต 2812 และชุดการตรวจสอบไว้ให้ — บนการติดตั้งใหม่ไม่ต้องตั้งค่าเองด้วยมือ
PSAD วิเคราะห์ล็อกของ iptables และตรวจจับการสแกนพอร์ตกับการโจมตีเครือข่าย โดยกำหนดระดับภัยคุกคาม (1–5) ให้แต่ละแหล่งที่มา เสริมการทำงานของ fail2ban และ Suricata
psad --Status (ต้องอยู่ใน sudoers) หากไม่เปิดการบันทึกล็อกของ iptables หน้านี้จะว่างเปล่า — ถือเป็นเรื่องปกติตราบใดที่ยังไม่มีการสแกน
Mandatory Access Control จำกัดว่าโปรแกรมสามารถเข้าถึงไฟล์และทรัพยากรใดได้บ้าง แม้จะถูกเจาะระบบไปแล้วก็ตาม โดยใน Ubuntu/Debian จะใช้ AppArmor เป็นค่าเริ่มต้น (โดยทั่วไปติดตั้งและเปิดใช้งานอยู่แล้ว)
aa-status (ต้องอยู่ใน sudoers) แสดงจำนวนโปรไฟล์ในโหมด enforce/complain และโปรเซสที่ไม่มีโปรไฟล์
“โปรไฟล์ที่โหลด” มากกว่า enforce + complain ถือเป็นเรื่องปกติ ใน AppArmor 4.x (Ubuntu 24.04 ขึ้นไป) มีโหมด unconfined เพิ่มเข้ามา คือโปรไฟล์ถูกโหลดเข้าเคอร์เนลแล้วแต่ไม่ได้จำกัดอะไร Ubuntu ตั้งค่าแบบนี้ให้กับโปรไฟล์นับสิบสำหรับโปรแกรมที่ใช้ user namespaces (เบราว์เซอร์ ไคลเอนต์ torrent และอื่น ๆ ทำนองนั้น) เมื่อมีโปรไฟล์แบบนี้อยู่ การ์ด “โปรไฟล์ที่โหลด” จะเปลี่ยนเป็นสีเหลืองอำพันและแสดงจำนวน — เช่น unconfined: 90 จาก 120 ที่โหลดและ 26 ที่อยู่ใน enforce ที่ป้องกันได้จริงมีเพียงโปรไฟล์ใน enforce เท่านั้น ส่วนบน Ubuntu 22.04 (AppArmor 3.x) ไม่มีโหมดนี้ ตัวเลขจึงตรงกันเสมอ
unconfined ให้เป็น enforce ควรทำอย่างรู้ตัวเท่านั้น เพราะมันถูกปิดไว้ไม่ใช่เพราะข้อผิดพลาด แต่เพราะไม่เช่นนั้นตัวโปรแกรมเองจะทำงานผิดพลาด ส่วนโปรไฟล์ใน complain เป็นอีกเรื่องหนึ่ง คือมีการเขียนกฎไว้แล้วเพียงแต่ยังไม่ได้บังคับใช้
debsums ตรวจสอบว่าไฟล์ของแพ็กเกจที่ติดตั้งตรงกับ checksum จากรีโพซิทอรี — เพื่อตรวจจับไบนารีระบบที่ถูกแทนที่ (เสริมกับ AIDE) การตรวจสอบเต็มรูปแบบใช้เวลา 1–2 นาที จึงถูกรันผ่าน cron ส่วนแดชบอร์ดจะอ่านผลลัพธ์จาก data/debsums/debsums.log และจัดหมวดหมู่ให้เอง (สำคัญเฉพาะไบนารีและไลบรารี)
งานนี้อยู่ใน root cron (sudo crontab -e) สคริปต์ครอบสำเร็จรูป debsums-scan.sh จะวางไว้ใน /usr/local/bin/ (chmod +x; ดูสรุปงาน cron) และเขียนรายงานลงใน data/debsums/ ของแดชบอร์ดเอง
สคริปต์ครอบ debsums-scan.sh จะค้นหา data/ ของแดชบอร์ดเอง — ไม่ต้องระบุพาธ
/etc/ (คอนฟิก) และ /usr/share/ (ทรัพยากร) บนเซิร์ฟเวอร์มักเป็นเรื่องปกติ — แดชบอร์ดจะทำเครื่องหมายด้วยสีแยกต่างหาก สิ่งที่น่ากังวลคือการเปลี่ยนแปลงไบนารีและไลบรารี (/bin, /sbin, /usr/lib เป็นต้น) — การ์ด “ไบนารี / ไลบรารี” จะแสดงเฉพาะรายการเหล่านั้น
Lynis รันแบบแมนนวลหรือผ่าน cron รายงานต้องบันทึกไว้ในโฟลเดอร์ data/lynis/ ของโปรเจกต์ — มอนิเตอร์จะอ่านไฟล์ lynis-report.dat
lynis-scan.sh ในเบื้องหลังจากแดชบอร์ดโดยตรง (ไม่ต้องรอ cron): แสดง “กำลังสแกน…” และอัปเดตรายงานเองเมื่อเสร็จ ในการนี้ผู้ใช้เว็บต้องมีบรรทัด sudoers สำหรับรันสคริปต์ — ตัวติดตั้งจะเพิ่มให้อัตโนมัติใน /etc/sudoers.d/monitor หากติดตั้งแดชบอร์ดแบบแมนนวล/ก่อนหน้านี้ ให้เพิ่มบรรทัดด้วยผู้ใช้เดียวกับที่ระบุไว้ในไฟล์อยู่แล้ว:
Logwatch ต้องบันทึกรายงานประจำวันลงในโฟลเดอร์ data/logwatch/ ของโปรเจกต์ในรูปแบบ .txt โดย Monitor จะแสดงรายงานล่าสุดและคลังรายงาน
การเฝ้าระวังเครือข่ายไม่ต้องติดตั้ง — เป็นหน้าในตัวของแดชบอร์ด แสดงสถานะเครือข่ายของเซิร์ฟเวอร์จากแหล่งข้อมูลในเครื่อง:
/proc/net/dev;ip;ss;journalctl -kแหล่งข้อมูลสามอย่างแรกทำงาน โดยไม่ต้องใช้ sudo จึงเห็นอินเทอร์เฟซ ทราฟฟิก การเชื่อมต่อ และพอร์ตได้ทันที ส่วนบล็อก “เหตุการณ์เคอร์เนล” ใช้ journalctl -k ซึ่งอ่านผ่านกลุ่ม systemd-journal (“การตั้งค่า sudo” ข้อ 2) ไม่ต้องใช้ sudo ตรวจสอบว่าผู้ใช้เว็บเข้าถึงได้ครบ:
UFW BLOCK จะไม่ปรากฏที่นี่ — อยู่ในหน้า “ไฟร์วอลล์ UFW” และ “แผนที่การโจมตี” บล็อกว่างพร้อมเครื่องหมายถูกสีเขียว = ในรอบวันไม่มีความขัดข้องของเครือข่าย
หน้านี้แสดงข้อมูลสามอย่าง:
df); แถบจะเป็นสีแดงเมื่อ ≥90%;lsblk) เฉพาะที่มีอยู่จริง (ซ่อน loop/snap);smartctl)พื้นที่และรายการอุปกรณ์ทำงานได้ทันทีโดยไม่ต้องตั้งค่า สำหรับ SMART ต้องมีแพ็กเกจ smartmontools เว็บโพรเซสไม่มีสิทธิ์เข้าถึงอุปกรณ์ดิสก์โดยตรง จึงต้องเก็บข้อมูล SMART ผ่าน cron ลงในไฟล์ data/disk/smart.txt แล้วแดชบอร์ดจะอ่านไฟล์นั้น
งานนี้อยู่ใน root cron (sudo crontab -e) สคริปต์ห่อ smart-scan.sh ที่เตรียมไว้จะวางไว้ใน /usr/local/bin/ (chmod +x; ดูสรุปงาน cron) และเขียนลงใน data/disk/ ของแดชบอร์ดเอง
สคริปต์ห่อ smart-scan.sh จะค้นหา data/ ของแดชบอร์ดเอง ไม่ต้องระบุพาธ ภายในนั้น lsblk -e7,11 จะยกเว้น loop/cdrom
หน้านี้แสดงประวัติโหลดของเซิร์ฟเวอร์ในช่วง 24 ชั่วโมงที่ผ่านมา — Load Average, การใช้งาน CPU และการรอ I/O, RAM/Swap, ทราฟฟิกเครือข่าย (รับ/ส่ง), ดิสก์ I/O (อ่าน/เขียน), พื้นที่ดิสก์และ inodes ที่ใช้ไป, file descriptor ที่เปิดอยู่และการเชื่อมต่อ MySQL รวมถึงจำนวนการเชื่อมต่อ TCP และโปรเซสในปัจจุบัน ค่าเริ่มต้นคือช่วง 24 ชั่วโมง ปุ่มด้านบนจะสลับเป็น 7 วัน หรือ 30 วัน
ข้อมูลถูกเก็บโดย cron/collect_metrics.php — ทุก 5 นาทีจะบันทึกสแนปช็อต “ดิบ” ของตัวนับหนึ่งชุด (/proc/loadavg, /proc/meminfo, /proc/stat, /proc/net/dev, /proc/diskstats, df/df -i, /proc/sys/fs/file-nr, SHOW GLOBAL STATUS LIKE 'Threads_connected') ลงในตาราง system_metrics ของฐานข้อมูล ส่วนเปอร์เซ็นต์และอัตราความเร็วนั้นหน้านี้คำนวณเองจากส่วนต่างระหว่างสแนปช็อตที่อยู่ติดกัน (พื้นที่ดิสก์/inodes/descriptor/การเชื่อมต่อ MySQL เป็นค่า ณ ขณะนั้น ไม่มีการคำนวณใหม่) ไม่ต้องใช้ sudo — แหล่งข้อมูลอ่านได้โดยไม่ต้องมีสิทธิ์ root
ความลึกของการเก็บข้อมูลสองระดับ สแนปช็อต “ดิบ” ทุกห้านาทีจะอยู่ได้หนึ่งวัน (บวกอีกหนึ่งชั่วโมงเป็นส่วนเผื่อ เพื่อให้จุดที่เก่าที่สุดบนกราฟยังมีจุดก่อนหน้าไว้คำนวณ) ทุกชั่วโมงที่จบลงจะถูกยุบเป็นแถวเดียว ชุดข้อมูลรายชั่วโมงนี้เก็บไว้ 30 วัน และมุมมอง “7 วัน” กับ “30 วัน” ก็อ่านจากชุดนี้เอง ประวัติหนึ่งเดือนจึงใช้เพียงราว 720 แถว แทนที่จะเป็นราว 8600 แถว
ตัวห่อ collect-metrics-all.sh (ดูสรุปงาน cron) จะค้นหาอินสแตนซ์ทั้งหมดของแดชบอร์ดที่ติดตั้งบนเซิร์ฟเวอร์เอง แล้วรัน cron/collect_metrics.php ของแต่ละอินสแตนซ์ในนามของเจ้าของเว็บไซต์
โปรเซสที่กินทรัพยากรมากที่สุด ใต้กราฟมีตารางสองตาราง แสดงห้าโปรเซสที่ใช้ CPU มากที่สุด:
ทั้งสองตารางอธิบายช่วง 24 ชั่วโมงเสมอ แม้กราฟจะแสดงทั้งเดือน เพราะสแนปช็อตของโปรเซสมีอยู่เฉพาะในแถวห้านาที และแถวเหล่านั้นไม่ได้เก็บไว้นานเกินหนึ่งวัน
ps, สคริปต์ PHP ที่เก็บข้อมูล และสาย cron/sudo ที่อยู่เหนือมัน) จะถูกคัดออกจากรายการ — ไม่เช่นนั้นมันจะครองแถวบนสุดของทุกสแนปช็อต เพราะ ps ในจังหวะที่เพิ่งเริ่มทำงานจะแสดงค่าเกือบ 100 % ส่วนงาน cron อื่น ๆ ที่รันในนาทีเดียวกันยังคงปรากฏ และนั่นแหละคือสิ่งที่ตารางนี้มีไว้เพื่อแสดง
การแจ้งเตือนโหลด (หัวข้อ “การตั้งค่า” → “การแจ้งเตือนโหลด”) — เมื่อค่าของ CPU/RAM/ดิสก์/inodes เกินเกณฑ์ แผงควบคุมจะส่งการแจ้งเตือนผ่านทุกช่องทางที่เปิดไว้ (Telegram, Email, webhook, พุช — ช่องทางเดียวกับรายงานประจำวัน ไม่ต้องเปิดอะไรเพิ่มสำหรับการแจ้งเตือน) และส่งอีกครั้งเมื่อค่ากลับสู่ปกติ ตราบใดที่ค่ายังเกินเกณฑ์อยู่ ระบบจะไม่ส่งซ้ำ ๆ การแจ้งเตือนครั้งถัดไปจะมาก็ต่อเมื่อผ่านวงจร “กลับสู่ปกติ → เกินเกณฑ์อีกครั้ง” แล้วเท่านั้น
collect_metrics.php ตัวเดียวกันทุกครั้งที่รัน (ทุก 5 นาที) — ไม่ต้องใช้ cron แยก สถานะ “แจ้งเตือนไปแล้ว / ยังไม่แจ้ง” เก็บไว้ใน data/alerts_state.json ส่วนเกณฑ์อยู่ในการตั้งค่าของแดชบอร์ด
รายงานประจำวันตอบคำถามว่า “เซิร์ฟเวอร์เป็นอย่างไรบ้าง” ส่วนเซนเซอร์ตอบอีกคำถามหนึ่ง — “เมื่อครู่นี้เกิดอะไรขึ้น” ทุก 5 นาทีมันจะสอบถามแหล่งข้อมูลที่เร็ว และบันทึกเฉพาะสิ่งที่เปลี่ยนไปนับจากการตรวจครั้งก่อน หน้า “เหตุการณ์ด้านความปลอดภัย” ในเมนูจะแสดงรายการสิ่งที่ตรวจพบ
การตรวจสอบที่ช้า — Lynis, debsums, การอัปเดตแพ็กเกจ, อายุของใบรับรอง SSL — เซนเซอร์จะไม่ยุ่งด้วย เพราะตัวเลขเหล่านั้นเปลี่ยนวันละครั้งอยู่แล้ว และยังคงเป็นหน้าที่ของรายงานประจำวัน
สิ่งที่มันสังเกตเห็น — เก้าแหล่ง:
[Priority: 1] จะยกระดับสิ่งที่พบขึ้นเป็นวิกฤต;FOUND ใหม่ในบันทึกการสแกน;root (วิกฤต) และการเข้าสู่ระบบจากที่อยู่ที่ไม่เคยพบมาก่อน (คำเตือน);เครื่องมือที่ยังไม่ได้ติดตั้ง หรือที่แผงควบคุมอ่านบันทึกไม่ได้ ก็เพียงแค่เงียบไป — นั่นไม่ใช่ข้อผิดพลาดและไม่ใช่เหตุการณ์
data/secwatch_state.json) และการทำงานรอบแรกจะเขียนแค่เครื่องหมายนั้น มิฉะนั้น พอเปิดการเฝ้าระวังก็จะได้รับการแจ้งเตือนเกี่ยวกับทุกอย่างที่บันทึกสะสมไว้หลายเดือน
การตั้งค่า — “การตั้งค่า” → “การเฝ้าระวังเหตุการณ์”:
23-7 ที่จะไม่ส่งคำเตือนการแจ้งเตือนส่งผ่านช่องทางเดียวกับรายงานประจำวัน (Telegram, Email, webhook, พุช) — ไม่ต้องเปิดอะไรเพิ่ม สิ่งที่พบทั้งหมดจะถูกบันทึกลงรายการ ไม่ว่าจะ ส่งการแจ้งเตือนออกไปหรือไม่ และเก็บไว้ 90 วัน
รายการเหตุการณ์ ตัวกรอง: ช่วงเวลา (24 ชั่วโมง, 7, 30 หรือ 90 วัน), ความสำคัญ และแหล่งที่มา แสดง 500 รายการล่าสุด ปุ่ม “ตรวจเดี๋ยวนี้” เรียกการตรวจแบบเดียวกับที่ cron ทำ — สะดวกทันทีหลังตั้งค่า จะได้ไม่ต้องรอห้านาที ปุ่มนี้ยังบอกเหตุผลด้วยเมื่อไม่ได้ส่งการแจ้งเตือน (“ต่ำกว่าเกณฑ์ความสำคัญ”, “ช่วงเวลาเงียบ”, “ยังไม่ได้ตั้งค่าช่องทางแจ้งเตือนใดเลย”) ตัวนับสีแดงข้างรายการเมนูคือจำนวนเหตุการณ์วิกฤตใน 24 ชั่วโมงที่ผ่านมา
การ์ดที่อยู่. การคลิกแถวในรายการเหตุการณ์หรือในบล็อก ที่อยู่ที่เกี่ยวข้องกัน จะเปิดทุกอย่างที่ทราบเกี่ยวกับที่อยู่หนึ่ง ได้แก่ ลำดับเวลาของเหตุการณ์ ประเทศ และข้อสรุปในบรรทัดแรก แถวของรายการจะเปิดการ์ดเมื่อเหตุการณ์นั้นเกี่ยวกับที่อยู่เดียวเท่านั้น หากมีหลายที่อยู่ ลิงก์คือที่อยู่ภายในแถวนั้นเอง ข้อสรุปมีสี่แบบ:
ใต้ลำดับเวลาคือบล็อก สิ่งที่เกิดขึ้นบนเซิร์ฟเวอร์ในเวลาเดียวกัน ซึ่งเป็นเหตุการณ์ที่ไม่มีที่อยู่เลย AIDE ไม่ทราบว่าใครแก้ไขไฟล์ ClamAV ไม่ทราบว่าใครนำไฟล์ติดเชื้อเข้ามา แสดงเฉพาะเหตุการณ์ที่อยู่ในช่วงที่ที่อยู่นี้มีความเคลื่อนไหวและอีกหกชั่วโมงหลังจากนั้น การเข้าสู่ระบบคู่กับสิ่งที่ตามมานี่เองที่แยกความพยายามออกจากการเข้าถึงที่เกิดขึ้นจริง
กำหนดเวลา งานนี้ใส่ไว้ใน crontab ของ root (sudo crontab -e) โดยเหลื่อมจากการเก็บเมตริก 2 นาที เพื่อไม่ให้ทั้งสองงานเริ่มพร้อมกัน:
php cron/security_watch.php โดยตรง wrapper จะค้นหาการติดตั้งแผงควบคุมทั้งหมดบนเซิร์ฟเวอร์ แล้วเรียกการตรวจ ในนามเจ้าของเว็บไซต์ — ด้วยสิทธิ์ sudo ชุดเดียวกับที่แผงควบคุมใช้จากเว็บ การเรียกโดยตรงจาก crontab ของ root จะสร้างไฟล์สถานะ data/secwatch_state.json ที่เป็นของ root และปุ่ม “ตรวจเดี๋ยวนี้” ในแผงควบคุมจะใช้งานไม่ได้อีกต่อไป
หน้า “เว็บเซิร์ฟเวอร์” แยกวิเคราะห์บันทึกการเข้าถึง และแสดงว่ามีคำขอกี่รายการ ส่วนไหนจบด้วยข้อผิดพลาด และใครเป็นผู้ส่ง ModSecurity ตอบคำถามว่า “อะไรถูกบล็อก” ส่วนหน้านี้ตอบคำถามว่า “มีอะไรเข้ามาที่เว็บไซต์บ้าง”
สิ่งที่เห็น: จำนวนคำขอ, RPS, สัดส่วนข้อผิดพลาด, ตัวนับ 5xx แยกต่างหาก และปริมาณข้อมูลที่ส่งออก; กราฟคำขอรายชั่วโมง; การกระจายของรหัส 2xx/3xx/4xx/5xx; ที่อยู่ที่พบบ่อย, IP ที่พบบ่อย, ข้อผิดพลาดที่พบบ่อย (รหัสบวกเส้นทาง) และไคลเอนต์ (User-Agent) ช่วงเวลา: 24 ชั่วโมงหรือ 7 วัน
แหล่งข้อมูลคือบันทึกการเข้าถึงรูปแบบ combined จึงใช้ได้ทั้ง Nginx และ Apache และไม่ต้องติดตั้งโมดูลเพิ่ม แผงควบคุมจะค้นหาบันทึกจากไฟล์มาตรฐานต่อไปนี้:
/var/log/nginx/access.log/var/log/apache2/access.log/var/log/apache2/other_vhosts_access.log/var/log/httpd/access_logนอกจากนี้ แผงควบคุมยังตรวจไฟล์ *access*.log และ *requests*.log ใน /var/log/nginx/, /var/log/apache2/ และ /var/log/httpd/ ด้วย จึงพบบันทึกที่เว็บไซต์เขียนลงไฟล์ของตัวเองด้วยไดเรกทีฟ CustomLog ได้ เช่น arciveo-monitor_requests.log ที่ตัวติดตั้ง Arcivéo สร้างขึ้น
ระบบอ่านบันทึกเพียงไฟล์เดียว เพราะเมื่อ Nginx อยู่หน้า Apache การรวมสองบันทึกจะนับทุกคำขอสองครั้ง ระบบเลือกบันทึกแรกในรายการข้างต้นที่มีการเขียนภายในหนึ่งวันที่ผ่านมา (ไฟล์ที่พบตามรูปแบบชื่อจะถูกลองถัดไป เริ่มจากไฟล์ใหม่สุด) หากไม่มีไฟล์ใดถูกเขียนเลยในหนึ่งวัน จะเลือกไฟล์ที่ไม่ว่างซึ่งใหม่ที่สุด ดังนั้นบันทึกที่ logrotate ทำให้ว่าง หรือบันทึกที่ค้างจากเว็บเซิร์ฟเวอร์ที่หยุดไปแล้ว จะไม่บังบันทึกที่ใช้งานอยู่อีก ระบบอ่านส่วนท้ายของบันทึก (3 MB) และเก็บผลลัพธ์ไว้ในแคช 5 นาที — บนเว็บไซต์ที่มีปริมาณเข้าชมสูง ช่วงเวลาที่เลือกจึงอาจครอบคลุมไม่ครบ ขอบเขตที่ครอบคลุมจริงระบุไว้เหนือกราฟ
adm ส่วนผู้ใช้เว็บไม่ได้อยู่ในกลุ่มนี้ ตัวติดตั้ง Arcivéo จะเพิ่มผู้ใช้เว็บเข้ากลุ่มนี้ให้ หากติดตั้งด้วยตนเอง ให้ใช้ wrapper เล็ก ๆ ของ root ที่อนุญาตให้ทำได้อย่างเดียวคือแสดงบันทึก (หน้า ModSecurity ก็ทำงานแบบเดียวกัน) wrapper จะเลือกบันทึกด้วยกฎเดียวกับแผงควบคุม คำสั่งจะขึ้นบนหน้านั้นอยู่แล้ว และนี่คือคำสั่งเดียวกัน ให้วางทั้งหมดในครั้งเดียว เพราะเป็นคำสั่งเดียว:
ผู้ใช้เว็บอาจไม่ใช่ www-data — ให้ตรวจว่า PHP-FPM pool ของเว็บไซต์ทำงานภายใต้ผู้ใช้ใด (ps -o user= -C php-fpm) แล้วใส่ชื่อนั้นในบรรทัด sudoers หากชื่อบันทึกไม่มีทั้ง access และ requests ให้เพิ่มพาธของบันทึกไว้ที่ต้นบรรทัด L=… ภายใน wrapper
ความพยายามใช้ช่องโหว่ที่รู้จัก แผงควบคุมเทียบคำขอในบันทึกกับลายเซ็นของเอ็กซ์พลอยต์ที่พบบ่อยราวยี่สิบรายการ เช่น PHP-CGI การไล่เส้นทางไดเรกทอรีใน Apache, PHPUnit, Log4Shell และช่องโหว่ของเราเตอร์ กล้อง และเกตเวย์ VPN สำหรับแต่ละความพยายาม แผงจะบอกว่าใช้ได้ผลบนเซิร์ฟเวอร์นี้หรือไม่โดยอิงข้อเท็จจริง ได้แก่ เวอร์ชัน Apache และ PHP ที่ติดตั้ง การมี Java และรหัสที่เซิร์ฟเวอร์ตอบคำขอไฟล์ สีแดงจะใช้เฉพาะกับสิ่งที่ใช้ได้ผลจริงเท่านั้น
การเสริมความปลอดภัยเว็บเซิร์ฟเวอร์ แผงควบคุมส่งคำขอไปยังทุกเว็บไซต์บนเซิร์ฟเวอร์ผ่าน 127.0.0.1 และตรวจว่าผู้เข้าชมได้รับอะไร ได้แก่ เห็นเวอร์ชันเว็บเซิร์ฟเวอร์และ PHP หรือไม่ เปิดเมธอด TRACE หรือไม่ และมีเฮดเดอร์ป้องกัน Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy และ Content-Security-Policy หรือไม่ รายชื่อเว็บไซต์มาจากที่อยู่ที่ใช้เปิดแผงควบคุมและจากไฟล์โฮสต์เสมือน หากแผงอ่านได้ ผลลัพธ์อัปเดตทุก 10 นาที
หากขาดสิ่งใด จะมีคำสั่งเดียวปรากฏใต้ตาราง คำสั่งนี้สร้างไฟล์แยก zz-arciveo-hardening.conf และรีโหลดเว็บเซิร์ฟเวอร์หลังผ่านการทดสอบการตั้งค่าแล้วเท่านั้น เฮดเดอร์ที่เว็บไซต์ส่งเองอยู่แล้วจะไม่ถูกส่งซ้ำ CSP ไม่ได้เสนอเป็นบรรทัดเดียว เพราะต้องสร้างนโยบายสำหรับแต่ละเว็บไซต์ ไม่เช่นนั้นเว็บไซต์จะโหลดสคริปต์ สไตล์ และฟอนต์ของตัวเองไม่ได้ ยกเลิกการเปลี่ยนแปลงบน Apache ได้ดังนี้:
ServerSignature) จะไม่ถูกทำเครื่องหมาย หากซ่อนเวอร์ชันเว็บเซิร์ฟเวอร์ไว้แล้ว เมื่อไม่มีเวอร์ชัน ลายเซ็นจะแสดงเพียงชื่อเซิร์ฟเวอร์และชื่อโฮสต์
หน้า “แผนที่การโจมตี” จะระบุประเทศจาก IP ด้วยคำสั่ง geoiplookup หากไม่มีแพ็กเกจ GeoIP จะไม่สามารถระบุประเทศได้และจะไม่มีจุดปรากฏบนแผนที่:
/usr/share/GeoIP/GeoIP.dat อ่านได้ทุกคน ผลลัพธ์จะถูกแคชไว้ใน tmp/geoip_cache.json ตัวแผนที่เอง (Leaflet + ไทล์ OpenStreetMap) จะโหลดในเบราว์เซอร์ — จึงต้องมีอินเทอร์เน็ตบนเครื่องที่เปิดแดชบอร์ด
การ์ดในตัวสองใบบนแดชบอร์ด ที่แสดงไม่ใช่แค่ “เปิด/ปิด” ของเครื่องมือ แต่แสดงความปลอดภัยจริงของเซิร์ฟเวอร์ ไม่ต้องติดตั้งเพิ่ม อ่านค่าในเครื่องได้โดยไม่ต้องใช้ sudo
การเปิดเผยสู่ภายนอก — มีบริการกี่ตัวที่รับฟังทุกอินเทอร์เฟซ (0.0.0.0/[::]) และเข้าถึงได้จากภายนอก จะขึ้นสีแดงหากมีฐานข้อมูลหรือแคช (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) เปิดออกสู่ภายนอก — นี่คือช่องโหว่โดยตรง (−10 ต่อคะแนนความปลอดภัย) แหล่งข้อมูล: ss -tuln
127.0.0.1 (bind-address ในคอนฟิก MySQL/PostgreSQL, bind 127.0.0.1 ใน Redis) หรือปิดพอร์ตใน UFW
127.0.0.1 (loopback) จะมองเห็นได้เฉพาะจากตัวเซิร์ฟเวอร์เอง — เข้าถึงจากภายนอกไม่ได้ ถึงแม้พอร์ตจะ “เปิด” ก็ตาม ดังนั้น Postfix บนพอร์ต 25 ที่ผูกกับ loopback จึงปลอดภัย: การตั้งค่าอัตโนมัติจะกำหนด inet_interfaces = loopback-only (พร้อม smtpd_banner แบบเป็นกลาง — ปิดข้อสังเกต Lynis MAIL-8818 เรื่องการเปิดเผยเวอร์ชัน) การ์ด “การเปิดเผยสู่ภายนอก” จะนับเฉพาะสิ่งที่รับฟัง 0.0.0.0/[::] ว่าเปิดออกภายนอก ส่วนบริการแบบ loopback จะไม่ถูกนับ
/etc/postfix/main.cf ให้กำหนด smtpd_banner = $myhostname ESMTP (ไม่มีเวอร์ชันและ OS) และ inet_interfaces = loopback-only จากนั้น sudo systemctl restart postfix
การอัปเดตความปลอดภัย — มีแพตช์ความปลอดภัยกี่รายการที่รอการติดตั้ง และต้องรีบูตหรือไม่หลังอัปเดตเคอร์เนล (−5 ต่อคะแนนความปลอดภัยเมื่อมีแพตช์ค้าง) แหล่งข้อมูล: /usr/lib/update-notifier/apt-check, ไฟล์ /var/run/reboot-required รายการโดยละเอียดดูได้ที่หน้า “การอัปเดตความปลอดภัย”
update-notifier-common) หากไม่มี apt-check — มอนิเตอร์จะนับแพตช์ผ่าน apt-get -s upgrade
การอัปเดตความปลอดภัยอัตโนมัติ (unattended-upgrades) — ที่หน้า “การอัปเดตความปลอดภัย” มีการ์ดแยกที่แสดงว่าการติดตั้งแพตช์ความปลอดภัยอัตโนมัติเปิดใช้งานอยู่หรือไม่ และทำงานล่าสุดเมื่อใด ไม่ต้องใช้ sudo — สถานะอ่านผ่าน apt-config dump
การสำรองข้อมูลคือหลักประกันสำคัญที่สุด เพราะการสูญเสียข้อมูลร้ายแรงกว่าการถูกเจาะระบบใดๆ คุณต้องมีสองอย่าง — สำรองข้อมูลเซิร์ฟเวอร์/เว็บไซต์ และแยกต่างหากคือ สำรองฐานข้อมูลของแดชบอร์ด (ที่นั่นมีผู้ใช้ คีย์ WebAuthn การตั้งค่า และใบอนุญาต)
ตัวเลือก A — HestiaCP: แท็บ Backup ของผู้ใช้ → ปุ่มสร้างการสำรองข้อมูล (หรือตามกำหนดเวลาในการตั้งค่าเซิร์ฟเวอร์) การสำรองข้อมูลจะรวมเว็บไซต์และฐานข้อมูลของเว็บไซต์
ตัวเลือก B — ด้วยตนเอง (cron): ดัมป์ฐานข้อมูล + บีบอัดไดเรกทอรี data/ ของแดชบอร์ด:
การอัปเดตเป็นเวอร์ชันใหม่ ก่อนอื่นให้สำรองข้อมูล จากนั้นอัปโหลดไฟล์โค้ดทับ โดยคงข้อมูลของคุณไว้:
public/, includes/, assets/, cron/, database/ รวมถึง .htaccess ที่รูท (front controller — ห้ามคงการกำหนดเส้นทางจากเวอร์ชันเก่า), manifest.json, sw.js;config.php (ข้อมูล DB), data/ (รายงาน), logs/, tmp/ (เซสชันและแคช)SSH_FX_PERMISSION_DENIED — Permission denied ไฟล์ของแผงควบคุมเป็นของ www-data (ตั้งไว้เช่นนี้ตอนติดตั้ง) ขณะที่ไคลเอนต์ SFTP เชื่อมต่อด้วยผู้ใช้ของคุณเองซึ่งไม่มีสิทธิ์เขียน การมอบทั้งแผงควบคุมให้ www-data “เพื่อให้ใช้งานได้” คือสิ่งที่นำไปสู่ข้อผิดพลาดนี้พอดี ด้านล่างมีสามวิธี วิธีใดก็แก้ปัญหาได้
data/ (รายงาน), tmp/ (เซสชันและแคช), logs/; ซึ่งยังคงเป็นของ www-data ส่วนที่เหลือคือโค้ด และเว็บเซิร์ฟเวอร์ต้องการเพียงสิทธิ์อ่านเท่านั้น ซึ่งได้จากกลุ่ม www-data ด้วยสิทธิ์ 644 ผลพลอยได้: หากมีช่องโหว่ใน PHP ก็ไม่สามารถเขียนทับไฟล์ของแผงควบคุมได้ บนแผงโฮสติ้ง (HestiaCP และที่คล้ายกัน) ไม่จำเป็นต้องใช้ทางเลือก A: ที่นั่นไฟล์เว็บไซต์เป็นของบัญชีที่คุณเข้าผ่าน SFTP อยู่แล้ว และเว็บเซิร์ฟเวอร์อ่านผ่านกลุ่ม
chmod ที่ตามมาภายหลังบนไฟล์จะรีเซ็ต ACL-mask และการเข้าถึงจะหายไปเงียบ ๆ หากหลังจาก “จัดระเบียบสิทธิ์” แล้วการอัปโหลดยังติด Permission denied อีก ให้รันคำสั่ง setfacl ทั้งสองอีกครั้ง
2 ในทางเลือก C คือ setgid: ไฟล์ที่อัปโหลดผ่าน SFTP จะยังอยู่ในกลุ่ม www-data มิฉะนั้นแผงควบคุมจะเขียนทับไม่ได้ หลังทางเลือก C ให้ เชื่อมต่อใหม่ใน FileZilla กลุ่มใหม่จะมีผลเมื่อเข้าสู่ระบบใหม่เท่านั้น ตรวจสอบ: id deploy (ต้องปรากฏกลุ่ม www-data) และ ls -ld /path/to/monitor (drwxrwsr-x — ตัวอักษร s หมายความว่าตั้ง setgid แล้ว)
การย้ายไปยังเซิร์ฟเวอร์อื่น:
config.php, data/mysqldump บนเครื่องเก่า → นำเข้าบนเครื่องใหม่ แล้วแก้ไขข้อมูล DB ใน config.phpadm, งาน cronแดชบอร์ดทำงานอยู่แล้ว และบนเซิร์ฟเวอร์เดียวกันยังต้องการเว็บไซต์อีกหนึ่งแห่ง — พร้อมโดเมนของตัวเองข้าง ๆ ตัวมอนิเตอร์ หลังการติดตั้งอัตโนมัติ เซิร์ฟเวอร์ก็คือ Apache + PHP-FPM ธรรมดา ดังนั้นเว็บไซต์ต้องการสามอย่าง: ไดเรกทอรีของตัวเอง, vhost ของตัวเอง และใบรับรองของตัวเอง ส่วนแดชบอร์ดไม่ต้องแตะต้อง: มันเฝ้าดูทั้งเซิร์ฟเวอร์ ไม่จำเป็นต้องมีชุดที่สองสำหรับโดเมนที่สอง
site2.example.com คือ ที่อยู่ของเว็บไซต์ใหม่ อาจเป็นโดเมนแยกต่างหาก (mycompany.com) หรือซับโดเมน (shop.mycompany.com) ก็ได้ — สำหรับ Apache ไม่ต่างกัน ต่างกันเพียงเรกคอร์ด DNS (ขั้นที่ 1) และการออกใบรับรอง (ขั้นที่ 5) ส่วน site2 เป็นเพียง ชื่อย่อของเว็บไซต์: ใช้ตั้งชื่อไดเรกทอรี /var/www/site2 และไฟล์การตั้งค่า site2.conf ชื่อนี้ไม่เกี่ยวข้องกับโดเมน Apache อ่านที่อยู่จาก ServerName เท่านั้น ชื่อจะเป็นอะไรก็ได้ — เช่นสำหรับ shop.mycompany.com ใช้ shop ก็สะดวก: ไดเรกทอรี /var/www/shop, การตั้งค่า shop.conf
1. DNS. ในแผง DNS ของผู้รับจดทะเบียนโดเมน ให้สร้าง เรกคอร์ด A ชี้ไปยัง IP ของเซิร์ฟเวอร์นี้:
อีกไม่กี่นาทีให้ตรวจสอบ: dig +short site2.example.com ต้องคืนค่า IP ของเซิร์ฟเวอร์
2. ไดเรกทอรีของเว็บไซต์
3. vhost วางบล็อกลงในเทอร์มินัล ทั้งชุด — เส้นทางของซ็อกเก็ต PHP-FPM จะถูกตรวจหาเอง:
4. เปิดใช้งานเว็บไซต์ และตรวจสอบการตั้งค่าก่อนโหลดใหม่:
5. SSL การติดตั้งอัตโนมัติได้ติดตั้ง certbot ไว้แล้ว ถึงตอนนี้ DNS ต้องชี้มาที่เซิร์ฟเวอร์แล้ว:
โดเมนที่สามและถัดไปเพิ่มด้วยวิธีเดียวกัน — ทำขั้นที่ 1–5 ซ้ำ โดยเปลี่ยนโดเมนและไดเรกทอรี
Host ไม่ตรงกับ ServerName ใดเลย (เข้าผ่าน IP หรือโดเมนของคนอื่นที่ชี้มายังเซิร์ฟเวอร์ของคุณ) Apache จะให้บริการเว็บไซต์ที่เปิดใช้งานอยู่ ลำดับแรกตามตัวอักษร จาก /etc/apache2/sites-enabled/ เว็บไซต์มาตรฐาน 000-default ถูกปิดโดยการติดตั้งอัตโนมัติ ดังนั้นบทบาท “เวรรับหน้า” นี้จึงตกอยู่กับ vhost ของแดชบอร์ด (arciveo-monitor.conf) — ไม่กระทบเว็บไซต์ที่เปิดด้วยชื่อของตัวเอง หากต้องการให้เปิดเว็บไซต์อื่นผ่าน IP ให้ตั้งชื่อไฟล์ของเว็บไซต์นั้นให้มาก่อนตามลำดับตัวอักษร (เช่น 000-site2.conf)
site2_error.log และ site2_access.log ใน /var/log/apache2/
.htaccess ของตัวเอง (front controller) และเว็บไซต์ที่ซ้อนอยู่ข้างในจะให้ผลลัพธ์ต่างจากที่คุณคาดไว้ ให้วางเว็บไซต์ไว้เคียงกัน: /var/www/monitor, /var/www/site2
หากคุณเข้าสู่ระบบไม่ได้ — แก้ไขได้โดยตรงในฐานข้อมูลจากเซิร์ฟเวอร์ เปิดฐานข้อมูล (ชื่อดูได้จาก config.php):
สูญเสียคีย์ WebAuthn (ผ่านการยืนยันปัจจัยที่สองไม่ได้) — ปิด 2FA เข้าสู่ระบบด้วยรหัสผ่าน แล้วลงทะเบียนคีย์ใหม่:
ลืมรหัสผ่าน — กำหนดแฮชใหม่ (สร้างบนเซิร์ฟเวอร์แล้วนำมาใส่):
บล็อกตัวเองด้วยตัวกรอง IP — ปิดการจำกัด:
sudo mysql บนเซิร์ฟเวอร์ หรือ phpMyAdmin / ส่วนฐานข้อมูลในแผงควบคุมของโฮสติ้ง หลังกู้คืนแล้วให้เปิด WebAuthn และตัวกรอง IP อีกครั้ง
สรุปรายการงานอยู่ใน root-cron ของเซิร์ฟเวอร์ (เพิ่มผ่าน sudo crontab -e) เก็บไว้เฉพาะบรรทัดของเครื่องมือที่คุณใช้จริง และแก้ไขพาธให้ตรงกับเซิร์ฟเวอร์ของคุณ
sudo crontab -l และตรวจว่าเซอร์วิส cron ทำงานอยู่
TIMEZONE จาก config.php ค่าคงที่ TIMEZONE ส่งผลต่อ PHP เท่านั้น (วิธีที่แดชบอร์ดแสดงวันที่) แต่ cron-daemon จะรันงานตามเวลาระบบของ OS หากโซนเวลาของเซิร์ฟเวอร์ไม่ตรงกับของคุณ รายงาน “08:00” จะมาผิดเวลา ตัวอย่าง: เซิร์ฟเวอร์อยู่คนละโซน (Asia/Dhaka, UTC+6) ส่วนคุณอยู่ในกรุงเทพฯ (UTC+7) → รายงาน “08:00” จะมาถึงเวลา 09:00 ตามเวลาคุณ ให้ตรวจสอบและปรับโซนเวลาระบบให้เป็นของคุณเมื่อจำเป็น:
0 8 * * * จะทำงานเวลา 08:00 ตามเวลาท้องถิ่น มิฉะนั้นต้องเลื่อน cron เอง แต่เมื่อเปลี่ยนเวลาฤดูหนาว/ฤดูร้อน ค่าที่เลื่อนจะคลาดเคลื่อนอีก — จึงควรตั้งโซนเวลาระบบให้ถูกต้องดีกว่า
crontab.txt) อยู่ในโฟลเดอร์ system/ ข้างโปรเจกต์ นอก public_html นี่ ไม่ใช่ส่วนของเว็บไซต์ — ไม่ต้องอัปโหลดเข้า web root ให้วางไว้บนเซิร์ฟเวอร์ตามพาธระบบ (เหมือน crontab ด้านบน):
lynis-scan.sh → /usr/local/bin/ (chmod +x) — รัน lynis audit system ระหว่างสแกนจะตั้งแฟล็ก /tmp/lynis-running และคัดลอก lynis-report.dat ไปยัง data/lynis/ ของแดชบอร์ด;logwatch_daily.sh → /usr/local/bin/ (chmod +x) — สร้างรายงาน Logwatch รายวัน (sshd, fail2ban, sudo, postfix) ใน data/logwatch/;smart-scan.sh → /usr/local/bin/ (chmod +x) — เก็บสถานะดิสก์ (smartctl) ใน data/disk/;debsums-scan.sh → /usr/local/bin/ (chmod +x) — ตรวจความสมบูรณ์ของแพ็กเกจ (debsums) ใน data/debsums/;clamav-scan.sh → /usr/local/bin/ (chmod +x) — สแกนไวรัสด้วย ClamAV ตามพาธเสี่ยง (web, home, temp) เขียนสรุปลง /var/log/clamav/scan.log ซึ่งหน้า ClamAV จะอ่านจากที่นั่น (บรรทัด 01:30 ใน crontab ด้านบน);load-ipsum.sh → /usr/local/bin/ (chmod +x) — อัปเดตเซ็ต ipset ipsum (level 1) ในที่เดิม โดยไม่ทำให้กฎไฟร์วอลล์ที่ใช้งานอยู่ขาด (บรรทัด 04:00 ใน crontab ด้านบน);daily-report-all.sh → /usr/local/bin/ (chmod +x) — รันรายงาน cron/daily_report.php ของแดชบอร์ด (บรรทัด 08:00 ใน crontab ด้านบน);daily_report.php — มาพร้อมแดชบอร์ดอยู่แล้ว (cron/daily_report.php) เรียกผ่าน daily-report-all.sh ไม่ต้องติดตั้งแยก;collect-metrics-all.sh → /usr/local/bin/ (chmod +x) — รัน cron/collect_metrics.php ของแดชบอร์ด (หน้า “ประสิทธิภาพ” บรรทัด */5 ใน crontab ด้านบน); collect_metrics.php มาพร้อมแดชบอร์ดอยู่แล้ว ไม่ต้องติดตั้งแยก;security-watch-all.sh → /usr/local/bin/ (chmod +x) — เรียก cron/security_watch.php ของแผงควบคุม ในนามเจ้าของเว็บไซต์ (หน้า “เหตุการณ์ด้านความปลอดภัย” บรรทัด 2-57/5 ใน crontab ด้านบน) ส่วน security_watch.php มาพร้อมแผงควบคุมอยู่แล้ว ไม่ต้องติดตั้งแยก;fleet-push-all.sh → /usr/local/bin/ (chmod +x) — ส่งสรุปของเซิร์ฟเวอร์ไปยังบัญชีผู้ใช้ผ่าน cron/fleet_push.php ของแผงควบคุม (บรรทัด 3,18,33,48 ด้านบน);crontab.txt (system/cron/) — ตัวอย่างงาน ให้เพิ่มบรรทัดที่ต้องการผ่าน sudo crontab -e./usr/local/bin/ ไม่สามารถเขียนตรงจาก FileZilla ได้ — ไดเรกทอรีเป็นของ root และไคลเอนต์ SFTP จะได้รับ SSH_FX_PERMISSION_DENIED ลำดับขั้นตอนคือ: อัปโหลดไฟล์ไปยัง /tmp ก่อน (ที่นั่นทุกคนเขียนได้) แล้วย้ายไปยังตำแหน่งที่ต้องการด้วยคำสั่งเดียว:
/tmp ที่รากของเซิร์ฟเวอร์ — ไม่ใช่ /var/tmp และไม่ใช่ tmp/ ภายในตัวแดชบอร์ดเอง (อันหลังเป็นของ www-data และปิดจากผู้ใช้ของคุณ) ในแผนผัง FileZilla /tmp เป็นสาขาระดับบนสุด อยู่ข้าง var ไม่ใช่อยู่ภายในมัน
/usr/local/bin/ ล็อก — /var/log/arciveo-cron.log) — ไม่ต้องทำอะไรด้วยตนเอง
/home/*/web/*/public_html และ /var/www/* แล้ววางรายงานลงใน data/ ของแต่ละแห่ง หากแดชบอร์ดอยู่ที่พาธอื่น — ให้เพิ่มพาธนั้นในบรรทัด for app in … ภายในสคริปต์ มิฉะนั้นรายงาน Lynis/SMART/debsums/Logwatch จะไม่เข้าสู่แดชบอร์ด
logs/cron.log จะถูกสร้างครั้งแรกโดย root-cron — ไฟล์จะเป็นของ root และแท็บ “บันทึก cron” ในแดชบอร์ดจะไม่สามารถอ่านหรือล้างมันได้ ให้สร้างไฟล์ไว้ล่วงหน้าในนามของเว็บยูสเซอร์ (เจ้าของไดเรกทอรีเว็บไซต์ บน HestiaCP คือบัญชี เช่น admin) — จากนั้น root-cron จะเพียงเขียนต่อท้ายโดยไม่เปลี่ยนเจ้าของ:
stat -c %U /path/to/monitor.
sudo crontab -e) มิฉะนั้นมันจะทำงานซ้ำสองครั้ง
sudo crontab เปล่า ๆ (นั่นจะเป็นการยกระดับสิทธิ์เป็น root โดยตรงสำหรับใครก็ตามที่เข้าถึงเซสชันของแดชบอร์ดได้) แต่เป็นสคริปต์แคบ ๆ ที่มีสองคำสั่ง (list/set) ซึ่งแตะเฉพาะบล็อกของตัวเองระหว่างคอมเมนต์เฉพาะ ติดตั้งเพียงครั้งเดียว:
www-data — ตรวจว่า PHP-FPM pool ของเว็บไซต์ทำงานภายใต้ผู้ใช้ใด (ps -o user= -C php-fpm) แล้วใส่ค่านั้นในบรรทัด sudoers
public/crontab_monitor.php ถูกอัปโหลดผ่าน FTP/SFTP ด้วยผู้ใช้ระบบคนอื่น (เช่น root) ที่ต่างจากไฟล์อื่นของเว็บไซต์ เว็บเซิร์ฟเวอร์จะอ่านมันไม่ได้ ให้เทียบเจ้าของและสิทธิ์กับไฟล์ข้างเคียงแล้วปรับให้ตรงกัน:
Monitor ตรวจหาเครื่องมือผ่าน dpkg-query — ฐานข้อมูลแพ็กเกจของ APT หากติดตั้งเครื่องมือโดยไม่ผ่าน apt (ติดตั้งเอง จาก snap หรือจากซอร์ส) dpkg จะมองไม่เห็น
ข้อผิดพลาด 500 — ตรวจสอบล็อกของ PHP, nginx และตัวมอนิเตอร์เอง:
www-data แต่ทำงานภายใต้บัญชีผู้ใช้ (เช่น admin — เจ้าของไดเรกทอรีเว็บไซต์) กฎ sudo และการเป็นสมาชิกกลุ่มทั้งหมด (adm, systemd-journal) ต้องกำหนดให้ผู้ใช้รายนี้ มิฉะนั้นโมดูลจะแสดง “ไม่ทำงาน / 0” ทั้งที่บริการทำงานอยู่ ดูผู้ใช้ PHP จริงได้ที่: ps -o user= -C php-fpm | sort -u หรือเจ้าของไดเรกทอรีเว็บไซต์ stat -c '%U' /path/to/monitor จากนั้นในทุกคำสั่งด้านล่างให้ใช้ผู้ใช้นี้แทน www-data การติดตั้งอัตโนมัติจะตรวจหาเว็บผู้ใช้เองและกำหนด sudoers ให้กับผู้ใช้นั้น
ข้อมูลไม่แสดง — เกือบทุกครั้งเกิดจากยังไม่ได้กำหนดสิทธิ์ sudo ตรวจสอบคำสั่งนั้น ๆ ในนามของเว็บผู้ใช้ (แทน www-data ด้วยผู้ใช้ของคุณ) แฟล็ก -n = ไม่ใช้รหัสผ่าน เหมือน PHP — หากถามรหัสผ่าน แสดงว่ายังไม่มีกฎใน sudoers:
sudo aa-status ในเทอร์มินัลแสดงโปรไฟล์ แต่หน้า “AppArmor” แสดง “ไม่ทำงาน”) สาเหตุ: เว็บผู้ใช้ไม่มีสิทธิ์ sudo สำหรับคำสั่งของโมดูลนั้น ตรวจสอบจากรายการด้านบน: หากถามรหัสผ่าน — เพิ่มบรรทัดที่ขาดใน /etc/sudoers.d/monitor (“การตั้งค่า sudo”) คำสั่ง “ใหม่” ที่พบบ่อย: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD)
apache2ctl, ausearch, aa-status หรือ ss หรือเว็บผู้ใช้ไม่ได้อยู่ในกลุ่ม adm/systemd-journal (เป็นที่อ่านล็อกของ fail2ban/auth/modsec และ journalctl — Falco และเหตุการณ์ของเคอร์เนล)
อาการ: บนเซิร์ฟเวอร์มีข้อมูลอยู่ (มองเห็นผ่าน shell) แต่หน้าเว็บแสดง “ไม่มีข้อมูล” หรือสถานะไม่ถูกต้อง เช่น AIDE ระบุว่า “ยังไม่ได้เริ่มต้นใช้งาน” ทั้งที่สร้างฐานข้อมูลแล้ว
สาเหตุคือ open_basedir: แผงควบคุมและโฮสติ้งจำนวนมากจำกัดพูล PHP-FPM ไว้เฉพาะไดเรกทอรีของโดเมน ทำให้ฟังก์ชัน PHP อย่าง file_exists(), file_get_contents(), filemtime() บนพาธของระบบ (/var/lib/aide, /var/log, /proc…) ถูกบล็อก Monitor แก้ปัญหานี้ด้วยการอ่านพาธเหล่านั้นผ่านคำสั่งของระบบตามปกติ (cat, test, stat)
open_basedir วิธีแก้ที่ถูกต้องคือการอ่านผ่านคำสั่งของระบบ (ทำไว้แล้วสำหรับ AIDE และ Network Monitor) ไม่จำเป็นต้องขยาย open_basedir ไปยัง /var, /proc และยังปลอดภัยน้อยกว่าด้วย
Monitor ตรวจสอบใบรับรองโดยเชื่อมต่อกับโดเมนโดยตรงผ่านพอร์ต 443 หากไม่สามารถเข้าถึงโดเมนจากตัวเซิร์ฟเวอร์เอง หรือพอร์ตถูกไฟร์วอลล์ปิดกั้น การตรวจสอบจะไม่สำเร็จ
/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) และ Apache (/etc/apache2/sites-enabled/) พร้อมกับโฮสต์ปัจจุบันจาก HTTP_HOST
Monitor เชื่อมต่อกับ MySQL ด้วยผู้ใช้จาก config.php ซึ่งมีสิทธิ์เข้าถึงเฉพาะฐานข้อมูลของตัวเอง MySQL จะแสดงใน information_schema เฉพาะฐานข้อมูลที่มีสิทธิ์เท่านั้น จึงมองไม่เห็นฐานอื่น
เพื่อให้ monitor เห็น ฐานข้อมูลทั้งหมด ให้มอบสิทธิ์อ่านอย่างเดียวแก่ผู้ใช้รายนี้ (ทำครั้งเดียวจาก root แล้วแทนชื่อผู้ใช้จาก config.php):
sudo mysql ใด ๆ รายการฐานข้อมูลดึงผ่านการเชื่อมต่อ PDO ของตัวเอง
PostgreSQL ต้องใช้สิทธิ์ระดับผู้ใช้ postgres ซึ่งเว็บผู้ใช้ของแดชบอร์ดไม่มี การเปิด sudo psql แบบกว้างจาก PHP นั้นไม่ปลอดภัย แดชบอร์ดจึงเรียกใช้ตัวห่อหุ้มแบบจำกัดที่ไม่รับพารามิเตอร์แทน ซึ่งแสดงเพียงเวอร์ชัน จำนวนการเชื่อมต่อ และรายการฐานข้อมูลพร้อมขนาด สร้างมันขึ้นมา:
monitor-pgstat ออกจาก sudoers (ขั้นตอนที่ 13 ของการติดตั้งด้วยตนเอง) และไม่ต้องสร้างสคริปต์: การ์ด PostgreSQL จะยังคงไม่ทำงานเท่านั้น
แดชบอร์ดแสดงสิ่งที่กำลังเกิดขึ้น ด้านล่างคือสิ่งที่ต้องทำในสถานการณ์ทั่วไป หลักการโดยรวม: อย่าตื่นตระหนก ตรวจสอบว่าเป็นกิจกรรมที่ถูกต้องหรือไม่ (การกระทำของคุณ การอัปเดต การสำรองข้อมูล) แล้วตอบสนองตามระดับความรุนแรง
ignoreip/etc, นอก /usr/share) — อาจถูกสับเปลี่ยน ตรวจสอบแพ็กเกจ: debsums PACKAGE_NAME หากไม่แน่ใจให้ติดตั้งใหม่ (apt install --reinstall)127.0.0.1 หรือปิดพอร์ตใน UFW นี่คือช่องโหว่จริงcertbot renew หรือการตั้งค่าในแดชบอร์ด)sudo apt update && sudo apt upgrade หลังอัปเดตเคอร์เนลให้รีบูตเซิร์ฟเวอร์