Nếu bạn đang quản trị một máy chủ VPS chạy CentOS, RHEL, Fedora (hoặc các bản fork như AlmaLinux, Rocky Linux), có lẽ bạn đã từng ở trong tình huống này:
Bạn vừa cài xong một dịch vụ mới. Có thể là deploy code web, cài đặt VNC, hoặc đổi cổng SSH mặc định (từ 22 sang cổng khác). Mọi thứ dường như đã sẵn sàng, bạn kiểm tra systemctl status thấy dịch vụ đang active (running)… nhưng bạn không thể truy cập được.
Web server báo lỗi 403 Forbidden. Cổng SSH mới thì “Connection Timed Out” (trong khi bài viết Không SSH được vào VPS Linux: 10 nguyên nhân và cách sửa lỗi đã loại trừ 9 lý do kia).
Sau một hồi “vò đầu bứt tai” và tìm kiếm, bạn thấy một giải pháp “thần kỳ” trên mạng:
setenforce 0
Và lạ thay, mọi thứ hoạt động! Dịch vụ của bạn chạy được ngay lập tức.
Lệnh setenforce 0 (chuyển SELinux sang chế độ Permissive) đã “cứu” bạn. Nhưng nó cũng giống như tháo còi báo cháy vì nó… quá ồn ào. Bạn đã vô hiệu hóa một trong những lớp bảo mật mạnh mẽ nhất của Linux chỉ vì bạn chưa hiểu nó.
Bạn không cô đơn. Hầu hết các quản trị viên (SysAdmin) đều “sợ” SELinux và chọn cách tắt nó đi.
Bài viết này sẽ giúp bạn thay đổi tư duy đó. Chúng ta sẽ giải mã SELinux là gì một cách đơn giản nhất, và quan trọng hơn, học cách “sống chung” với nó để cấu hình dịch vụ (như SSH, Web Server) một cách đúng đắn.
Nội dung chính bạn sẽ học:
- SELinux là một lớp bảo mật MAC (bắt buộc), hoạt động như một “người bảo vệ” bên cạnh “chìa khóa” (quyền
rwxtruyền thống).- Lệnh
setenforce 0(chế độ Permissive) chỉ nên dùng để gỡ lỗi, không phải là giải pháp vĩnh viễn vì nó làm giảm bảo mật.- 90% lỗi SELinux được giải quyết bằng cách sửa “Nhãn” (Context) hoặc bật “Công tắc” (Booleans).
- Bạn sẽ học cách sửa lỗi cổng SSH (
semanage port) và lỗi thư mục web (semanage fcontext&restorecon) mà không cần tắt SELinux.
SELinux là gì? (Giải thích “không kỹ thuật”)
SELinux là viết tắt của Security-Enhanced Linux (Linux tăng cường bảo mật). Đây là một mô-đun bảo mật cấp nhân (kernel-level) được phát triển ban đầu bởi Cơ quan An ninh Quốc gia Hoa Kỳ (NSA).
Nó không phải là tường lửa (như Firewalld, UFW) và cũng không phải là chương trình diệt virus.
Cách giải thích “không kỹ thuật” dễ hiểu nhất là qua phép ẩn dụ sau:
Phép ẩn dụ: Bảo vệ 2 lớp của tòa nhà
Hãy tưởng tượng hệ thống Linux của bạn là một tòa nhà văn phòng được bảo vệ nghiêm ngặt.
Lớp 1: Quyền Linux truyền thống (DAC – rwx)
- Đây là hệ thống Kiểm soát truy cập tùy ý (Discretionary Access Control).
- Nó giống như thẻ từ và chìa khóa của tòa nhà.
- Nếu bạn (user) có chìa khóa của phòng Kế toán, bạn được phép vào phòng đó và toàn quyền làm mọi thứ bên trong (đọc, ghi, xóa file). Chủ sở hữu (owner) của căn phòng quyết định ai được có chìa khóa.
Lớp 2: SELinux (MAC)
- Đây là hệ thống Kiểm soát truy cập bắt buộc (Mandatory Access Control).
- Nó giống như một anh bảo vệ nghiêm ngặt đi theo bạn bên trong tòa nhà.
- Anh bảo vệ này không quan tâm bạn có chìa khóa hay không. Anh ta có một cuốn sổ “Chính sách” (Policy) từ ban quản lý tòa nhà (Hệ thống) quy định rõ:
- “Nhân viên Kế toán (
user_t) chỉ được vào phòng Kế toán (accounting_t).” - “Khi vào, anh ta chỉ được phép ĐỌC tài liệu (
accounting_file_t), cấm GHI ĐÈ hoặc MANG TÀI LIỆU ra ngoài.”
- “Nhân viên Kế toán (
Đó là lý do tại sao ngay cả khi bạn là root (Giám đốc, có chìa khóa mọi phòng), anh bảo vệ SELinux vẫn có thể chặn bạn nếu bạn cố làm điều gì đó “trái” với quy định bảo mật đã định sẵn.
Tại sao cần SELinux? (So sánh DAC vs. MAC)
Vậy tại sao chúng ta cần anh bảo vệ “phiền phức” đó? Bởi vì nếu chỉ dựa vào chìa khóa (DAC), điều gì sẽ xảy ra nếu một kẻ gian cướp được chìa khóa của Giám đốc (root)? Hắn sẽ có toàn quyền.
SELinux giải quyết vấn đề này. Giả sử hacker tấn công và chiếm được quyền thực thi của Web Server (ví dụ: Apache, httpd_t), anh bảo vệ SELinux vẫn “nhốt” hacker đó lại.
Dưới đây là bảng so sánh trực quan:
| Đặc điểm | DAC (Quyền Linux truyền thống – rwx) |
MAC (SELinux) |
| Ai quyết định? | Chủ sở hữu file (User quyết định) | Hệ thống quyết định (Policy) |
| Nguyên tắc | Tùy ý (Discretionary) | Bắt buộc (Mandatory) |
| Lỗ hổng | Hacker chiếm quyền root (hoặc apache) → có thể làm MỌI THỨ mà user đó có quyền. |
Hacker chiếm quyền apache → Vẫn bị “nhốt” trong lồng httpd_t, không thể đọc file /etc/passwd hay kết nối database mysqld_db_t. |
| Triết lý | “Làm mọi thứ, trừ những gì bị cấm.” | “Cấm mọi thứ, trừ những gì được cho phép.” |
3 chế độ hoạt động của SELinux (Enforcing, Permissive, Disabled)
Một trong những lý do khiến SELinux “khó chịu” là vì nó có 3 chế độ hoạt động, và bạn phải hiểu rõ mình đang ở đâu.
Bạn có thể kiểm tra nhanh chế độ hiện tại bằng lệnh: getenforce
Và xem chi tiết hơn bằng sestatus:
[root@vps ~]# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing <-- Đây là thứ bạn quan tâm
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection: enabled
Max kernel policy version: 33
Dưới đây là bảng giải thích 3 chế độ này:
| Chế độ | Hành vi | Khi nào dùng? | Lệnh đổi tạm thời |
| Enforcing | Chặn + Ghi Log: Đây là chế độ mặc định. SELinux sẽ thực thi chính sách, chặn mọi hành vi vi phạm và ghi log lại. | Môi trường Production. Đây là trạng thái cuối cùng, an toàn nhất của máy chủ. | setenforce 1 |
| Permissive | Không Chặn + Ghi Log: Đây là “chìa khóa vàng” để gỡ lỗi. SELinux không chặn bất cứ thứ gì, nhưng vẫn ghi log tất cả các hành vi vi phạm. | Khi gỡ lỗi (Troubleshooting). Lệnh setenforce 0 chính là chuyển về chế độ này. |
setenforce 0 |
| Disabled | Tắt hoàn toàn: SELinux bị tắt. Không chặn, không ghi log, không gán nhãn context cho file mới. | Không bao giờ (nếu có thể). Việc tắt Disabled sẽ khiến toàn bộ file trên hệ thống mất nhãn (label). Bật lại sẽ yêu cầu “relabel” toàn bộ ổ cứng, rất mất thời gian. | (Không thể) |
Làm thế nào để thay đổi vĩnh viễn?
Bạn phải sửa file cấu hình /etc/selinux/config:
# Mở file bằng nano hoặc vi
nano /etc/selinux/config
Tìm dòng SELINUX=enforcing và sửa nó thành:
SELINUX=permissiveSELINUX=disabled
Cảnh báo cực kỳ quan trọng: Sau khi sửa file này, bạn bắt buộc phải reboot máy chủ để nó có hiệu lực. Đừng bao giờ chuyển từ Disabled về Enforcing ngay lập tức, bạn sẽ khóa chính mình khỏi máy chủ.
“Sống chung” với SELinux: Quy trình gỡ lỗi 3 bước (thay vì “tắt”)
Giờ chúng ta đến phần quan trọng nhất: làm thế nào để “sống chung” với nó.
Khi một dịch vụ bị lỗi, đừng vội chạy setenforce 0 rồi… bỏ đi. Lệnh đó chỉ nên là bước đầu tiên trong quy trình gỡ lỗi để xác nhận đây có phải lỗi do SELinux hay không.
Nếu bạn chạy setenforce 0 (chuyển sang Permissive) và dịch vụ chạy được, bạn đã 100% xác định thủ phạm.
Bây giờ, hãy setenforce 1 (trả về Enforcing) để dịch vụ… lỗi trở lại. Chúng ta sẽ đi sửa tận gốc vấn đề.
Mẹo chuyên nghiệp (Pro-Tip): Thay vì “setenforce 0”
Việc chạy
setenforce 0sẽ tắt SELinux cho toàn bộ hệ thống, khiến việc gỡ lỗi trở nên ồn ào.Thay vào đó, bạn có thể chỉ cần đặt miền (domain) của dịch vụ đang lỗi sang chế độ Permissive. Ví dụ, nếu Web Server (
httpd_t) bị lỗi, hãy chạy:# Cài công cụ semanage (nếu chưa có) sudo dnf install policycoreutils-python-utilsĐặt miền
httpd_tsang chế độ Permissivesudo semanage permissive -a httpd_tBằng cách này, chỉ Apache được phép vi phạm chính sách (nhưng vẫn ghi log), còn toàn bộ hệ thống vẫn được bảo vệ. Sau khi sửa lỗi xong, bạn có thể xóa quy tắc này bằng
semanage permissive -d httpd_t.
Bước 1: Đọc Log – Hỏi SELinux xem “Vấn đề là gì?”
Khi SELinux (ở chế độ Enforcing) chặn một thứ gì đó, nó luôn “la làng” trong file log. Việc của bạn là đọc nó.
Công cụ tốt nhất cho người mới: sealert. (Nếu chưa có, hãy cài dnf install setroubleshoot-server).
Nơi kiểm tra Log:
- Nếu dịch vụ
auditdđang chạy (mặc định), log nằm ở:/var/log/audit/audit.log - Nếu
auditdkhông chạy, log sẽ nằm ở:/var/log/messages
Chỉ cần chạy lệnh sau để nó quét file log và đưa ra gợi ý:
sealert -a /var/log/audit/audit.log
Kết quả sealert sẽ cực kỳ thân thiện. Nó sẽ cho bạn biết chính xác:
- Chuyện gì đã xảy ra: Ví dụ: “SELinux is preventing httpd (tiến trình web) from reading… (một file nào đó).”
- Tại sao nó bị chặn: Ví dụ: File đó có “context” (nhãn) là
default_t, trong khi tiến trìnhhttpd_tchỉ được phép đọc file có nhãnhttpd_sys_content_t. - Cách sửa (The Fix): Đây là phần “ăn tiền”. Nó sẽ gợi ý cho bạn một lệnh, ví dụ: “Nếu bạn tin tưởng điều này, hãy chạy
restorecon -v /path/to/file” hoặc “hãy chạysetsebool -P httpd_can_network_connect 1“.
Bạn gần như chỉ cần copy-paste lệnh nó gợi ý!
Bước 2: “Labels/Context” – Gán nhãn đúng (Lỗi phổ biến nhất)
Đây là 90% nguyên nhân gây lỗi SELinux.
- Vấn đề: Bạn tạo một thư mục web mới ở
/srv/my-web(thay vì/var/www/htmltruyền thống). SELinux không biết thư mục này, nên gán nhãn mặc định làdefault_t. Tiến trình web server (httpd_t) không được phép đọc nhãn này -> Báo lỗi 403 Forbidden. - Kiểm tra nhãn: Dùng lệnh
ls -Z# Nhãn chuẩn của web server ls -Zd /var/www/html # Output: system_u:object_r:httpd_sys_content_t:s0 /var/www/html # Nhãn sai của thư mục bạn mới tạo ls -Zd /srv/my-web # Output: system_u:object_r:default_t:s0 /srv/my-web - Cách sửa (ĐÚNG và VĨNH VIỄN): Chúng ta cần làm 2 việc: (1) Báo cho SELinux biết quy tắc mới, và (2) Áp dụng quy tắc đó.
# Cài đặt công cụ 'semanage' (nếu chưa có) # Gói này là 'policycoreutils-python-utils' (RHEL 8/9) # hoặc 'policycoreutils-python' (RHEL 7) sudo dnf install policycoreutils-python-utils # 1. Thêm quy tắc "vĩnh viễn" vào policy # "Bảo SELinux rằng /srv/my-web và MỌI THỨ bên trong nó (/.*)? là httpd_sys_content_t" sudo semanage fcontext -a -t httpd_sys_content_t "/srv/my-web(/.*)?" # 2. Áp dụng quy tắc vừa thêm # "Chạy và gán lại nhãn cho toàn bộ thư mục /srv/my-web" sudo restorecon -Rv /srv/my-webSau 2 lệnh này, Web server của bạn sẽ chạy được mà không cần
setenforce 0.
Bước 3: “Booleans” – Bật/Tắt các tính năng có sẵn
Đôi khi, file context đã đúng, nhưng hành động của dịch vụ lại bị cấm.
- Vấn đề: Mặc định, SELinux cấm tiến trình web (
httpd_t) kết nối ra mạng bên ngoài (để gọi API, kết nối DB) hoặc gửi email. Đây là một tính năng an ninh “đề phòng”. - Giải pháp: Dùng “Boolean” (công tắc Bật/Tắt) mà SELinux đã tạo sẵn.
- Cách sửa:
# Xem tất cả các công tắc liên quan đến httpd getsebool -a | grep httpd # Ví dụ: cho phép web server kết nối ra mạng (vào DB, API) # Cờ -P là để BẬT VĨNH VIỄN (rất quan trọng) sudo setsebool -P httpd_can_network_connect 1 # Ví dụ: cho phép web server gửi email sudo setsebool -P httpd_can_sendmail 1 # Ví dụ: cho phép web đọc file trong thư mục /home (ví dụ /home/user/public_html) sudo setsebool -P httpd_enable_homedirs 1
Ví dụ thực tế: Đổi cổng SSH (Kết nối từ bài “10 Lỗi SSH”)
Đây là ví dụ “kinh điển” mà chúng ta đã nhắc đến:
- Kịch bản: Bạn sửa file
/etc/ssh/sshd_config, đổi Port 22 thànhPort 2222. - Lỗi: Bạn
systemctl restart sshd, dịch vụ vẫn chạy, nhưng bạn không thể SSH vào cổng 2222 (báo “Connection Timed Out” hoặc “Connection Refused”). - Lý do: SELinux chỉ “biết” cổng 22 là cổng dành cho SSH (có nhãn
ssh_port_t). Nó chặn tiến trìnhsshd_t“chiếm” (bind) bất kỳ cổng nào khác. - Giải pháp (Cách của chuyên gia):
# 1. Cài công cụ (nếu chưa có) sudo dnf install policycoreutils-python-utils # 2. Kiểm tra các cổng SSH được phép (bạn sẽ chỉ thấy port 22) sudo semanage port -l | grep ssh # 3. "Báo" cho SELinux: cổng 2222 GIỜ LÀ CỔNG SSH HỢP LỆ sudo semanage port -a -t ssh_port_t -p tcp 2222 # 4. Khởi động lại sshd sudo systemctl restart sshdBây giờ bạn có thể SSH vào cổng 2222 một cách bình thường, trong khi SELinux vẫn ở chế độ
Enforcingvà bảo vệ bạn.
Bảng tra cứu (Cheat Sheet) các lệnh SELinux phổ biến
Để giúp bạn “sống chung” với SELinux dễ dàng hơn, đây là bảng tra cứu nhanh các lệnh quan trọng nhất. Hãy lưu (bookmark) lại phần này:
| Lệnh | Mục đích | Ví dụ thực tế |
getenforce |
Kiểm tra nhanh chế độ hiện tại (Enforcing/Permissive). | getenforce |
setenforce [0|1] |
Tạm thời đổi chế độ. 0 = Permissive, 1 = Enforcing. |
setenforce 0 |
sestatus |
Xem báo cáo trạng thái SELinux đầy đủ, chi tiết. | sestatus |
ls -Z |
(Quan trọng) Xem “Nhãn” (Context) của file/thư mục. | ls -Z /var/www/html |
ps axZ |
(Quan trọng) Xem “Nhãn” (Context) của tiến trình (process). | ps axZ | grep httpd |
sealert -a [log] |
(Hữu ích nhất) Phân tích log và đưa ra gợi ý sửa lỗi. | sealert -a /var/log/audit/audit.log |
restorecon -Rv |
Khôi phục context đúng (theo policy) cho file/thư mục. | restorecon -Rv /var/www/html |
semanage fcontext ... |
(Quan trọng) Thêm quy tắc context vĩnh viễn cho thư mục mới. | semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?" |
semanage port ... |
(Quan trọng) Thêm quy tắc cho phép một cổng (port) mới. | semanage port -a -t ssh_port_t -p tcp 2222 |
semanage permissive ... |
(Nâng cao) Đặt một miền (dịch vụ) cụ thể sang Permissive. | semanage permissive -a httpd_t |
getsebool -a |
Liệt kê tất cả các “Công tắc” (Boolean) Bật/Tắt. | getsebool -a | grep httpd |
setsebool -P ... |
Bật/Tắt vĩnh viễn một Boolean. (Cờ -P là bắt buộc). | setsebool -P httpd_can_network_connect 1 |
Câu hỏi thường gặp (FAQ) về SELinux
1. Tôi có nên tắt SELinux (setenforce 0) vĩnh viễn không?
Không. Bạn tuyệt đối không nên đặt SELINUX=disabled trong file config.
- Lệnh
setenforce 0(chuyển sang chế độ Permissive) là một công cụ gỡ lỗi tạm thời rất tốt. - Tuy nhiên, việc tắt vãng viễn (
disabled) sẽ khiến hệ thống ngừng gán nhãn (context) cho các file mới. Nếu sau này bạn muốn bật lại, bạn sẽ phải “relabel” (gán nhãn lại) toàn bộ ổ cứng, một quá trình rất mất thời gian và có thể làm hỏng hệ thống nếu không cẩn thận.
2. SELinux khác gì với Tường lửa (Firewalld/UFW)?
Đây là hai lớp bảo vệ hoàn toàn khác nhau. Bạn cần cả hai:
- Tường lửa (Firewalld/UFW): Giống như lính gác bên ngoài cổng thành. Nó kiểm soát lưu lượng mạng (ai được phép vào/ra, qua cổng (port) nào).
- SELinux: Giống như một anh bảo vệ bên trong thành. Nó kiểm soát hành vi của các tiến trình. Ngay cả khi hacker đã đi qua tường lửa, SELinux sẽ ngăn chặn hacker đó (ví dụ: tiến trình web
httpd_t) đọc các file nhạy cảm (như databasemysqld_db_t).
3. Tại sao tôi đã chạy setenforce 0 và nó hoạt động, nhưng khi reboot (khởi động lại) VPS thì lỗi lại quay trở lại?
Lệnh setenforce 0 chỉ thay đổi chế độ của SELinux tạm thời (cho phiên làm việc đó).
Khi bạn reboot, hệ thống sẽ đọc file cấu hình vĩnh viễn tại /etc/selinux/config, nơi vẫn đang đặt chế độ là enforcing. Đây là lý do tại sao bạn phải sửa lỗi tận gốc bằng các lệnh vĩnh viễn như semanage fcontext -a ..., semanage port -a ... hoặc setsebool -P ... như đã hướng dẫn trong bài.
4. Tôi có cần SELinux cho một website WordPress/PHP đơn giản không?
Có, rất cần. Đây là một ví dụ hoàn hảo. Nếu hacker tấn công qua một lỗ hổng trong plugin WordPress, chúng sẽ chiếm quyền của tiến trình web server (httpd_t).
- Không có SELinux: Hacker có thể dùng quyền
httpd_tđể đọc/etc/passwd, quét các cổng nội bộ, hoặc cố gắng truy cập file database. - Có SELinux: SELinux “nhốt” tiến trình
httpd_tlại. Nó sẽ bị chặn ngay lập tức khi cố gắng đọc bất cứ thứ gì không có nhãnhttpd_sys_content_t(nhãn của file web). Cuộc tấn công bị ngăn chặn tại chỗ.
Kết luận
SELinux không phải là một “thủ phạm giấu mặt” được tạo ra để gây khó khăn cho bạn. Nó là một lớp bảo vệ an ninh cấp độ quân sự, được thiết kế để hạn chế tối đa thiệt hại ngay cả khi hacker đã xâm nhập vào một dịch vụ trên máy chủ của bạn (như Web Server).
Việc chạy lệnh setenforce 0 và bỏ đi giống như thấy trộm vào nhà và… tự bịt mắt mình lại.
Hy vọng qua bài viết này, bạn đã hiểu SELinux là gì và có một quy trình gỡ lỗi rõ ràng:
- Dùng
setenforce 0(hoặcsemanage permissive) để xác nhận lỗi. - Bật
setenforce 1trở lại (hoặc gỡ bỏ permissive domain). - Dùng
sealertđể đọc log và tìm gợi ý. - Nếu là lỗi “Nhãn”, dùng
semanage fcontextvàrestorecon(cho thư mục) hoặcsemanage port(cho cổng). - Nếu là lỗi “Hành vi”, dùng
setseboolđể bật công tắc (Boolean) cho phép.
Chỉ với 3 kỹ thuật này (Context, Port, Boolean), bạn có thể giải quyết 99% các vấn đề “khó đỡ” do SELinux gây ra và giữ cho máy chủ của mình an toàn tuyệt đối.
Bạn đã từng gặp lỗi “khó đỡ” nào với SELinux? Bạn đã giải quyết nó bằng cách “tắt” hay “sống chung”? Hãy chia sẻ kinh nghiệm hoặc câu hỏi của bạn ở phần bình luận bên dưới nhé!




