Hệ thống cảnh báo CPU của một node VPS vọt lên 100%. Bạn SSH vội vào server và gõ dòng lệnh quen thuộc để tìm nguyên nhân:
tail -f /var/log/auth.log
Trống trơn. Kẻ tấn công đã kịp xóa sạch mọi dấu vết trước khi cắm một script đào coin ẩn sâu vào hệ thống. Trong một hạ tầng phân tán với hàng chục, thậm chí hàng trăm node chạy microservices, việc đuổi theo log cục bộ trên từng máy chủ vô cùng khó khăn. Đến khi bạn tìm ra nguyên nhân thì thiệt hại đã rồi.
Đó là lúc các SysAdmin và kỹ sư SecOps nhận ra tính quan trọng của một hệ thống centralized logging. Tuy nhiên, dựng cụm ELK thì dễ, nhưng dựng sao cho chặt chẽ lại là một bài toán hóc búa. Việc mở toang các cổng nhận dữ liệu ra ngoài public không khác gì tự giao quyền truy cập hạ tầng cho hacker.
Vậy làm thế nào để giám sát log VPS tập trung Elastic Stack mà không để lộ public port nào ra Internet? Liệu có cách nào ép toàn bộ traffic log phải đi qua một chốt chặn bảo mật được mã hóa và xác thực nghiêm ngặt? Hãy cùng bóc tách kiến trúc Zero Public Ports phiên bản hiệu quả hiện nay.
Nỗi đau của SysAdmin: Log phân mảnh và rủi ro khi mở public port
Truy vết sự cố trên hàng chục VPS rời rạc, thách thức của đội SecOps
Khi quản lý một dự án nhỏ, việc SSH vào 1-2 VPS để đọc file access log của Nginx hay system log là chuyện trong tầm tay. Nhưng khi hệ thống scale lên, cách làm thủ công này không còn hiệu quả bởi những điểm yếu nghiêm trọng:
- Bị xóa dấu vết (Anti-Forensics): Hacker chuyên nghiệp luôn có thói quen dọn dẹp file log nội bộ (
/var/log/secure, /var/log/auth.log) ngay sau khi leo thang đặc quyền thành công. Nếu bạn không có cơ chế đẩy log đi thời gian thực (real-time streaming) ra một máy chủ khác, bạn sẽ mất đi bằng chứng số để làm forensics.
- Không thể đối chiếu chéo (Correlation): Các cuộc tấn công Brute-force hoặc rà soát lỗ hổng (scanning) hiếm khi nhắm vào một IP. Chúng tấn công rải rác trên toàn bộ dải IP VPS của bạn. Nhìn vào màn hình
tail của một máy, bạn không thể vẽ ra bức tranh tổng thể của một cuộc tấn công có tổ chức.
Mở cổng 9200/5601 ra Internet: Giao chìa khóa cho Shodan và Botnet
Để giải quyết bài toán phân mảnh, một số tài liệu cũ thường hướng dẫn cài đặt Elasticsearch và Kibana, sau đó cấu hình network.host: 0.0.0.0 để mở thẳng cổng 9200 và 5601 ra Internet. Đây là một sai lầm cấu hình kinh điển dẫn đến thảm họa.
Bạn có biết các hệ thống rà soát của Shodan hay Censys chỉ mất vài giờ để tìm ra cụm Elasticsearch cấu hình lỏng lẻo của bạn?
Một khi cổng 9200 (REST API của Elasticsearch) bị mở công khai:
- Bất kỳ ai cũng có thể dùng cURL gọi thẳng vào endpoint
/_cat/indices để list toàn bộ cơ sở dữ liệu của bạn.
- Dữ liệu log nhạy cảm (chứa IP thật của khách hàng, thông tin request, header bị rò rỉ token) bị tải về hoặc xóa sạch bằng một lệnh
DELETE /_all.
- Các nhóm Ransomware tự động sẽ mã hóa toàn bộ data streams của bạn và để lại một document yêu cầu tiền chuộc bằng Bitcoin.
Tương tự, giao diện Kibana (5601) nếu bị lộ sẽ trở thành bàn đạp để kẻ tấn công dò tìm lỗ hổng ứng dụng và leo thang đặc quyền vào sâu trong mạng lưới nội bộ.

