Đây là hướng dẫn cài đặt, cấu hình và bảo trì Arcivéo Monitor. Các phần được nhóm lại: tổng quan chung, triển khai bảng điều khiển, kết nối các công cụ bảo mật, mô-đun tích hợp và chẩn đoán. Có thể sao chép lệnh bằng nút bên phải.
Việc cài đặt bảng điều khiển nằm trên các trang hướng dẫn từng bước riêng. Hãy chọn phương thức:
Arcivéo Monitor — bảng điều khiển bảo mật máy chủ. Nó thu thập dữ liệu từ các công cụ đã cài đặt (Fail2ban, UFW, Lynis, ModSecurity, AIDE, ClamAV, Auditd, CrowdSec, Suricata, Falco v.v.) và hiển thị chúng trong một giao diện thống nhất với dashboard, bản đồ tấn công và các trang chi tiết cho từng công cụ.
Monitor không phải là công cụ bảo vệ chủ động — bản thân nó không chặn các cuộc tấn công. Nhiệm vụ của nó là tổng hợp thông tin từ các công cụ đang hoạt động và trình bày một cách tiện lợi.
Trình giám sát chỉ hoạt động cục bộ — phải được cài trên chính máy chủ mà nó giám sát. Không dùng SSH hay API từ xa.
Mọi lệnh (fail2ban-client, ufw status, ipset list v.v.) được dashboard chạy dưới danh nghĩa người dùng máy chủ web (thường là www-data, trên panel hosting là tài khoản site) với bộ quyền hạn hẹp sudo — chỉ cho các tiện ích cụ thể, không có quyền root chung. Kết quả được phân tích và hiển thị trong trình duyệt.
Điểm bắt đầu từ mức tối đa và giảm dần theo từng vấn đề được phát hiện:
PermitRootLogin yes) — −20Kết quả: 80+ = Được bảo vệ, 60–79 = Cần chú ý, <60 = Đang bị đe dọa.
WebAuthn — chuẩn xác thực không cần mật khẩu thông qua khóa phần cứng. Hỗ trợ YubiKey, Touch ID, Face ID, Windows Hello, Passkey.
Sau khi đăng nhập bằng mật khẩu, hệ thống yêu cầu xác nhận qua khóa đã đăng ký. Ngay cả khi mật khẩu bị lộ — không có khóa vật lý hoặc sinh trắc học thì cũng không thể đăng nhập.
Để thiết lập, mở Khóa WebAuthn trong menu bên và nhấn “Đăng ký khóa”. Hãy đăng ký ngay hai khóa: nếu khóa duy nhất bị mất hoặc hỏng, bạn sẽ không thể đăng nhập vào dashboard bằng khóa đó.
Bảng điều khiển có thể gửi báo cáo bảo mật đến Telegram và email (theo nút bấm và theo lịch). Cấu hình trong mục “Cài đặt”.
Telegram. Cần token của bot và chat id:
@BotFather → /newbot → nhận token dạng 123456:ABC....@userinfobot, hoặc mở https://api.telegram.org/bot<TOKEN>/getUpdates và tìm "chat":{"id":...}.Email. Hai cách để chọn trong “Cài đặt” → Email:
re_...) và tên miền người gửi đã xác minh.Trạng thái báo cáo: “CHÚ Ý” hoặc “OK”. Tiêu đề chuyển thành “CHÚ Ý” chỉ khi có sự cố thực sự hoặc có hành động đang chờ: phát hiện mối đe dọa ClamAV, thay đổi tệp trong AIDE, sự kiện nghiêm trọng của Falco (Emergency/Alert/Critical trong 24 giờ qua), dịch vụ bị sập trong Monit, cần khởi động lại, SSL sắp hết hạn (≤14 ngày) hoặc đang chờ cập nhật bảo mật. Nhiễu nền — bot dò SSH, IP bị fail2ban cấm, cảnh báo Suricata, cảnh báo Lynis và các yêu cầu đã bị ModSecurity chặn — không làm tăng trạng thái, nên những con số đó trong báo cáo tự thân không có nghĩa là “CHÚ Ý”.
Các module giám sát chi tiết (Lynis, UFW, ModSecurity, bản đồ tấn công, AIDE, ClamAV v.v.) sẽ mở khi có giấy phép hợp lệ. Nếu không có, dashboard, cài đặt và tài khoản vẫn hoạt động, còn các module hiển thị thẻ “Cần giấy phép”.
Sau khi mua trong tài khoản cá nhân, bạn có mã kích hoạt dạng ARCIVEO-XXXX-XXXX-XXXX-XXXX. Cần “kích hoạt” mã này cho domain của panel — thao tác này biến mã thành tệp giấy phép đã ký (khối [license]), rồi bạn dán vào panel.
Cách kích hoạt (3 bước):
my.arciveo.com → mục “Giấy phép” / “Kích hoạt giấy phép” — sao chép mã ARCIVEO-….monitor.example.com). Nhấn kích hoạt — hệ thống tạo tệp giấy phép gắn với domain này và hiển thị trong ô có nút “Sao chép”.Panel kiểm tra key bằng mật mã: chữ ký, sự gắn kết với domain và thời hạn hiệu lực.
APP_URL trong config.php và chỉ nhập tên host — không có https:// và không có tiền tố www. Kích hoạt chỉ một lần: mã biến thành giấy phép cho domain đã nhập và không kích hoạt lại được — nếu nhập sai domain, key sẽ không hợp với panel của bạn, còn mã thì đã bị tiêu tốn. Vì vậy hãy nhập domain thật cẩn thận.
Tất cả tham số chính của panel được khai báo trong một tệp duy nhất config.php ở thư mục gốc (cạnh thư mục public/) bằng các hằng define() thông thường. Tệp được tạo khi cài đặt; hiếm khi cần sửa thủ công — chủ yếu khi đổi domain, di chuyển hoặc kết nối tới cơ sở dữ liệu khác. Sau mỗi lần sửa, hãy khởi động lại PHP-FPM (nếu không, do OPcache mà thay đổi sẽ không được áp dụng).
Điền giá trị của bạn vào những chỗ được tô sáng; phần còn lại giữ nguyên:
Cơ sở dữ liệu. Thông tin kết nối tới MySQL/MariaDB:
DB_HOST — máy chủ CSDL, hầu như luôn là localhost;DB_NAME — tên cơ sở dữ liệu của panel;DB_USER — người dùng CSDL (chỉ truy cập được cơ sở dữ liệu của mình);DB_PASS — mật khẩu của người dùng này;DB_CHARSET — bảng mã kết nối, hãy giữ utf8mb4.Ứng dụng.
APP_URL — địa chỉ đầy đủ của panel (vd. https://monitor.example.com). Phải trùng với domain mà giấy phép đã được kích hoạt — nếu không, khóa sẽ bị từ chối (xem mục “Giấy phép”);TIMEZONE — múi giờ PHP: chỉ ảnh hưởng tới cách panel hiển thị ngày và giờ. Không ảnh hưởng tới thời điểm chạy các tác vụ cron — nơi đó dùng múi giờ của hệ thống (xem “Tất cả tác vụ cron”).Thời gian phiên. SESSION_LIFETIME — thời gian chờ nhàn rỗi của phiên tính bằng giây (trượt: làm mới khi có hoạt động). Mặc định 28800 = 8 giờ; sau khoảng thời gian không hoạt động này, panel sẽ yêu cầu đăng nhập lại. Ví dụ, 3600 = 1 giờ, 86400 = một ngày.
Ghi nhật ký lỗi. Lỗi không bao giờ hiển thị cho khách truy cập mà được ghi vào logs/php_errors.log — có thể xem chúng ở trang “Nhật ký ứng dụng”. Các dòng này (display_errors=0, log_errors=1, đường dẫn error_log) thường không cần đổi — cài đặt được khai báo ngay trong tệp và không phụ thuộc vào php.ini.
public/), và với panel này thì web-root (DocumentRoot) chính là thư mục gốc của panel, không phải public/. Bản thân tệp không bị “rò rỉ”: trong .htaccess ở gốc đã có lệnh cấm rõ ràng cho nó (Require all denied) — máy chủ trả về 403. Ngay cả khi không có quy tắc này thì mã nguồn cũng không rò rỉ: đây là PHP — máy chủ thực thi nó chứ không trả về dưới dạng văn bản. Để chắc chắn: đừng đưa nó lên các kho công khai và đừng gửi cho bộ phận hỗ trợ với mật khẩu thật. Quyền của tệp là 640.
UFW (Uncomplicated Firewall) — giao diện đơn giản cho nftables/iptables. Nó chặn mọi cổng đến, trừ những cổng được cho phép rõ ràng. Trang “Tường lửa UFW” hiển thị trạng thái và các quy tắc.
ufw enable, hãy chắc chắn cho phép SSH (ufw allow OpenSSH), nếu không bạn sẽ mất quyền truy cập máy chủ.
deny không được xem là truy cập được từ bên ngoài.
Skipping adding existing rule — đây không phải lỗi. Đó là cách UFW báo rằng quy tắc y hệt đã tồn tại và không thêm lại nó. Khi chạy lại tự động cấu hình (vốn có tính idempotent), đây là thông báo bình thường — không cần xử lý gì.
Tự động chặn IP khi vượt quá số lần đăng nhập thất bại. Phân tích log của SSH, nginx, Apache và các dịch vụ khác.
Cài đặt cơ bản đã ở trên. Ở đây là cấu hình thực tế cho hàng chục jail đang hoạt động và hàng nghìn lượt chặn: thiết lập chung, các jail chính và tự động chặn IP độc hại từ danh sách ipsum.
Tệp /etc/fail2ban/jail.local — thiết lập chung và các jail quan trọng nhất:
ignoreip nhớ nhập IP của bạn và các mạng tin cậy, nếu không bạn có thể tự chặn chính mình. Sau khi sửa: sudo fail2ban-client reload.
Tự động nạp danh sách chặn ipsum — vào cron của root (sudo crontab -e): level 1 (hơn 100 nghìn IP) được nạp vào tập ipsum và bị cắt ở tường lửa (chi tiết ở mục “Danh sách chặn IPset”):
ipsum — đây chính là tập mà dashboard đọc (thẻ “IPset ipsum”). Cấp độ: levels/1.txt — bao phủ tối đa, levels/3.txt — chính xác hơn (từ 3 nguồn trở lên).
Vì sao “Màn hình giám sát an ninh” được chia thành hai vùng. Việc bảo vệ hoạt động ở hai cấp độ và dashboard không trộn lẫn chúng:
sshd, apache-*, nginx-* v.v.) và kẻ tái phạm nguy hiểm (jail recidive — những kẻ đã bị chặn nhiều lần). Đây là các IP thực sự đã tấn công vào bạn — chúng hiện trên bản đồ tấn công và “Dòng thời gian”.ipset ipsum, bị cắt ở tường lửa bằng quy tắc DROP. Phần lớn các địa chỉ này còn chưa hề chạm tới máy chủ của bạn — chúng bị chặn từ trước; bộ đếm “IPset ipsum” cho biết đã cắt được bao nhiêu địa chỉ theo cách phòng ngừa.Khác biệt rất đơn giản: phản ứng — “những kẻ này đã tấn công và bị chặn”, phòng ngừa — “những kẻ này bị chặn trước cả khi ra tay”. Trước đây list-3 ipsum bị nhồi giả tạo vào recidive (từ đó có cách chia cũ “recidive theo danh sách”); nay recidive chỉ gồm kẻ tái phạm thực sự, còn phòng ngừa hoàn toàn nằm ở tường lửa.
ipsum — danh sách IP độc hại công khai, cập nhật hàng ngày. Monitor hiển thị số địa chỉ đã tải trên dashboard và bản đồ tấn công, đồng thời tính vào Điểm bảo mật (−10 nếu tập chưa được tải).
Phương án tối giản không dùng fail2ban — tập ipsum riêng với việc chặn qua iptables:
@reboot. Đồng thời lệnh create … -exist đặt giới hạn maxelem 300000 (mặc định 65536 — level 1 không vừa, sẽ báo “Hash is full”):
ipsum và, nếu tường lửa do trình cài đặt quản lý (VPS mới — profile “Đầy đủ”/“Rút gọn”), gắn tập vào UFW bằng quy tắc DROP — lưu lượng từ các IP này thực sự bị chặn. Quy tắc nằm sau ESTABLISHED,RELATED, nên các kết nối hiện tại (kể cả SSH của bạn) không bị ngắt — chỉ chặn các kết nối mới từ danh sách. Tập được khôi phục khi dịch vụ ipsum-load.service khởi động trước tường lửa (nếu không UFW sẽ không lên được), và được cron cập nhật lúc 04:00. Trên máy chủ đã cấu hình sẵn (dashboard, tường lửa riêng), trình cài đặt không đụng vào tường lửa — ở đó ipsum vẫn là danh sách cho dashboard và bản đồ tấn công, còn quy tắc DROP nếu muốn thì thêm thủ công (phương án tối giản với iptables … --match-set ipsum … -j DROP — ở trên). Khi cài đặt tự động thì không cần làm gì thủ công.
Giải pháp thay thế hiện đại cho Fail2ban với threat intelligence cộng đồng: chặn từ cộng đồng cùng với luật riêng của bạn. Cần một bouncer riêng để áp dụng lệnh chặn vào tường lửa.
systemctl is-active crowdsec). Khởi động: sudo systemctl enable --now crowdsec; nếu bị lỗi hãy xem sudo journalctl -u crowdsec -n 30. Áp dụng tương tự cho mọi dịch vụ có trạng thái “Chưa chạy” (Suricata, Falco, Monit, MySQL).
stream halted / lệnh chặn không được áp dụng. Đây là api-key mồ côi: bouncer đã bị xóa khỏi cscli bouncers list, nhưng key cũ của nó vẫn còn trong /etc/crowdsec/bouncers/*.yaml. Hãy đăng ký lại bouncer và ghi key mới vào:
AIDE (Advanced Intrusion Detection Environment) tạo ảnh chụp hệ thống tập tin và mỗi lần kiểm tra sẽ báo cáo các thay đổi trong /etc, /bin, /usr. Sau khi cài đặt bắt buộc phải khởi tạo cơ sở dữ liệu (aideinit).
aideinit terminal sẽ đứng ở dòng Running aide --init... trong 5–15 phút — đây là bình thường (băm toàn bộ hệ thống tập tin, tải nặng lên đĩa). Đừng ngắt bằng Ctrl+C. Nếu tiến trình “treo” mà không hiển thị gì — có thể nó đang chờ trả lời một yêu cầu ẩn Overwrite existing aide.db.new [Yn]? (nhấn Y). Kiểm tra hoạt động từ một phiên khác: pgrep -af aide.
aideinit: “21_aide_spamassassin … printf: invalid number” (return code 20) — lỗi đã biết của đoạn cấu hình AIDE trong Ubuntu 22.04. Cơ sở dữ liệu không được tạo. Hãy chuyển đoạn snippet bị lỗi ra ngoài rồi thử lại:
aideinit chưa chạy, hoặc (Ubuntu 24.04) thư mục /var/lib/aide được tạo ở chế độ 700 và www-data không truy cập được — khắc phục bằng sudo chmod 755 /var/lib/aide (xem khối trên). “Chưa có lần kiểm tra nào” = đã có cơ sở dữ liệu nhưng chưa chạy kiểm tra — đây không phải lỗi. Monitor đọc kết quả từ /var/log/aide/aide.log.
/etc/cron.daily/aide mặc định trên Ubuntu/Debian mới có thể không ghi /var/log/aide/aide.log đúng định dạng (và aide.wrapper cũng không còn trong đó). Đáng tin cậy hơn là thêm cron riêng với --config rõ ràng — nó ghi log dưới quyền root ở chế độ 644, và monitor đọc được mà không cần nhóm bổ sung:
chmod 755 /var/lib/aide và cron kiểm tra lúc 02:00 — không cần làm thủ công gì cả.
sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db.
Trình quét diệt virus cho Linux. Đặc biệt hữu ích để kiểm tra /var/www tìm PHP-shell và mã độc.
enable --now? Ba nguyên nhân thường gặp:
1. Trong cấu hình còn dòng Example — clamd không chịu khởi động khi dòng này còn:
2. Chưa tải cơ sở dữ liệu chữ ký — clamd không khởi động khi thiếu nó:
3. Chỉ đang tải — clamd nạp ~8 triệu chữ ký vào bộ nhớ mất 30–60 giây. Hãy đợi và kiểm tra: systemctl is-active clamav-daemon (trạng thái activating → vẫn đang tải).
sudo journalctl -u clamav-daemon -n 30 --no-pager.
clamd chỉ giữ chữ ký trong bộ nhớ, bản thân nó không quét theo lịch. Bảng điều khiển hiển thị kết quả quét theo lịch, nên cần một cron để quét và ghi log. Trình tự động cài đặt sẽ đặt wrapper /usr/local/bin/clamav-scan.sh và cron lúc 01:30 — sau lần chạy đầu tiên, “Số tệp đã quét” và “Lần quét cuối” sẽ được điền. Chạy ngay không cần đợi lịch: sudo /usr/local/bin/clamav-scan.sh.
Linux Malware Detect (LMD) — trình quét phần mềm độc hại chuyên về các mối đe dọa web: PHP-shell, backdoor web, trình tải mã độc. Dùng engine ClamAV và bổ sung thêm chữ ký riêng.
maldet --report.
update-rc.d: error: unable to read /etc/init.d/maldet — dòng này vô hại. maldet không dùng init.d, việc cập nhật chữ ký và quét được chạy qua /etc/cron.daily/maldet. Nếu bên dưới thấy installation completed thì mọi thứ đã cài xong.
apt mà nằm ở /usr/local/maldetect, và khi bật open_basedir thì sự tồn tại của nó được kiểm tra qua shell — xem mục “Trang trống dù dữ liệu đã có trên máy chủ”.
Hệ thống phát hiện xâm nhập mạng: phân tích lưu lượng ở cấp độ gói tin và biết hàng nghìn chữ ký tấn công. Bổ sung cho ModSecurity (ModSecurity hoạt động ở cấp HTTP, còn Suricata ở cấp TCP/IP).
/var/log/suricata/eve.json dưới quyền root với chế độ 750 cho thư mục, nên máy chủ web (www-data) không đọc được. Hãy mở quyền truy cập thư mục — các tệp bên trong vẫn được bảo vệ:
Chặn bắt các lời gọi hệ thống qua eBPF/kernel module và phát hiện bất thường theo thời gian thực: shell từ nginx, tiến trình web đọc /etc/passwd, ghi vào /bin, v.v.
journalctl -u falco (không cần sudo — thông qua nhóm systemd-journal). Hãy đảm bảo www-data thuộc nhóm này — xem “Cấu hình sudo” (mục 2) ở trang cài đặt thủ công.
/etc/passwd, ghi vào thư mục hệ thống). Không có sự kiện nghiêm trọng nào trong một ngày trên máy chủ yên tĩnh là trạng thái khỏe mạnh.
journalctl đòi hỏi quyền truy cập nhật ký; để dashboard thấy sự kiện ổn định, quá trình tự cài đặt bật file_output cho Falco → /var/log/falco/falco.log và đặt UMask=0022 cho dịch vụ (log được web server đọc). Trên bản cài đặt mới, không cần cấu hình thủ công điều này.
ModSecurity — tường lửa web (WAF) cho Apache hoặc Nginx. Chặn các cuộc tấn công ở tầng ứng dụng: SQL injection, XSS, vượt đường dẫn, trình quét.
IncludeOptional /etc/modsecurity/*.conf, còn gói chỉ đặt modsecurity.conf-recommended — file này không khớp mẫu *.conf. Nếu không sao chép nó thành modsecurity.conf, SecRuleEngine vẫn ở trạng thái Off: module đã nạp, quy tắc CRS đã nạp, nhưng lưu lượng không được kiểm tra và không tạo audit log. Chế độ trung gian DetectionOnly chỉ ghi sự kiện vào log mà không chặn yêu cầu — dashboard hiển thị nó màu vàng.
Quyền truy cập audit log của dashboard. Log /var/log/apache2/modsec_audit.log thuộc quyền root (quyền 640), người dùng web không đọc được. Dashboard lấy dữ liệu qua một lớp bọc — hãy tạo nó:
SecRuleEngine cuối cùng không có thụt lề: các dòng có thụt lề nằm bên trong khối <LocationMatch>/<Directory> (ví dụ tắt WAF cho phpMyAdmin) và không quyết định chế độ toàn cục.www-data, còn trong HestiaCP pool của site chạy dưới quyền chủ site (ví dụ admin) — hãy kiểm tra grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf.X-Forwarded-For. Chỉ những giao dịch có quy tắc kích hoạt mới được đưa vào thống kê: chỉ thị SecAuditLogRelevantStatus ghi vào audit log mọi phản hồi 4xx/5xx, nên các lỗi 403/500 thông thường cũng lọt vào đó — dashboard không tính chúng là sự kiện WAF.---RULES--- cần cho mục “Tất cả quy tắc đang hoạt động” — dashboard hiển thị không chỉ những quy tắc đã kích hoạt mà toàn bộ quy tắc CRS đã nạp + quy tắc tùy chỉnh. Ba đường dẫn trong vòng lặp for f in … là các vị trí điển hình cho quy tắc CRS và phần bổ sung cục bộ; nếu bố trí của bạn khác (gói đặt file vào thư mục riêng, hoặc quy tắc tùy chỉnh không nằm ở /etc/modsecurity/custom-rules.conf), hãy tìm đường dẫn thật bằng lệnh sudo grep -rl 'IncludeOptional\|^Include ' /etc/apache2/mods-enabled/security2.conf /etc/apache2/conf-enabled/*.conf 2>/dev/null rồi thay chúng vào danh sách. Nếu lớp bọc cũ (không có phần này) — mục đó chỉ hiển thị cảnh báo “không khả dụng”, phần còn lại của trang vẫn hoạt động như trước.
Auditd (Linux Audit Daemon) ghi lại các lệnh gọi hệ thống ở cấp nhân: đăng nhập và đăng xuất, lệnh sudo, các lần xác thực thất bại, thay đổi tệp. Monitor hiển thị lượt đăng nhập, các lần thất bại và lệnh sudo trong ngày hôm nay.
ausearch (/usr/sbin/ausearch) và khi cần thì từ /var/log/audit/audit.log bằng lệnh tail. Cả hai phải có trong sudoers.
Theo dõi các dịch vụ (nginx, php-fpm, mysql, v.v.) và tự khởi động lại khi chúng ngừng chạy. Có thể gửi cảnh báo qua email.
monit status. Trong /etc/monit/monitrc phải bật giao diện HTTP (khối set httpd với allow localhost), nếu không monit status sẽ báo lỗi.
monitrc dòng set httpd bị chú thích (mặc định ở dạng # set httpd port 2812 …). Hãy bỏ chú thích khối đó và cho phép localhost. (2) Bản thân httpd được bật không theo dõi gì cả — Monit chỉ đếm những gì được mô tả trong các stanza check; thiếu chúng thì danh sách vẫn trống dù giao diện đang chạy. Cấu hình tối thiểu hoạt động được:
conf.d với httpd trên cổng 2812 và một bộ kiểm tra — trên bản cài mới không cần cấu hình thủ công.
PSAD phân tích nhật ký iptables và phát hiện việc quét cổng cùng các cuộc tấn công mạng, gán cho mỗi nguồn một mức độ nguy hiểm (1–5). Bổ trợ cho fail2ban và Suricata.
psad --Status (cần có trong sudoers). Nếu không bật ghi log iptables, trang sẽ trống — điều này là bình thường khi chưa có lần quét nào.
Mandatory Access Control giới hạn những tệp và tài nguyên mà một chương trình có thể truy cập, ngay cả khi nó đã bị xâm nhập. Trên Ubuntu/Debian, AppArmor được dùng mặc định (thường đã được cài sẵn và đang hoạt động).
aa-status (cần có trong sudoers). Nó hiển thị số profile ở chế độ enforce/complain và các tiến trình không có profile.
“Số profile đã nạp” nhiều hơn enforce + complain là điều bình thường. Trong AppArmor 4.x (Ubuntu 24.04 trở lên) có thêm chế độ unconfined: profile được nạp vào nhân nhưng không giới hạn gì cả. Ubuntu gắn nhãn này cho hàng chục profile của các chương trình dùng user namespaces (trình duyệt, ứng dụng torrent và tương tự). Khi có những profile như vậy, thẻ “Số profile đã nạp” chuyển sang màu hổ phách và hiển thị số lượng của chúng — ví dụ unconfined: 90 trong tổng số 120 profile đã nạp và 26 ở chế độ enforce. Chỉ những profile ở enforce mới thực sự bảo vệ; trên Ubuntu 22.04 (AppArmor 3.x) không có chế độ này và các con số luôn khớp nhau.
unconfined khi bạn thực sự hiểu rõ: chúng bị tắt không phải do lỗi, mà vì nếu không thì chính các chương trình đó sẽ hỏng. Còn các profile ở complain là chuyện khác: quy tắc ở đó đã được viết sẵn và chỉ là chưa được áp dụng mà thôi.
debsums kiểm tra xem tệp của các gói đã cài có khớp với giá trị băm từ kho lưu trữ không — phát hiện các tệp nhị phân hệ thống bị thay thế (bổ sung cho AIDE). Quét đầy đủ mất 1–2 phút nên chạy qua cron, còn dashboard đọc kết quả từ data/debsums/debsums.log và tự phân loại (chỉ tệp nhị phân và thư viện là quan trọng).
Tác vụ nằm trong cron của root (sudo crontab -e). Trình bao bọc debsums-scan.sh có sẵn được đặt vào /usr/local/bin/ (chmod +x; xem bảng tóm tắt các tác vụ cron) và tự ghi báo cáo vào data/debsums/ của dashboard.
Trình bao bọc debsums-scan.sh tự tìm data/ của dashboard — không cần khai báo đường dẫn.
/etc/ (tệp cấu hình) và /usr/share/ (tài nguyên) trên máy chủ thường là bình thường — dashboard đánh dấu chúng bằng màu riêng. Đáng lo là thay đổi ở tệp nhị phân và thư viện (/bin, /sbin, /usr/lib v.v.) — thẻ “Tệp nhị phân / thư viện” hiển thị đúng những thay đổi này.
Lynis chạy thủ công hoặc theo cron. Báo cáo phải được lưu vào thư mục data/lynis/ của dự án — monitor đọc tệp lynis-report.dat.
lynis-scan.sh ở chế độ nền ngay từ bảng điều khiển (không cần đợi cron): hiển thị “Đang quét…” và tự cập nhật báo cáo khi hoàn tất. Để làm được điều này, người dùng web cần một dòng sudoers để chạy script — trình cài đặt tự động thêm nó vào /etc/sudoers.d/monitor. Nếu bảng điều khiển được cài thủ công/trước đây, hãy thêm dòng đó với cùng người dùng đã ghi trong tệp:
Logwatch phải lưu báo cáo hằng ngày vào thư mục data/logwatch/ của dự án ở định dạng .txt. Monitor hiển thị báo cáo mới nhất và kho lưu trữ.
Giám sát mạng không cần cài đặt — đây là một trang tích hợp sẵn trong bảng điều khiển. Nó hiển thị trạng thái mạng của máy chủ từ các nguồn cục bộ:
/proc/net/dev;ip;ss;journalctl -k.Ba nguồn đầu hoạt động không cần sudo, nên giao diện, lưu lượng, kết nối và cổng hiển thị ngay lập tức. Khối “Sự kiện nhân” dùng journalctl -k — được đọc qua nhóm systemd-journal (“Cấu hình sudo”, mục 2), không cần sudo. Kiểm tra rằng người dùng web truy cập được mọi thứ:
UFW BLOCK không xuất hiện ở đây — chúng nằm ở trang “Tường lửa UFW” và “Bản đồ tấn công”. Khối trống với dấu tích xanh = suốt ngày qua không có sự cố mạng nào.
Trang tích hợp hiển thị ba nội dung:
df); thanh chuyển đỏ khi ≥90%;lsblk), chỉ đĩa thật (loop/snap được ẩn);smartctl).Dung lượng và danh sách thiết bị hoạt động ngay, không cần thiết lập. SMART cần gói smartmontools. Tiến trình web không truy cập trực tiếp được vào thiết bị đĩa, nên SMART được thu thập bằng cron vào tệp data/disk/smart.txt để dashboard đọc.
Tác vụ nằm trong cron của root (sudo crontab -e). Trình bao smart-scan.sh có sẵn được đặt vào /usr/local/bin/ (chmod +x; xem tổng hợp tác vụ cron) và tự ghi vào thư mục data/disk/ của dashboard.
Trình bao smart-scan.sh tự tìm thư mục data/ của dashboard — không cần khai báo đường dẫn. Bên trong, lsblk -e7,11 loại trừ loop/cdrom.
Trang này hiển thị lịch sử tải của máy chủ trong 24 giờ gần nhất — Load Average, mức chiếm dụng CPU và thời gian chờ I/O, RAM/Swap, lưu lượng mạng (nhận/gửi), I/O đĩa (đọc/ghi), mức lấp đầy đĩa và inode, số file descriptor đang mở và kết nối MySQL, cùng số kết nối TCP và tiến trình hiện tại.
Dữ liệu do cron/collect_metrics.php thu thập — cứ mỗi 5 phút ghi một ảnh chụp “thô” của các bộ đếm (/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') vào bảng CSDL system_metrics; phần trăm và tốc độ được trang tự tính từ chênh lệch giữa hai ảnh chụp liền kề (mức lấp đầy đĩa/inode/descriptor/kết nối MySQL là giá trị tức thời, không tính lại). Không cần sudo — các nguồn được đọc mà không cần quyền root. Các điểm cũ hơn 24 giờ sẽ tự động bị xóa mỗi lần ghi.
Trình bao bọc collect-metrics-all.sh (xem tóm tắt các tác vụ cron) tự tìm mọi phiên bản dashboard đã cài trên máy chủ và chạy cron/collect_metrics.php của từng cái dưới danh nghĩa chủ sở hữu trang web.
Cảnh báo về tải (mục “Cài đặt” → “Cảnh báo về tải”) — khi vượt ngưỡng CPU/RAM/đĩa/inode, dashboard sẽ gửi thông báo qua Telegram/Email (cùng các kênh như báo cáo hằng ngày — không cần bật riêng cho cảnh báo), và một thông báo nữa khi chỉ số trở lại bình thường. Không spam lặp lại trong lúc còn giữ ở ngưỡng: thông báo tiếp theo chỉ đến sau chu kỳ “trở lại bình thường → lại vượt ngưỡng”.
collect_metrics.php mỗi lần chạy (mỗi 5 phút) — không cần cron riêng. Trạng thái “đã thông báo / chưa” được lưu trong data/alerts_state.json, còn các ngưỡng nằm trong cài đặt của dashboard.
Trang “Bản đồ tấn công” xác định quốc gia theo IP bằng lệnh geoiplookup. Nếu thiếu gói GeoIP thì quốc gia sẽ không được xác định và các điểm sẽ không hiện trên bản đồ:
/usr/share/GeoIP/GeoIP.dat ai cũng đọc được, kết quả được lưu cache trong tmp/geoip_cache.json. Bản đồ (Leaflet + ô bản đồ OpenStreetMap) được tải trong trình duyệt — cần có internet trên máy tính đang mở dashboard.
Hai thẻ tích hợp sẵn trên dashboard cho thấy không phải công cụ đang “bật/tắt”, mà mức độ an toàn thực sự của máy chủ. Không cần cài đặt, đọc cục bộ mà không cần sudo.
Phơi lộ ra ngoài — số dịch vụ lắng nghe trên mọi giao diện (0.0.0.0/[::]) và truy cập được từ bên ngoài. Tô đỏ nếu CSDL hoặc cache lộ ra ngoài (MySQL, PostgreSQL, Redis, MongoDB, Memcached, Elasticsearch) — đây là lỗ hổng trực tiếp (−10 điểm An toàn). Nguồn: ss -tuln.
127.0.0.1 (bind-address trong cấu hình MySQL/PostgreSQL, bind 127.0.0.1 trong Redis) hoặc đóng cổng trong UFW.
127.0.0.1 (loopback) chỉ chính máy chủ nhìn thấy — từ bên ngoài không thể truy cập, ngay cả khi cổng đã “mở”. Vì vậy Postfix trên cổng 25 gắn với loopback là an toàn: tự động cấu hình đặt inet_interfaces = loopback-only (cộng thêm smtpd_banner trung tính — khắc phục cảnh báo Lynis MAIL-8818 về việc lộ phiên bản). Thẻ “Phơi lộ ra ngoài” chỉ tính là lộ ra ngoài những gì lắng nghe trên 0.0.0.0/[::]; các dịch vụ loopback không được tính.
/etc/postfix/main.cf hãy đặt smtpd_banner = $myhostname ESMTP (không có phiên bản và HĐH) và inet_interfaces = loopback-only, rồi sudo systemctl restart postfix.
Cập nhật bảo mật — bao nhiêu bản vá bảo mật đang chờ cài đặt và có cần khởi động lại sau khi cập nhật nhân hay không (−5 điểm An toàn khi có bản vá). Nguồn: /usr/lib/update-notifier/apt-check, tệp /var/run/reboot-required. Danh sách chi tiết — ở trang “Cập nhật bảo mật”.
update-notifier-common). Nếu không có apt-check — monitor tính số bản vá qua apt-get -s upgrade.
Tự động cập nhật bảo mật (unattended-upgrades) — ở trang “Cập nhật bảo mật” có một thẻ riêng cho thấy việc tự động cài bản vá bảo mật có được bật hay không và lần cuối nó chạy khi nào. Không cần sudo — trạng thái được đọc qua apt-config dump.
Sao lưu là biện pháp bảo hiểm quan trọng nhất: mất dữ liệu còn đáng sợ hơn bất kỳ vụ xâm nhập nào. Bạn cần hai thứ — bản sao lưu máy chủ/website và riêng một bản sao lưu cơ sở dữ liệu của dashboard (nơi lưu người dùng, khóa WebAuthn, thiết lập, giấy phép).
Cách A — HestiaCP: tab Backup ở người dùng → nút tạo bản sao lưu (hoặc theo lịch trong thiết lập máy chủ). Bản sao lưu bao gồm website và cơ sở dữ liệu của chúng.
Cách B — thủ công (cron): dump cơ sở dữ liệu + nén thư mục data/ của dashboard:
Cập nhật lên phiên bản mới. Trước tiên hãy sao lưu. Sau đó tải lại các tệp mã, giữ nguyên dữ liệu của bạn:
public/, includes/, assets/, cron/, database/, cùng với các tệp gốc .htaccess (front-controller — không được để định tuyến từ phiên bản cũ), manifest.json, sw.js;config.php (dữ liệu CSDL), data/ (báo cáo), logs/, tmp/ (phiên và cache).SSH_FX_PERMISSION_DENIED — Permission denied. Tệp của bảng điều khiển thuộc về www-data (chúng được đặt như vậy khi cài đặt), trong khi ứng dụng SFTP kết nối bằng người dùng của bạn, vốn không có quyền ghi. Giao toàn bộ bảng điều khiển cho www-data “cho nó chạy” chính là điều dẫn đến lỗi này; dưới đây là ba cách, cách nào cũng giải quyết được vấn đề.
data/ (báo cáo), tmp/ (phiên và cache), logs/; chúng vẫn thuộc về www-data. Phần còn lại là mã, và máy chủ web chỉ cần đọc chúng, điều mà nhóm www-data với quyền 644 đã cho phép. Lợi ích phụ: khi có lỗ hổng trong PHP, các tệp của bảng điều khiển không thể bị ghi đè. Trên các bảng điều khiển hosting (HestiaCP và tương tự) không cần phương án A: ở đó tệp website vốn đã thuộc tài khoản mà bạn dùng để đăng nhập qua SFTP, còn máy chủ web đọc chúng theo nhóm.
chmod tiếp theo lên các tệp sẽ đặt lại mặt nạ ACL, và quyền truy cập lặng lẽ biến mất. Nếu sau khi “dọn dẹp lại quyền” việc tải lên lại vấp phải Permission denied — hãy chạy lại cả hai lệnh setfacl.
2 trong phương án C chính là setgid: tệp tải lên qua SFTP vẫn nằm trong nhóm www-data, nếu không bảng điều khiển sẽ không ghi đè được. Sau phương án C, hãy kết nối lại trong FileZilla — nhóm mới chỉ có hiệu lực khi đăng nhập mới. Kiểm tra: id deploy (phải xuất hiện nhóm www-data) và ls -ld /path/to/monitor (drwxrwsr-x — chữ s nghĩa là setgid đã được đặt).
Di chuyển sang máy chủ khác:
config.php, data/.mysqldump trên máy cũ → nhập vào máy mới; sửa dữ liệu CSDL trong config.php.adm, tác vụ cron.Nếu bạn không thể đăng nhập — mọi thứ đều sửa được trực tiếp trong CSDL từ máy chủ. Mở CSDL (tên lấy từ config.php):
Mất khóa WebAuthn (không qua được yếu tố thứ hai) — tắt 2FA, đăng nhập bằng mật khẩu, đăng ký khóa mới:
Quên mật khẩu — đặt hash mới (tạo hash trên máy chủ rồi thay vào):
Tự chặn mình bằng bộ lọc IP — tắt giới hạn:
sudo mysql trên máy chủ, hoặc phpMyAdmin / mục CSDL trong bảng điều khiển hosting. Sau khi khôi phục, hãy bật lại WebAuthn và bộ lọc IP.
Tổng hợp các tác vụ nằm trong root-cron của máy chủ (thêm qua sudo crontab -e). Chỉ giữ lại các dòng của những công cụ bạn dùng; chỉnh đường dẫn cho khớp máy chủ của bạn.
sudo crontab -l và xem dịch vụ cron còn hoạt động không.
TIMEZONE trong config.php. Hằng số TIMEZONE chỉ ảnh hưởng đến PHP (cách dashboard hiển thị ngày), nhưng cron-daemon chạy tác vụ theo giờ hệ thống của OS. Nếu múi giờ máy chủ không khớp với bạn, báo cáo “08:00” sẽ đến sai giờ. Ví dụ: máy chủ đặt ở múi giờ khác (Asia/Dhaka, UTC+6), còn bạn ở TP. Hồ Chí Minh (UTC+7) → báo cáo “08:00” sẽ đến lúc 09:00 giờ của bạn. Hãy kiểm tra và nếu cần, chỉnh múi giờ hệ thống về giờ của bạn:
0 8 * * * sẽ chạy lúc 08:00 giờ địa phương. Nếu không, bạn sẽ phải tự dịch chuyển cron, nhưng khi chuyển giờ mùa đông/mùa hè độ lệch lại sai — nên chỉnh múi giờ hệ thống là đúng hơn.
crontab.txt) nằm trong thư mục system/ cạnh dự án, bên ngoài public_html. Đây không phải phần của trang web — không cần tải chúng lên web-root; hãy đặt trên máy chủ theo các đường dẫn hệ thống (như trong crontab ở trên):
lynis-scan.sh → /usr/local/bin/ (chmod +x) — chạy lynis audit system, trong lúc quét đặt cờ /tmp/lynis-running và sao chép lynis-report.dat vào data/lynis/ của dashboard;logwatch_daily.sh → /usr/local/bin/ (chmod +x) — tạo báo cáo Logwatch hằng ngày (sshd, fail2ban, sudo, postfix) vào data/logwatch/;smart-scan.sh → /usr/local/bin/ (chmod +x) — lấy trạng thái ổ đĩa (smartctl) vào data/disk/;debsums-scan.sh → /usr/local/bin/ (chmod +x) — kiểm tra tính toàn vẹn gói (debsums) vào data/debsums/;clamav-scan.sh → /usr/local/bin/ (chmod +x) — quét diệt virus ClamAV theo các đường dẫn nguy hiểm (web, home, temp); ghi tổng hợp vào /var/log/clamav/scan.log, nơi trang ClamAV đọc dữ liệu (dòng 01:30 trong crontab ở trên);load-ipsum.sh → /usr/local/bin/ (chmod +x) — cập nhật tập ipset ipsum (level 1) tại chỗ, không phá vỡ các quy tắc tường lửa đang hoạt động (dòng 04:00 trong crontab ở trên);daily-report-all.sh → /usr/local/bin/ (chmod +x) — chạy báo cáo cron/daily_report.php của dashboard (dòng 08:00 trong crontab ở trên);daily_report.php — đã có sẵn trong dashboard (cron/daily_report.php), chạy qua daily-report-all.sh, không cần cài riêng;collect-metrics-all.sh → /usr/local/bin/ (chmod +x) — chạy cron/collect_metrics.php của dashboard (trang “Hiệu năng”, dòng */5 trong crontab ở trên); collect_metrics.php đã có sẵn trong dashboard, không cần cài riêng;crontab.txt (system/cron/) — mẫu tác vụ; nhập các dòng cần thiết qua sudo crontab -e./usr/local/bin/. Không thể ghi trực tiếp từ FileZilla vào đó — thư mục thuộc về root, và SFTP-client sẽ nhận SSH_FX_PERMISSION_DENIED. Trình tự như sau: trước tiên tải tệp lên /tmp (ai cũng ghi được vào đó), rồi chuyển nó vào đúng chỗ bằng một lệnh:
/tmp ở gốc máy chủ — không phải /var/tmp và cũng không phải tmp/ bên trong chính dashboard (thư mục sau thuộc về www-data và không cho người dùng của bạn truy cập). Trong cây thư mục của FileZilla, /tmp là nhánh cấp cao nhất, cạnh var, không nằm bên trong nó.
/usr/local/bin/, log — /var/log/arciveo-cron.log) — không cần làm gì thủ công.
/home/*/web/*/public_html và /var/www/*, rồi đặt báo cáo vào data/ của chúng. Nếu dashboard nằm ở đường dẫn khác — hãy thêm nó vào dòng for app in … bên trong các script, nếu không báo cáo Lynis/SMART/debsums/Logwatch sẽ không vào được dashboard.
logs/cron.log được tạo đầu tiên bởi root-cron — nó sẽ thuộc về root, và tab “Nhật ký cron” trong dashboard sẽ không đọc cũng như xóa được nó. Hãy tạo tệp trước bằng danh nghĩa web-user (chủ sở hữu thư mục trang web; trên HestiaCP đây là tài khoản, vd. admin) — khi đó root-cron chỉ ghi thêm mà không đổi chủ sở hữu:
stat -c %U /path/to/monitor.
sudo crontab -e), nếu không nó sẽ chạy hai lần.
sudo crontab trần (như vậy sẽ là leo thang trực tiếp lên root cho bất kỳ ai chiếm được phiên dashboard), mà là một script hẹp với hai lệnh (list/set), chỉ đụng đến khối riêng của nó nằm giữa các chú thích nội bộ. Cài một lần:
www-data — hãy kiểm tra pool PHP-FPM của trang web chạy dưới người dùng nào (ps -o user= -C php-fpm), rồi thay vào dòng sudoers.
public/crontab_monitor.php được tải lên qua FTP/SFTP dưới người dùng hệ thống khác (ví dụ root) so với các tệp còn lại của trang web, web-server sẽ không đọc được nó. Hãy đối chiếu chủ sở hữu và quyền với tệp lân cận rồi chỉnh cho khớp:
Monitor xác định sự hiện diện của công cụ thông qua dpkg-query — cơ sở dữ liệu gói APT. Nếu công cụ không được cài qua apt (thủ công, từ snap hoặc từ mã nguồn), dpkg sẽ không thấy nó.
Lỗi 500 — hãy kiểm tra log của PHP, nginx và của chính monitor:
www-data mà dưới tài khoản người dùng (ví dụ admin — chủ sở hữu thư mục website). Mọi quy tắc sudo và thành viên nhóm (adm, systemd-journal) đều phải khai báo cho người dùng này, nếu không các mô-đun sẽ hiện “Không hoạt động / 0” dù dịch vụ đang chạy. Xác định người dùng PHP thực tế: ps -o user= -C php-fpm | sort -u hoặc chủ sở hữu thư mục website stat -c '%U' /path/to/monitor. Sau đó trong tất cả lệnh bên dưới hãy thay nó vào chỗ www-data. Bản cài đặt tự động tự nhận diện người dùng web và khai báo sudoers cho nó.
Dữ liệu không hiển thị — hầu như luôn do chưa cấp quyền sudo. Hãy kiểm tra từng lệnh cụ thể với tư cách người dùng web (thay www-data bằng người dùng của bạn). Cờ -n = không cần mật khẩu, giống như PHP — nếu nó hỏi mật khẩu nghĩa là chưa có quy tắc trong sudoers:
sudo aa-status trong terminal có hiện profile, nhưng trang “AppArmor” lại “Không hoạt động”). Nguyên nhân: người dùng web không có quyền sudo cho lệnh của chính mô-đun đó. Hãy thử lệnh đó từ danh sách trên: nếu bị hỏi mật khẩu — thêm dòng còn thiếu vào /etc/sudoers.d/monitor (“Cấu hình sudo”). Các lệnh “mới” hay gặp: /usr/sbin/aa-status (MAC), /usr/sbin/psad --Status (PSAD).
apache2ctl, ausearch, aa-status hoặc ss, hoặc người dùng web không thuộc nhóm adm/systemd-journal (từ đó đọc log fail2ban/auth/modsec và journalctl — Falco cùng các sự kiện kernel).
Triệu chứng: trên máy chủ có dữ liệu (thấy được qua shell), nhưng trang lại hiển thị “không có dữ liệu” hoặc trạng thái sai — ví dụ AIDE báo “Chưa khởi tạo” dù cơ sở dữ liệu đã được tạo.
Nguyên nhân là open_basedir: nhiều bảng điều khiển và hosting giới hạn pool PHP-FPM trong thư mục của domain, nên các hàm PHP file_exists(), file_get_contents(), filemtime() trên các đường dẫn hệ thống (/var/lib/aide, /var/log, /proc…) bị chặn. Monitor khắc phục bằng cách đọc các đường dẫn đó qua lệnh hệ thống chuẩn (cat, test, stat).
open_basedir. Giải pháp đúng là đọc bằng lệnh hệ thống (đã áp dụng cho AIDE và Giám sát mạng). Không cần mở rộng open_basedir ra /var, /proc và như vậy kém an toàn hơn.
Monitor kiểm tra chứng chỉ bằng cách kết nối trực tiếp đến các domain qua cổng 443. Nếu domain không truy cập được từ chính máy chủ hoặc cổng bị firewall chặn — việc kiểm tra sẽ thất bại.
/etc/nginx/sites-enabled/, /etc/nginx/conf.d/) và Apache (/etc/apache2/sites-enabled/) cùng với host hiện tại từ HTTP_HOST.
Monitor kết nối tới MySQL bằng người dùng khai báo trong config.php, người này chỉ có quyền truy cập cơ sở dữ liệu của mình. MySQL chỉ hiển thị trong information_schema các cơ sở dữ liệu mà người dùng có quyền — nên những cơ sở còn lại không hiện ra.
Để monitor thấy được tất cả CSDL, hãy cấp cho người dùng này quyền chỉ đọc (một lần bằng root; thay bằng tên người dùng trong config.php):
sudo mysql: danh sách cơ sở dữ liệu được lấy qua kết nối PDO riêng của nó.
PostgreSQL yêu cầu quyền truy cập ở cấp người dùng postgres, mà người dùng web của dashboard không có. Việc mở lệnh sudo psql rộng từ PHP là không an toàn — thay vào đó dashboard gọi một lớp bọc hẹp không tham số, chỉ in ra phiên bản, số kết nối và danh sách cơ sở dữ liệu kèm dung lượng. Hãy tạo nó:
monitor-pgstat khỏi sudoers (bước 13 của phần cài đặt thủ công) và không cần tạo script: thẻ PostgreSQL sẽ chỉ đơn giản là không hoạt động.
Bảng điều khiển cho thấy điều gì đang xảy ra; dưới đây là cần làm gì trong các tình huống điển hình. Nguyên tắc chung: đừng hoảng loạn, đối chiếu với hoạt động hợp lệ (thao tác của bạn, cập nhật, sao lưu), và xử lý theo mức độ nghiêm trọng.
ignoreip./etc, ngoài /usr/share) — có khả năng bị đánh tráo. Hãy đối chiếu gói: debsums PACKAGE_NAME, nếu nghi ngờ hãy cài đặt lại nó (apt install --reinstall).127.0.0.1 hoặc đóng cổng trong UFW. Đây là một lỗ hổng thực sự.certbot renew hoặc thiết lập trong bảng điều khiển).sudo apt update && sudo apt upgrade; sau khi cập nhật nhân hãy khởi động lại máy chủ.