Vì sao một Ubuntu server “chạy được web” chưa bao giờ là đủ an toàn?
Rất nhiều website bị tấn công không phải vì có lỗ hổng “quá lớn”, mà vì server được cấu hình theo kiểu mặc định là xong: mở quá nhiều dịch vụ, Nginx lộ thông tin phiên bản, PHP cho phép thực thi nguy hiểm, MySQL lắng nghe từ bên ngoài, quyền file quá rộng. Với web hosting, đặc biệt khi chạy nhiều site hoặc xử lý dữ liệu khách hàng, bảo mật không thể chỉ là cài ufw rồi yên tâm.
Cách hiệu quả hơn là tiếp cận theo tư duy phòng thủ nhiều lớp. Mỗi lớp không cần hoàn hảo, nhưng khi ghép lại sẽ làm giảm đáng kể khả năng bị khai thác và hạn chế thiệt hại nếu một lớp bị xuyên thủng. Trong bài viết này, chúng ta sẽ đi theo từng lớp bảo mật trên Ubuntu server dành cho web hosting, tập trung vào Nginx, PHP và MySQL, kèm các khuyến nghị thực tế để dễ áp dụng.
Lớp 1: Cứng hóa Ubuntu trước khi nghĩ đến ứng dụng
Trước khi tối ưu Nginx hay PHP, hãy đảm bảo hệ điều hành không trở thành điểm yếu nền tảng.
Cập nhật và tối giản bề mặt tấn công
Các nguyên tắc cơ bản nhưng rất hay bị bỏ qua:
– Cập nhật bảo mật định kỳ với apt update && apt upgrade hoặc bật unattended-upgrades.
– Chỉ cài đúng thứ cần dùng: Nginx, PHP-FPM, MySQL, công cụ giám sát; tránh giữ lại dịch vụ thừa như FTP cũ, mail server không dùng, database phụ.
– Tắt hoặc vô hiệu hóa service không cần thiết bằng systemctl disable --now.
Mỗi service chạy trên server là thêm một cổng rủi ro. Server càng gọn, khả năng bị dò quét và khai thác càng thấp.
Bảo vệ truy cập SSH
SSH gần như luôn là cổng quản trị quan trọng nhất. Nên áp dụng:
– Tắt đăng nhập bằng mật khẩu, dùng SSH key.
– Đổi port SSH không phải để “ẩn hoàn toàn”, mà để giảm bot scan tự động.
– Tắt đăng nhập trực tiếp bằng root.
– Bật Fail2ban để chặn brute-force.
– Giới hạn IP quản trị nếu có thể, qua firewall.
Firewall là lớp lọc đầu tiên
Với Ubuntu, ufw đủ tốt cho đa số nhu cầu hosting:
– Chỉ mở 80, 443, và cổng SSH quản trị.
– Không public 3306 nếu MySQL chỉ dùng nội bộ.
– Không mở trực tiếp cổng PHP-FPM.
Điểm mấu chốt là: chỉ những gì thật sự phải truy cập từ Internet mới được mở.
Lớp 2: Bảo mật Nginx như lớp biên của toàn hệ thống
Nginx là thứ đầu tiên tiếp xúc với Internet, nên cấu hình của nó quyết định bạn chặn được bao nhiêu rủi ro từ ngoài vào.
Ẩn thông tin và giảm dấu vết
Mặc định, web server thường để lộ khá nhiều thông tin. Bạn nên:
– Tắt hiển thị phiên bản bằng server_tokens off;
– Loại bỏ header thừa nếu có module phù hợp
– Dùng trang lỗi tùy chỉnh thay vì phản hồi mặc định
Mục tiêu là không cung cấp miễn phí dữ liệu cho attacker về stack mà bạn đang chạy.
Ép HTTPS và cấu hình TLS đúng cách
HTTPS giờ không chỉ để “có ổ khóa”, mà còn là lớp bảo vệ phiên đăng nhập, cookie và dữ liệu form.
Các điểm cần có:
– Chuyển hướng toàn bộ HTTP sang HTTPS
– Dùng TLS 1.2/1.3
– Vô hiệu các cipher yếu
– Bật HSTS sau khi chắc chắn site đã chạy ổn qua HTTPS
– Gia hạn chứng chỉ tự động với Let’s Encrypt
Ngoài ra, nên thêm các header bảo mật quan trọng:
– X-Frame-Options
– X-Content-Type-Options
– Referrer-Policy
– Content-Security-Policy nếu ứng dụng cho phép
Đây là lớp nhỏ nhưng rất giá trị trong việc giảm clickjacking, MIME sniffing và một số kiểu XSS.
Giới hạn request bất thường
Nginx có thể giúp giảm nhiều kiểu tấn công trước khi request chạm vào PHP:
– Giới hạn kích thước body bằng client_max_body_size
– Rate limit cho login, API nhạy cảm, hoặc XML-RPC nếu chạy WordPress
– Timeout hợp lý để chống giữ kết nối lâu
– Chặn truy cập vào file nhạy cảm như .env, .git, composer.json, wp-config.php backup
Một rule đơn giản nhưng cực hữu ích là không cho thực thi PHP trong thư mục upload. Nếu attacker tải được file độc lên, họ vẫn khó biến nó thành shell.
Lớp 3: Cô lập và siết PHP để giảm thiểu hậu quả
Phần lớn website động trên Ubuntu dùng PHP-FPM. Đây thường là nơi lỗ hổng ứng dụng bị biến thành thực thi mã, nên cần siết kỹ.
Không chạy mọi website dưới cùng một user
Nếu bạn host nhiều site, đừng để tất cả cùng chạy chung một pool PHP với cùng quyền. Thay vào đó:
– Mỗi website nên có PHP-FPM pool riêng
– Mỗi pool chạy dưới user/group riêng
– Thư mục web chỉ cấp quyền đúng mức cần thiết
Lợi ích rất rõ: nếu một site bị khai thác, attacker khó lan sang site khác.
Tắt các hàm và tính năng nguy hiểm
Trong php.ini, nên xem xét:
– expose_php = Off
– display_errors = Off trên production
– log_errors = On
– allow_url_fopen và allow_url_include chỉ bật nếu thật sự cần
– disable_functions với các hàm nguy hiểm như exec, shell_exec, system, passthru, proc_open
Không phải mọi ứng dụng đều tương thích với danh sách chặn mạnh tay, nên cần kiểm tra trước. Nhưng nguyên tắc là: PHP không nên có quyền gọi shell nếu ứng dụng web không cần.
Giới hạn tài nguyên và đường dẫn truy cập
Bạn nên đặt giới hạn để một script lỗi không kéo sập cả server:
– memory_limit
– max_execution_time
– max_input_vars
– post_max_size
– upload_max_filesize
Nếu phù hợp, dùng thêm:
– open_basedir để giới hạn thư mục PHP được phép truy cập
– session.cookie_httponly = On
– session.cookie_secure = On khi dùng HTTPS
– cgi.fix_pathinfo = 0 để tránh một số kiểu xử lý path nguy hiểm
PHP càng ít quyền, ít thời gian chạy và ít khả năng chạm ra ngoài phạm vi app, mức độ thiệt hại càng thấp khi có lỗi.
Lớp 4: Gia cố MySQL để dữ liệu không bị “mở cửa sau”
MySQL thường chứa tài sản quan trọng nhất: tài khoản, đơn hàng, thông tin khách hàng, token. Nhưng nhiều server lại để database ở trạng thái quá dễ dãi.
Chạy MySQL ở chế độ nội bộ nếu có thể
Nếu web app và database cùng một máy, hãy để MySQL chỉ lắng nghe ở 127.0.0.1. Điều này giúp:
– Không lộ cổng 3306 ra Internet
– Giảm nguy cơ brute-force từ bên ngoài
– Đơn giản hóa firewall
Chỉ bind ra mạng riêng khi thật sự cần kiến trúc nhiều máy.
Dùng tài khoản riêng, quyền tối thiểu
Một lỗi rất phổ biến là ứng dụng dùng tài khoản có quyền quá cao, thậm chí gần như root. Thay vào đó:
– Tạo một user riêng cho từng ứng dụng
– Chỉ cấp quyền cần thiết trên đúng database
– Tránh cấp GRANT, SUPER, FILE, DROP nếu không cần
Nguyên tắc quyền tối thiểu ở database quan trọng không kém ở hệ điều hành.
Chạy mysql_secure_installation nhưng đừng dừng ở đó
Script này giúp bạn:
– Đặt mật khẩu mạnh cho tài khoản quản trị
– Xóa anonymous user
– Tắt remote root login
– Xóa database test
Tuy nhiên, cần đi xa hơn:
– Bật log phù hợp để phát hiện truy vấn bất thường
– Sao lưu định kỳ và kiểm tra khả năng restore
– Mã hóa backup nếu lưu ngoài server
– Theo dõi số lần đăng nhập lỗi hoặc kết nối bất thường
Database an toàn không chỉ là “khó vào”, mà còn là khó mất dữ liệu và dễ phục hồi.
Lớp 5: Quyền file, giám sát và ứng phó sự cố
Nhiều vụ xâm nhập kéo dài hàng tuần chỉ vì admin không có log đủ tốt, hoặc quyền file cho phép sửa toàn bộ mã nguồn từ web process.
Phân quyền file đúng cách
Một mô hình phổ biến:
– File code: chỉ owner được ghi
– Web server chỉ cần quyền đọc, và ghi vào một số thư mục cụ thể như storage, cache, uploads
– Không dùng 777
– Tách rõ thư mục deploy, log và dữ liệu người dùng
Điều này giúp giảm nguy cơ web shell sửa mã nguồn hoặc cài backdoor sâu hơn.
Log và giám sát là “báo động sớm”
Bạn nên theo dõi ít nhất:
– auth.log cho SSH
– access/error log của Nginx
– log PHP-FPM
– log MySQL
– cảnh báo từ Fail2ban, ufw, hoặc công cụ giám sát như Netdata/Prometheus
Không cần hệ thống SIEM quá phức tạp ngay từ đầu, nhưng phải có khả năng trả lời các câu hỏi cơ bản: ai đăng nhập, khi nào, từ đâu, request nào bất thường, tiến trình nào tiêu tốn tài nguyên.
Luôn chuẩn bị cho tình huống bị xâm nhập
Bảo mật tốt không đồng nghĩa với miễn nhiễm tuyệt đối. Hãy chuẩn bị:
– Backup tự động, lưu ở nơi khác server chính
– Kế hoạch rotate password và SSH key
– Quy trình cách ly site bị nhiễm
– Checklist rà soát: cron lạ, file mới bất thường, process đáng ngờ, thay đổi trong config Nginx/PHP
Khả năng phục hồi nhanh thường quan trọng ngang khả năng phòng thủ.
Kết luận: bảo mật theo lớp là cách thực tế nhất cho web hosting
Để secure một Ubuntu server cho web hosting, không có “một lệnh thần kỳ” nào đủ cả. Điều hiệu quả là kết hợp nhiều lớp:
– Ubuntu tối giản, cập nhật và khóa SSH
– Nginx làm lớp chắn đầu tiên với HTTPS, header và rate limit
– PHP bị cô lập, hạn chế hàm nguy hiểm và tài nguyên
– MySQL chỉ mở đúng nơi, đúng user, đúng quyền
– File permission, log và backup hỗ trợ phát hiện và phục hồi
Nếu phải ưu tiên theo thứ tự, hãy làm ngay 5 việc: tắt SSH password login, bật firewall tối thiểu, ép HTTPS, tách PHP-FPM pool theo site, và không public MySQL ra Internet. Chỉ riêng các bước này đã nâng mức an toàn của server lên đáng kể.
Bảo mật tốt không phải làm một lần rồi quên. Đó là một quy trình vận hành liên tục: cập nhật, kiểm tra, giám sát và cải tiến. Với web hosting, tư duy “nhiều lớp, ít quyền, dễ phục hồi” luôn là chiến lược bền vững nhất.