Sự khác biệt giữa quản trị log cục bộ thủ công và hệ thống Centralized Logging an toàn.
Giải mã kiến trúc giám sát log VPS tập trung Elastic Stack an toàn (Zero Public Ports)
Để hệ thống bảo mật cao, nguyên tắc cốt lõi là: Elasticsearch và Kibana không bao giờ được nhìn thấy Internet trực tiếp.
Sức mạnh của Elastic Stack 9.x: Lược bỏ Logstash, tối ưu bằng Ingest Pipelines
Nhiều kiến trúc trước đây thường sử dụng Logstash làm trạm trung chuyển (Nginx sang Logstash sang Elasticsearch) để phân tích cú pháp (parse) log bằng Grok. Tuy nhiên, với khả năng của các phiên bản Elastic Stack 8.x và 9.x hiện hành (như bản 9.4.x / 9.5.x của năm 2026), điều này không còn bắt buộc.
Filebeat và Elastic Agent hiện nay có thể bọc mTLS, gửi thẳng dữ liệu qua Nginx Proxy và truyền trực tiếp vào Elasticsearch. Bản thân Elasticsearch sẽ sử dụng Ingest Pipelines tích hợp sẵn để tự động parse Grok và map GeoIP ngay tại khâu nạp dữ liệu. Việc loại bỏ Logstash giúp hạ tầng giám sát của bạn bớt đi một thành phần cồng kềnh, tiết kiệm đáng kể lượng RAM và CPU cho máy chủ trung tâm.
Nginx Stream (TCP mTLS): Chốt chặn biên bảo mật chặt chẽ
Thay vì mở cổng Elasticsearch, ta dựng một Nginx Proxy (phiên bản 1.30.4 stable hoặc 1.31.3 mainline) đứng ở ranh giới mạng. Hoặc đối với các mạng cô lập, nhiều developer chọn cách tự tạo Proxy Server trên VPS Ubuntu/CentOS với Squid để làm cổng Forward Proxy.
Tuy nhiên, kiến trúc bài viết này tập trung sử dụng Nginx TCP Stream (Layer 4) đóng vai trò là một Reverse Proxy bọc TLS. Nginx mở một cổng (ví dụ: 5544), ép tất cả VPS nguồn (client) phải trình ra chứng chỉ hợp lệ thông qua cơ chế Mutual TLS (mTLS) mới được phép kết nối. Nếu chứng chỉ đúng, Nginx sẽ định tuyến packet TCP thô truyền vào cổng 9200 của Elasticsearch nội bộ. Nếu chứng chỉ sai, Nginx drop packet ngay lập tức ở tầng mạng.

