Đây là hướng dẫn cài đặt, cấu hình và bảo trì Arcivéo Security 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 Security 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.
Hai nhịp làm việc. Các trang của panel hỏi công cụ ngay lúc bạn mở chúng — bạn luôn thấy trạng thái hiện thời. Ngoài ra, các tác vụ nền chạy theo lịch (cron):
Danh sách đầy đủ các tác vụ nằm ở mục “Tất cả tác vụ cron ở một nơi”.
Đ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) — −20PasswordAuthentication yes) — −10X11Forwarding, MaxAuthTries lớn hơn 3 hoặc mọi tài khoản đều đọc được sshd_config — −5TRACE đang bật, hoặc thiếu header Strict-Transport-Security hay X-Frame-Options — −5Kế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 đó.
Có bốn kênh: Telegram, Email, webhook và push vào trình duyệt. Chúng độc lập với nhau — bật kênh nào cũng được, thậm chí cả bốn. Cũng qua các kênh đó, panel gửi báo cáo bảo mật hằng ngày, cảnh báo về tải và các phát hiện của cảm biến sự kiện; tất cả được cấu hình một lần, tại đây, 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.Webhook. Một địa chỉ duy nhất nhận POST là đủ cho Slack, Discord, Mattermost, n8n và trình xử lý của riêng bạn. “Cài đặt” → Webhook: dán địa chỉ và bật công tắc.
{"text": …}, tới Discord gửi {"content": …} (Discord từ chối tin nhắn dài hơn 2000 ký tự nên phần văn bản bị cắt bớt);text, event, severity, source, count, host, ts — không cần phân tích lại nội dung tin nhắn.Thông báo đẩy. Tin nhắn đến thẳng trình duyệt, và nếu panel đã được thêm vào màn hình chính của điện thoại thì hiện ra như một thông báo ứng dụng bình thường — không cần bot, không cần máy chủ thư ở giữa. “Cài đặt” → Thông báo đẩy: bật công tắc và nhấn “Kết nối thiết bị này” trên từng thiết bị cần nhận thông báo. Bộ đếm “Thiết bị đã kết nối” cho biết có bao nhiêu thiết bị.
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.
Panel được đóng bằng đăng nhập có mật khẩu và, nếu đã bật, bằng bộ lọc IP. Với một chương trình thì cả hai đều không dùng được, nên các hệ thống bên ngoài có lối vào riêng — hai địa chỉ chỉ đọc, được bảo vệ bằng mã. Mã này không thay đổi gì trên máy chủ: dùng nó chỉ có thể lấy về các chỉ số.
Bật lên — “Cài đặt” → “API chỉ đọc”: công tắc “Bật API”; mã được tạo tự động ở lần lưu đầu tiên. Nút “Mã mới” cấp một mã khác và ngay lúc đó ngắt tất cả những ai đang dùng mã cũ.
/api/status.php — JSON: điểm bảo mật, trạng thái các mô-đun, lần đo tải mới nhất kèm các tiến trình nặng nhất và các sự kiện bảo mật trong 24 giờ qua;/api/metrics.php — cũng những con số đó ở định dạng văn bản của Prometheus (các số đo arciveo_*: arciveo_security_score, arciveo_fail2ban_banned, arciveo_cpu_busy_pct và tương tự).Nếu máy khách của bạn không đặt được tiêu đề, mã cũng được chấp nhận dưới dạng tham số — ?token=…. Lưu ý rằng ở dạng đó nó sẽ lọt vào nhật ký truy cập của máy chủ web, nên dùng tiêu đề vẫn hơn.
Prometheus. Khối dựng sẵn cho scrape_configs:
api disabled — API đang tắt trong cài đặt. Các yêu cầu bị từ chối được ghi vào nhật ký ứng dụng cùng IP người gửi, nên việc dò mã sẽ thấy được ở trang “Nhật ký ứng dụng”.
Panel được cài trên từng máy chủ riêng và trả lời rất tốt câu hỏi “máy này đang thế nào”. Câu hỏi “tất cả các máy của tôi đang thế nào” thì nó không trả lời — vì vậy mỗi panel có thể gửi một bản tóm tắt ngắn về tài khoản cá nhân, nơi các máy chủ hiện ra trong một danh sách duy nhất.
Những gì cần lấy trong tài khoản cá nhân my.arciveo.com → mục “Máy chủ của tôi”: ở đó cấp một mã (dạng fk_…) và ghi rõ địa chỉ nơi nhận https://my.arciveo.com/api/fleet.php. Mã là một cho mỗi tài khoản — dùng chung cho mọi máy chủ của bạn.
Những gì cần đặt trong panel — “Cài đặt” → “Tổng quan máy chủ”: địa chỉ nơi nhận, mã, tên máy chủ (cách nó hiện trong danh sách; để trống thì lấy tên miền của panel) và công tắc “Gửi bản tóm tắt”. Nút “Gửi ngay” kiểm tra kết nối tức thì, không phải chờ lịch.
Sau đó bản tóm tắt đi theo cron, 15 phút một lần:
Chính xác thì những gì được gửi đi: tên và tên miền máy chủ, hệ điều hành, thời gian hoạt động, phiên bản PHP; điểm bảo mật; trạng thái các mô-đun (UFW, số jail của Fail2ban, số lệnh chặn hôm nay, CrowdSec, Suricata và Falco có đang chạy không, mối đe dọa ClamAV, thay đổi AIDE, chỉ số Lynis, các bản cập nhật đang chờ, có cần khởi động lại không, số ngày còn lại của chứng chỉ, số cổng mở nguy hiểm); lần đo tải gần nhất (load, CPU, RAM, đĩa, inode); bộ đếm sự kiện trong 24 giờ và sự kiện nghiêm trọng gần nhất. Bản tóm tắt không chứa nhật ký, mật khẩu hay nội dung tệp.
sudo crontab -l) và câu trả lời của nút “Gửi ngay”. Lỗi gửi được ghi vào nhật ký ứng dụng với nhãn FLEET — ở đó sẽ thấy mã bị từ chối (HTTP 401) hay bản thân kết nối không thiết lập được.
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. Khung 24 giờ là mặc định: các nút phía trên chuyển sang 7 ngày hoặc 30 ngày.
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.
Hai độ sâu lưu trữ. Các ảnh chụp “thô” năm phút sống được một ngày (cộng thêm một giờ dự phòng để điểm cũ nhất trên biểu đồ vẫn có điểm trước đó phục vụ tính toán). Mỗi giờ đã kết thúc được gộp thành một hàng; chuỗi theo giờ này được giữ 30 ngày và chính nó là thứ mà các chế độ xem “7 ngày” và “30 ngày” đọc. Nhờ vậy một tháng lịch sử chỉ tốn khoảng 720 hàng thay vì khoảng 8600.
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.
Tiến trình nặng nhất. Dưới các biểu đồ có hai bảng liệt kê năm tiến trình ngốn CPU nhiều nhất:
Cả hai bảng luôn mô tả 24 giờ gần nhất, ngay cả khi biểu đồ hiển thị cả tháng: ảnh chụp tiến trình chỉ có ở các hàng năm phút, mà những hàng đó không được giữ quá một ngày.
ps, tập lệnh PHP thu thập và chuỗi cron/sudo phía trên nó) bị loại khỏi danh sách — nếu không chúng sẽ đứng đầu mọi ảnh chụp: ps ngay lúc khởi động cho thấy gần 100 % CPU. Còn các tác vụ cron khác chạy cùng phút thì vẫn xuất hiện, và đó chính là điều bảng này cần cho thấy.
Cảnh báo về tải (mục “Cài đặt” → “Cảnh báo về tải”) — khi ngưỡng CPU/RAM/đĩa/inode bị vượt, panel gửi thông báo qua tất cả các kênh đang bật (Telegram, Email, webhook, push — cùng những kênh của báo cáo hằng ngày; không cần bật riêng gì cho cảnh báo), rồi gửi thêm một thông báo nữa khi chỉ số trở lại bình thường. Trong lúc ngưỡng vẫn bị vượt, panel không gửi dồn dập: 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.
Báo cáo hằng ngày trả lời câu hỏi “máy chủ đang thế nào”. Cảm biến trả lời một câu hỏi khác — “vừa có chuyện gì xảy ra”. Cứ 5 phút, nó hỏi các nguồn nhanh và chỉ ghi lại những gì đã thay đổi kể từ lần kiểm tra trước; trang “Sự kiện bảo mật” trong menu hiển thị danh sách các phát hiện.
Các kiểm tra chậm — Lynis, debsums, cập nhật gói, hạn của chứng chỉ SSL — cảm biến không đụng đến: dù sao con số của chúng cũng chỉ thay đổi mỗi ngày một lần và vẫn thuộc phần việc của báo cáo hằng ngày.
Nó nhận ra những gì — chín nguồn:
[Priority: 1] nâng phát hiện lên mức nghiêm trọng;FOUND mới trong nhật ký quét;root (nghiêm trọng) và đăng nhập từ một địa chỉ chưa từng gặp (cảnh báo);Công cụ chưa được cài, hoặc có nhật ký mà panel không đọc được, đơn giản là im lặng — đó không phải lỗi và cũng không phải sự kiện.
data/secwatch_state.json), và lần chạy đầu chỉ ghi dấu đó. Nếu không, vừa bật theo dõi là bạn sẽ nhận thông báo về mọi thứ mà nhật ký đã tích lại suốt nhiều tháng.
Cấu hình — “Cài đặt” → “Theo dõi sự kiện”:
23-7, trong đó cảnh báo không được gửi đi.Thông báo đi theo đúng các kênh của báo cáo hằng ngày (Telegram, Email, webhook, push) — không cần bật riêng gì thêm. Mọi phát hiện đều được ghi vào danh sách bất kể thông báo có được gửi hay không, và được giữ trong 90 ngày.
Danh sách sự kiện. Bộ lọc: khoảng thời gian (24 giờ, 7, 30 hoặc 90 ngày), mức độ quan trọng và nguồn; hiển thị 500 bản ghi gần nhất. Nút “Kiểm tra ngay” chạy đúng lượt kiểm tra như cron — tiện ngay sau khi cấu hình, để khỏi phải chờ năm phút; nút này cũng nêu lý do khi không có thông báo nào được gửi (“dưới ngưỡng quan trọng”, “giờ yên lặng”, “chưa cấu hình kênh thông báo nào”). Bộ đếm màu đỏ cạnh mục menu là số sự kiện nghiêm trọng trong 24 giờ qua.
Thẻ địa chỉ. Nhấp vào một dòng trong danh sách sự kiện hoặc trong khối Địa chỉ liên quan sẽ mở ra mọi điều đã biết về một địa chỉ: trình tự thời gian các sự kiện của nó, quốc gia và ngay dòng đầu tiên là kết luận. Dòng trong danh sách mở thẻ khi sự kiện chỉ liên quan đến đúng một địa chỉ; nếu có nhiều địa chỉ thì chính các địa chỉ bên trong dòng là liên kết. Có bốn kết luận:
Dưới trình tự thời gian là khối Điều gì đã xảy ra trên máy chủ cùng lúc đó: những sự kiện hoàn toàn không có địa chỉ. AIDE không biết ai đã sửa tệp, ClamAV không biết ai mang tệp nhiễm vào. Chỉ hiển thị những sự kiện rơi vào khoảng hoạt động của địa chỉ và sáu giờ sau đó. Chính lần đăng nhập cùng với những gì xảy ra tiếp theo mới phân biệt một nỗ lực với quyền truy cập thực sự.
Lịch chạy. Tác vụ được đưa vào crontab của root (sudo crontab -e), lệch 2 phút so với việc thu thập số liệu để hai bên không khởi động cùng lúc:
php cron/security_watch.php. Wrapper tìm tất cả bản cài của panel trên máy chủ và chạy phần kiểm tra dưới danh nghĩa chủ sở hữu trang — với đúng những quyền sudo mà panel dùng từ web. Gọi thẳng từ crontab của root sẽ tạo tệp trạng thái data/secwatch_state.json thuộc sở hữu root, và nút “Kiểm tra ngay” trong panel sẽ ngừng hoạt động.
Trang “Máy chủ web” phân tích nhật ký truy cập và cho thấy đã có bao nhiêu yêu cầu, bao nhiêu phần trong đó kết thúc bằng lỗi và ai đã gửi chúng. ModSecurity trả lời câu hỏi “cái gì đã bị chặn”, còn trang này trả lời “rốt cuộc thì cái gì đã đến được trang web”.
Những gì hiển thị: số yêu cầu, RPS, tỷ lệ lỗi, bộ đếm 5xx riêng và lượng dữ liệu đã gửi đi; biểu đồ yêu cầu theo giờ; phân bố các mã 2xx/3xx/4xx/5xx; địa chỉ hay gặp, IP hay gặp, lỗi hay gặp (mã cộng đường dẫn) và các máy khách (User-Agent). Khoảng thời gian: 24 giờ hoặc 7 ngày.
Nguồn là nhật ký truy cập ở định dạng combined, nên cả Nginx lẫn Apache đều phù hợp và không cần thêm mô-đun nào. Panel tìm nhật ký trong số các tệp tiêu chuẩn:
/var/log/nginx/access.log/var/log/apache2/access.log/var/log/apache2/other_vhosts_access.log/var/log/httpd/access_logNgoài ra, panel còn kiểm tra các tệp *access*.log và *requests*.log trong /var/log/nginx/, /var/log/apache2/ và /var/log/httpd/. Nhờ vậy cũng tìm được nhật ký mà một trang ghi vào tệp riêng bằng chỉ thị CustomLog — ví dụ arciveo-monitor_requests.log do trình cài đặt Arcivéo tạo ra.
Chỉ một nhật ký được đọc: khi Nginx đứng trước Apache, cộng hai nhật ký lại sẽ đếm mỗi yêu cầu hai lần. Panel lấy nhật ký đầu tiên trong danh sách trên có được ghi trong một ngày gần nhất (các tệp tìm theo mẫu tên được thử sau đó, mới nhất trước); nếu suốt một ngày không tệp nào được ghi, panel lấy tệp không rỗng mới nhất. Vì thế, nhật ký bị logrotate làm rỗng hoặc còn sót lại từ một máy chủ web đã tắt không còn che mất nhật ký đang hoạt động. Phần cuối của nhật ký được đọc (3 MB) và kết quả được lưu đệm 5 phút — vì thế trên một trang có nhiều lưu lượng, khoảng thời gian đã chọn có thể không được phủ hết; phạm vi thực tế được ghi phía trên biểu đồ.
adm, còn người dùng web lại không thuộc nhóm này. Trình cài đặt Arcivéo thêm người dùng đó vào nhóm; sau khi cài đặt thủ công, một wrapper nhỏ của root chỉ được phép làm đúng một việc — in nhật ký ra — sẽ giải quyết vấn đề (trang ModSecurity cũng hoạt động như vậy). Wrapper chọn nhật ký theo cùng quy tắc với panel. Lệnh hiển thị ngay trên trang đó; đây cũng chính là lệnh ấy. Hãy dán toàn bộ — đây là một lệnh duy nhất:
Người dùng web có thể khác www-data — hãy kiểm tra pool PHP-FPM của trang chạy dưới người dùng nào (ps -o user= -C php-fpm) và điền tên đó vào dòng sudoers. Nếu tên nhật ký không chứa access lẫn requests, hãy thêm đường dẫn của nó vào đầu dòng L=… bên trong wrapper.
Các lần thử khai thác lỗ hổng đã biết. Bảng điều khiển đối chiếu các yêu cầu trong nhật ký với chữ ký của khoảng hai mươi mã khai thác phổ biến: PHP-CGI, duyệt thư mục trái phép trong Apache, PHPUnit, Log4Shell, lỗ hổng của router, camera và cổng VPN. Với mỗi lần thử, bảng cho biết nó có thể thành công trên máy chủ này không, dựa trên dữ kiện: phiên bản Apache và PHP đã cài, có Java hay không và mã phản hồi của máy chủ với yêu cầu tệp. Chỉ những gì thật sự có thể thành công mới được đánh dấu đỏ.
Gia cố máy chủ web. Bảng điều khiển gửi yêu cầu tới từng trang trên máy chủ qua 127.0.0.1 và kiểm tra những gì khách truy cập nhận được: phiên bản máy chủ web và PHP có lộ ra không, phương thức TRACE có bật không và có các header bảo vệ Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy và Content-Security-Policy không. Danh sách trang lấy từ địa chỉ dùng để mở bảng điều khiển và từ các tệp máy chủ ảo, nếu bảng điều khiển đọc được. Kết quả cập nhật mỗi 10 phút.
Nếu thiếu thứ gì, bên dưới bảng sẽ hiện một lệnh duy nhất. Lệnh tạo tệp riêng zz-arciveo-hardening.conf và chỉ nạp lại máy chủ web sau khi kiểm tra cấu hình đạt; các header trang đã tự gửi không bị lặp lại. CSP không được đề xuất dưới dạng một dòng: chính sách phải soạn riêng cho từng trang, nếu không trang sẽ không tải được script, style và phông chữ của chính nó. Hoàn tác thay đổi trên Apache:
ServerSignature) không bị đánh dấu khi phiên bản máy chủ web đã được ẩn: không có phiên bản, nó chỉ hiện tên máy chủ và tên host.
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.Bảng điều khiển đã chạy và trên cùng máy chủ cần thêm một trang nữa — với tên miền riêng bên cạnh trình giám sát. Sau khi thiết lập tự động, máy chủ là một Apache + PHP-FPM thông thường, nên trang web cần ba thứ: thư mục riêng, vhost riêng và chứng chỉ riêng. Bảng điều khiển thì không đụng tới: nó theo dõi toàn bộ máy chủ, không cần bản thứ hai cho tên miền thứ hai.
site2.example.com là địa chỉ của trang mới. Đó có thể là một tên miền riêng (mycompany.com) hoặc một tên miền phụ (shop.mycompany.com) — với Apache thì không khác nhau, chỉ khác ở bản ghi DNS (bước 1) và việc cấp chứng chỉ (bước 5). site2 chỉ là tên ngắn của trang: thư mục /var/www/site2 và tệp cấu hình site2.conf được đặt theo tên đó. Nó không liên quan gì đến tên miền, Apache chỉ lấy địa chỉ từ ServerName; tên có thể là bất kỳ — ví dụ với shop.mycompany.com thì dùng shop là tiện: thư mục /var/www/shop, cấu hình shop.conf.
1. DNS. Trong bảng DNS tại nhà đăng ký tên miền, hãy tạo bản ghi A trỏ tới IP của máy chủ này:
Vài phút sau hãy kiểm tra: dig +short site2.example.com phải trả về IP của máy chủ.
2. Thư mục của trang.
3. vhost. Dán khối lệnh vào terminal nguyên vẹn — đường dẫn tới socket PHP-FPM được tự xác định:
4. Bật trang và kiểm tra cấu hình trước khi nạp lại:
5. SSL. certbot đã được thiết lập tự động cài sẵn; đến lúc này DNS phải trỏ về máy chủ:
Tên miền thứ ba và các tên miền tiếp theo được thêm y hệt — lặp lại các bước 1–5 với tên miền và thư mục khác.
Host không khớp với bất kỳ ServerName nào (truy cập bằng IP hoặc tên miền của người khác trỏ về máy chủ của bạn), Apache sẽ phục vụ trang được bật đầu tiên theo thứ tự bảng chữ cái trong /etc/apache2/sites-enabled/. Trang mặc định 000-default bị thiết lập tự động vô hiệu hóa, nên vai trò “trực” đó thuộc về vhost của bảng điều khiển (arciveo-monitor.conf) — điều này không ảnh hưởng tới các trang mở bằng tên riêng của chúng. Nếu muốn mở trang khác qua IP, hãy đặt tên tệp của nó để đứng trước theo bảng chữ cái (ví dụ 000-site2.conf).
site2_error.log và site2_access.log trong /var/log/apache2/.
.htaccess riêng điều phối (front controller), và một trang lồng bên trong sẽ trả về thứ khác với mong đợi. Hãy để các trang nằm cạnh nhau: /var/www/monitor, /var/www/site2.
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;security-watch-all.sh → /usr/local/bin/ (chmod +x) — chạy cron/security_watch.php của panel dưới danh nghĩa chủ sở hữu trang (trang “Sự kiện bảo mật”, dòng 2-57/5 trong crontab ở trên); security_watch.php đã nằm sẵn trong panel, không cần cài riêng;fleet-push-all.sh → /usr/local/bin/ (chmod +x) — gửi bản tóm tắt máy chủ về tài khoản cá nhân thông qua cron/fleet_push.php của panel (dòng 3,18,33,48 ở trên);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ủ.