Sơ đồ luồng dữ liệu: Filebeat định tuyến qua Nginx Stream mTLS, chặn đứng Botnet ngay tại biên mạng.
Hướng dẫn cấu hình luồng đẩy log không lọt khe
Dưới đây là các bước thực chiến cấu hình kiến trúc Zero Public Ports, lược bỏ Logstash và tối ưu hóa cho Elastic Stack đời mới.
Bước 1: Khóa chặt Elasticsearch & Kibana (chỉ bind Localhost/VPN)
Khác với các phiên bản 6.x hay 7.x cũ, từ Elastic 8.0 trở đi, tính năng bảo mật X-Pack (xpack.security.enabled) đã được BẬT MẶC ĐỊNH. Bạn không cần phải cấu hình thủ công tính năng này nữa.
Nhiệm vụ của bạn bây giờ chỉ là đóng kết nối mạng. Mở file /etc/elasticsearch/elasticsearch.yml và cấu hình:
# Bắt buộc Elasticsearch chỉ lắng nghe trên loopback hoặc IP của mạng VPN nội bộ (vd: 10.8.0.1)
network.host: "127.0.0.1"
http.port: 9200
# Các tính năng bảo mật mặc định (không sửa)
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
Làm tương tự với /etc/kibana/kibana.yml:
server.host: "127.0.0.1"
elasticsearch.hosts: ["https://127.0.0.1:9200"]
Cuối cùng, dùng ufw (Uncomplicated Firewall) để khóa cổng ở tầng OS.
Khóa cổng 9200:
sudo ufw deny 9200/tcp
Khóa cổng 5601:
sudo ufw deny 5601/tcp
Lúc này, Kibana chỉ có thể được truy cập thông qua SSH Local Port Forwarding hoặc các giải pháp mã hóa mạng nhờ vào việc xây dựng kiến trúc bảo mật Zero Trust bằng WireGuard trên VPS nội bộ của đội ngũ quản trị.
Bước 2: Thiết lập proxy biên với CA nội bộ & IP Whitelist
Để mTLS hoạt động, bạn không thể dùng chứng chỉ Let’s Encrypt vì nó là public. Hãy tự dựng một Internal Certificate Authority (CA) bằng OpenSSL. Đồng thời, việc kết hợp kỹ năng cấu hình Reverse Proxy Nginx nâng cao sẽ giúp lọc bớt các request độc hại.
Tạo CA nội bộ và cấp chứng chỉ cho VPS client:
Tạo khóa (Key) cho CA gốc:
openssl genrsa -out ca.key 4096
Tạo chứng chỉ (Certificate) cho CA gốc:
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=SecOps-Internal-CA"
Cấp khóa cho VPS Client số 1:
openssl genrsa -out vps1.key 2048
Tạo yêu cầu ký chứng chỉ (CSR) cho VPS Client số 1:
openssl req -new -key vps1.key -out vps1.csr -subj "/CN=VPS-Node-01"
Tạo file cấu hình extfile khai báo EKU = clientAuth:
echo -e "extendedKeyUsage = clientAuth\n" > client.ext
Ký chứng chỉ client:
openssl x509 -req -in vps1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out vps1.crt -days 365 -extfile client.ext
Cấu hình Nginx Stream (Layer 4):
Mở /etc/nginx/nginx.conf, thêm khối stream (phải đặt ngang hàng với khối http):
stream {
upstream elasticsearch_backend {
server 127.0.0.1:9200; # Đâm thẳng vào Elasticsearch nội bộ
}
server {
listen 5544 ssl; # Cổng mở ra Internet để nhận log
# 1. IP Whitelist - Chặn ngay từ vòng ngoài
allow 203.0.113.0/24; # Chỉ cho phép dải IP của các VPS Production
deny all;
# 2. Cấu hình mTLS: Ép buộc xác thực chứng chỉ Client
ssl_certificate /etc/nginx/certs/proxy-server.crt;
ssl_certificate_key /etc/nginx/certs/proxy-server.key;
ssl_client_certificate /etc/nginx/certs/ca.crt; # Dùng CA nội bộ để xác minh Client
# Chốt chặn quan trọng: Bắt buộc client phải có chứng chỉ hợp lệ
ssl_verify_client on;
proxy_pass elasticsearch_backend;
}
}
Bước 3: Cấu hình Filebeat định tuyến thẳng vào Elasticsearch
Mang cặp chứng chỉ vps1.crt và vps1.key cùng CA gốc ca.crt lên VPS nguồn. Thay vì trỏ output ra Logstash, ta cấu hình filebeat.yml xuất thẳng qua Nginx Proxy vào Elasticsearch bằng API Key:
filebeat.inputs:
- type: filestream
id: system-auth-logs
paths:
- /var/log/auth.log
# Bỏ qua Logstash, cấu hình Output Elasticsearch
output.elasticsearch:
hosts: ["https://proxy.yourdomain.com:5544"]
api_key: "ID_CỦA_KEY:MÃ_API_KEY_BÍ_MẬT"
# Cấu hình TLS Client để vượt qua Nginx Proxy
ssl.certificate_authorities: ["/etc/filebeat/certs/ca.crt"]
ssl.certificate: "/etc/filebeat/certs/vps1.crt"
ssl.key: "/etc/filebeat/certs/vps1.key"
Lưu ý kỹ thuật: Chuỗi API Key dán vào Filebeat bắt buộc phải chứa cả ID và Key nối với nhau bằng dấu hai chấm (Ví dụ: id_abc:key_xyz). Đừng chỉ copy mỗi phần mã bí mật kẻo Filebeat sẽ báo lỗi 401 Unauthorized ngay lập tức.
Khi network chập chờn, tính năng Backpressure và cơ chế Store-and-Forward nội bộ của Filebeat sẽ tự động đệm (buffer) file log, sau đó gửi bù khi kết nối mạng phục hồi. Không dòng log nào bị drop.
Khai thác dữ liệu trên Kibana: Dashboard và alerting thực chiến
Dữ liệu an toàn cập bến là lúc khả năng phân tích của Elastic lên tiếng.
Trực quan hóa bản đồ tấn công SSH Brute-force qua GeoIP (Ingest Pipeline)
Nếu chỉ nhìn vào raw log với hàng ngàn dòng Failed password for root from 192.168.x.x, developer sẽ không thể nhận diện được Patterns tấn công. Thay vì dùng Logstash, ta cấu hình một Ingest Pipeline ngay trên Elasticsearch để bóc tách IP và gán GeoIP:
PUT _ingest/pipeline/ssh-geoip-pipeline
{
"description": "Parse SSH Auth logs and add GeoIP",
"processors": [
{
"grok": {
"field": "message",
"patterns": ["%{SYSLOGTIMESTAMP} %{SYSLOGHOST} sshd\\[%{POSINT}\\]: Failed password for .* from %{IP:attacker_ip} port .*"]
}
},
{
"geoip": {
"field": "attacker_ip",
"target_field": "geo"
}
}
]
}
Lưu ý: Để vẽ được bản đồ trên Kibana, dữ liệu không thể lưu ở định dạng text thông thường. Bạn phải cấu hình Index Template để ép kiểu dữ liệu của trường geo.location thành geo_point.
Mở Kibana > Maps, nạp lớp layer từ Data Stream của bạn. Một bản đồ Heatmap sẽ hiện ra, cho bạn thấy rõ cuộc tấn công SSH Brute-force đang bắt nguồn từ quốc gia hay dải ASN nào.

Cơ chế hoạt động của Ingest Pipeline: Biến raw log vô hồn thành tọa độ địa lý (geo_point) theo thời gian thực.
Cảnh báo realtime khi request web 4xx/5xx tăng đột biến
Hệ thống của bạn có thể đang bị DDoS HTTP Flood hoặc đang gặp lỗi deploy gây tràn RAM (OOM) khiến Nginx trả về lỗi 502/503 liên tục. Đừng chờ khách hàng phàn nàn mới hành động.
Trong Kibana Alerting, hãy thiết lập một Rule: Nếu lượng log Nginx trả về mã HTTP 500-599 tăng vọt quá 100 request/phút từ một Data Stream cụ thể, bắn ngay Webhook cảnh báo về kênh Slack hoặc Telegram của team DevOps. Việc phản ứng chủ động giúp giảm thiểu MTTR (Mean Time To Recovery) đáng kể.
Best Practices & Hardening (phòng thủ chiều sâu)
Để cụm Elastic hoạt động ổn định qua nhiều năm, bạn cần áp dụng các biện pháp phòng thủ lớp sâu (Defense in Depth).
Data Stream Lifecycle: Quản lý vòng đời log tối giản, chống đầy ổ cứng
Trước đây, SysAdmin thường phải vật lộn với ILM (Index Lifecycle Management) bằng cách chia phần cứng thành các node Hot, Warm, Cold phức tạp. Từ các phiên bản Elastic mới, hãng đã giới thiệu Data Stream Lifecycle, một cơ chế quản lý dữ liệu chuỗi thời gian (time-series) tập trung vào sự tối giản.
Thay vì quản lý các index rời rạc như vps-logs-2026.08.17, bạn đẩy toàn bộ log vào một Data Stream. Sau đó, chỉ cần cấu hình retention (thời gian lưu giữ). Ví dụ: Set retention = 30 ngày. Elasticsearch sẽ tự động làm nhiệm vụ Rollover dữ liệu nền và tự động xóa (delete) các luồng dữ liệu cũ hơn 30 ngày mà bạn không cần phải chia Tier phần cứng phức tạp. Điều này đảm bảo ổ cứng server của bạn không bao giờ bị đầy vì quá tải log.
Tích hợp Fail2ban tại proxy và sử dụng API Key thay thế password
Chặn IP tự động với Fail2ban:
Khi một IP lạ cố kết nối vào cổng mTLS của Nginx mà không có chứng chỉ CA nội bộ, Nginx sẽ từ chối kết nối và ghi một lỗi 495 Client Certificate Error hoặc 496 No Cert vào file error.log.
Hãy viết một bộ lọc (jail) cho Fail2ban quét trực tiếp file error log này. Chỉ cần một IP có 2 lần gửi sai chứng chỉ, Fail2ban sẽ lập tức ném một rule DROP vào iptables/UFW, khóa chặt IP đó trong 24 giờ. Bạn có thể tham khảo thêm hướng dẫn bảo mật VPS Fail2Ban chống Brute Force để tối ưu cấu hình.
Bảo mật Least Privilege bằng API Key:
Không nên nhúng mật khẩu của superuser elastic vào trong file cấu hình Filebeat trên các VPS. Hãy tạo các API Keys thông qua Kibana, cấp cho nó quyền tối thiểu (Least Privilege) là chỉ được phép create_doc vào một Data Stream chỉ định. Nếu một VPS bị tấn công và lộ API Key, kẻ tấn công cũng không thể dùng key đó để đọc, xóa hay truy vấn bất kỳ dữ liệu nào khác trong hệ thống.
Câu hỏi thường gặp (FAQ)
1. Tại sao không dùng VPN (WireGuard/Tailscale) thay cho Nginx mTLS Proxy?
VPN buộc phải cài đặt client và cấp IP ảo cho từng VPS, rất khó scale và quản lý khi hạ tầng lên tới hàng trăm node. Nginx mTLS Proxy nhẹ gọn hơn, kiểm soát luồng dữ liệu ở tầng Layer 4 (chỉ cho phép đẩy log qua một cổng 5544) thay vì cấp quyền truy cập vào toàn bộ dải mạng.
2. Có bắt buộc phải cài đặt Logstash trong kiến trúc này không?
Không. Với các phiên bản Elastic 8.x và 9.x hiện nay, Filebeat/Elastic Agent có thể gửi log xuyên qua Proxy truyền trực tiếp vào Elasticsearch. Việc parse Grok hay map GeoIP sẽ do Ingest Pipelines đảm nhận, giúp tiết kiệm triệt để tài nguyên (RAM/CPU) cho server trung tâm.
3. Nếu chứng chỉ mTLS của một VPS bị kẻ tấn công lấy cắp thì sao?
Bạn chỉ cần Revoke (thu hồi) chứng chỉ của VPS bị lộ trên CA nội bộ, sau đó nạp file CRL (Certificate Revocation List) vào Nginx. Kẻ tấn công sẽ bị chặn lập tức, trong khi các VPS khác vẫn đẩy log bình thường mà không bị gián đoạn.
4. Elasticsearch báo lỗi đầy ổ cứng (Disk Watermark) thì phải làm gì?
Tránh xóa index thủ công. Hãy sử dụng Data Stream Lifecycle (hoặc ILM ở bản cũ) cấu hình thời gian retention. Hệ thống sẽ tự động cuộn (rollover) và xóa log cũ hơn 30 ngày ngầm ở background.
5. Nginx Stream có làm mất IP gốc của VPS nguồn không?
Có, nếu bạn không cấu hình thêm. Elasticsearch sẽ chỉ nhìn thấy IP của Nginx. Để khắc phục, bạn cần bật tính năng PROXY protocol trên khối upstream của Nginx và cấu hình endpoint của Elasticsearch để nhận diện lại IP gốc thật sự.
Kết luận
Việc giám sát log VPS tập trung Elastic Stack là tiêu chuẩn vận hành bắt buộc (SOP) đối với mọi hạ tầng hiện đại. Bằng việc khéo léo chèn một lớp Forward Proxy kết hợp cơ chế mTLS ở ranh giới mạng, đồng thời khai thác khả năng của Data Streams và Ingest Pipelines, bạn đã giải quyết trọn vẹn bài toán hóc búa: Thu thập dữ liệu real-time mà vẫn duy trì kiến trúc Zero Public Ports.
Khi hệ thống đã scale lên đến hàng chục node, đừng quản trị hạ tầng bằng những lệnh tail thủ công nữa. Dữ liệu log chính là thành phần cốt lõi của SecOps, hãy bảo vệ nó từ những lớp mạng ngoài cùng.
Tài liệu tham khảo