Hướng dẫn

Cấu hình ufw trên Linux: firewall cho máy chủ và kiến thức nền về nftables

Cập nhật: · Skillaria.Top

Cấu hình ufw gồm ba bước: đặt chính sách mặc định (sudo ufw default deny incoming và allow outgoing), cho phép SSH và các cổng cần thiết (sudo ufw allow 22/tcp, sudo ufw allow 443/tcp), rồi bật firewall bằng sudo ufw enable. Kiểm tra quy tắc bằng sudo ufw status numbered; bên dưới, ufw điều khiển netfilter thông qua iptables hoặc nftables.

Firewall trên Linux quyết định gói tin mạng nào được phép vào máy chủ và gói nào bị loại bỏ. Chính nhân Linux thực hiện việc lọc thông qua netfilter, còn người quản trị điều khiển nó bằng các công cụ như iptables và nftables ở mức thấp, hoặc ufw (Uncomplicated Firewall) ở mức đơn giản hơn. Với phần lớn máy chủ Ubuntu và Debian, cấu hình ufw mất khoảng năm phút: chặn mọi kết nối vào, mở SSH và các cổng dịch vụ, rồi bật lên. Dưới đây là quy trình từng bước, các lỗi thường gặp và phần nftables tối thiểu để hiểu chuyện gì đang xảy ra bên dưới.

Firewall trên Linux hoạt động như thế nào

Việc lọc gói tin nằm trong nhân — đó là netfilter. Nó cung cấp các điểm chặn (hook): lưu lượng vào máy, lưu lượng đi ra và lưu lượng chuyển tiếp (forward). Các công cụ người dùng chỉ ghi quy tắc vào nhân cho những điểm này.

Công cụMứcKhi nào dùng
ufwlớp bao ngoài, cú pháp đơn giảnmáy chủ đơn lẻ trên Ubuntu/Debian, quy tắc thông thường
firewalldlớp bao ngoài có vùng (zone)RHEL, Rocky, Fedora
nftables (nft)mức thấp, hiện đạiquy tắc phức tạp, NAT, tập hợp địa chỉ
iptablesmức thấp, đang lỗi thờihệ thống và script cũ

Quan trọng: chỉ dùng một công cụ quản lý. Nếu vừa sửa quy tắc bằng ufw vừa sửa bằng iptables thủ công, hai bên sẽ ghi đè lẫn nhau và kết quả trở nên khó đoán.

Cài đặt và kiểm tra ufw

Trên Ubuntu, ufw thường đã được cài sẵn nhưng đang tắt. Trên Debian cần cài riêng:

$ sudo apt update
$ sudo apt install ufw
$ sudo ufw status
Status: inactive

Trạng thái inactive nghĩa là các quy tắc ufw chưa được áp dụng. Chưa nên bật firewall ngay: hãy cho phép SSH trước, nếu không trên máy chủ từ xa bạn sẽ tự cắt quyền truy cập của chính mình.

Cấu hình ufw từng bước trên máy chủ

Bước 1. Chính sách mặc định

Chính sách mặc định là hành động áp dụng khi không có quy tắc nào khớp với gói tin. Cách an toàn cho máy chủ: chặn lưu lượng vào, cho phép lưu lượng ra.

$ sudo ufw default deny incoming
Default incoming policy changed to 'deny'
$ sudo ufw default allow outgoing
Default outgoing policy changed to 'allow'

Phản hồi cho các kết nối đi ra do chính bạn khởi tạo được cho qua tự động: ufw theo dõi trạng thái kết nối (connection tracking), nên không cần mở cổng cho các gói phản hồi.

Bước 2. Cho phép SSH

$ sudo ufw allow OpenSSH
Rules updated
Rules updated (v6)

OpenSSH là một profile ứng dụng. Nếu SSH lắng nghe trên cổng khác, hãy cho phép rõ ràng: sudo ufw allow 2222/tcp. Để biết sshd thực sự đang nghe cổng nào, chạy sudo ss -tlnp | grep sshd.

Bước 3. Mở cổng cho các dịch vụ

$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp

Hãy chỉ rõ giao thức: nếu không ghi /tcp, ufw sẽ mở cổng cho cả TCP lẫn UDP, và một cổng mở thừa không cần thiết.

Bước 4. Bật firewall

$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

ufw khởi chạy ngay và sẽ tự bật khi máy khởi động. Đừng đóng phiên SSH hiện tại: hãy mở thêm một phiên thứ hai và kiểm tra rằng kết nối vẫn hoạt động.

Bước 5. Kiểm tra quy tắc

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

Quy tắc cho IPv6 do ufw tự tạo, nếu trong /etc/default/ufw có IPV6=yes (giá trị mặc định).

Cách mở cổng trong ufw: mọi cú pháp

Lệnh ufw allow hiểu cả dạng ngắn lẫn dạng đầy đủ. Dạng ngắn tiện cho trường hợp thông thường, còn dạng đầy đủ dùng khi cần chỉ định nguồn, giao diện hoặc địa chỉ đích.

Việc cần làmLệnh
Cổng TCPsudo ufw allow 443/tcp
Cổng UDPsudo ufw allow 51820/udp
Dải cổngsudo ufw allow 6000:6007/tcp
Theo tên dịch vụsudo ufw allow https
Từ một IPsudo ufw allow from 203.0.113.10
Từ một mạng con tới một cổngsudo ufw allow from 10.0.0.0/24 to any port 5432 proto tcp
Trên một giao diệnsudo ufw allow in on eth1 to any port 3306 proto tcp
Chặnsudo ufw deny 23/tcp
Từ chối kèm phản hồisudo ufw reject 25/tcp

Khác biệt giữa deny và reject: deny lặng lẽ loại bỏ gói tin, nên client phải chờ đến khi hết thời gian; reject gửi phản hồi rằng cổng đã đóng. Với thế giới bên ngoài thường chọn deny, còn với mạng nội bộ reject tiện hơn vì client thấy lỗi ngay.

Cơ sở dữ liệu chỉ cho phép một máy chủ truy cập

Tình huống hay gặp: PostgreSQL hoặc MySQL không được lộ ra Internet, nhưng ứng dụng trên máy chủ bên cạnh vẫn phải kết nối được.

$ sudo ufw allow from 10.0.0.5 to any port 5432 proto tcp
Rule added

Cổng 5432 vẫn đóng với mọi máy khác nhờ chính sách deny incoming. Ngoài ra nên cấu hình chính CSDL chỉ lắng nghe trên địa chỉ nội bộ — firewall và cấu hình dịch vụ bảo vệ lẫn nhau.

Profile ứng dụng

Các gói phần mềm có thể đặt mô tả cổng của chúng trong /etc/ufw/applications.d/. Xem danh sách và nội dung profile:

$ sudo ufw app list
Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH
$ sudo ufw app info "Nginx Full"
Profile: Nginx Full
Title: Web Server (Nginx, HTTP + HTTPS)
Description: Small, but very powerful and efficient web server

Ports:
  80,443/tcp

Cho phép một profile: sudo ufw allow "Nginx Full". Tên có khoảng trắng cần đặt trong dấu nháy. Có thể tự viết profile theo định dạng INI trong cùng thư mục rồi áp dụng bằng sudo ufw app update tên.

Cách xóa quy tắc ufw

Cách chắc chắn nhất là xóa theo số thứ tự:

$ sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] OpenSSH                    ALLOW IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere
[ 4] OpenSSH (v6)               ALLOW IN    Anywhere (v6)
[ 5] 80/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 6] 443/tcp (v6)               ALLOW IN    Anywhere (v6)

$ sudo ufw delete 2
Deleting:
 allow 80/tcp
Proceed with operation (y|n)? y
Rule deleted

Sau khi xóa, các số thứ tự bị dịch chuyển, nên trước lần xóa tiếp theo hãy chạy lại status numbered. Cách khác là lặp lại quy tắc kèm chữ delete: sudo ufw delete allow 80/tcp; lệnh này xóa cả biến thể IPv4 lẫn IPv6 cùng lúc.

Thứ tự quy tắc và chèn lên đầu

ufw kiểm tra quy tắc từ trên xuống, và quy tắc khớp đầu tiên được áp dụng. Vì vậy chặn một địa chỉ cụ thể phải nằm phía trên quy tắc cho phép chung:

$ sudo ufw insert 1 deny from 198.51.100.23
Rule inserted

Nếu thêm deny bằng lệnh thông thường, nó sẽ nằm cuối danh sách, sau allow 443/tcp, và sẽ không có tác dụng với cổng đó.

Bảo vệ SSH khỏi dò mật khẩu: ufw limit

Quy tắc limit cho phép kết nối nhưng chặn địa chỉ đã mở từ 6 kết nối trở lên trong 30 giây:

$ sudo ufw limit OpenSSH
Rule updated

Đây là cách bảo vệ đơn giản chống dò mật khẩu hàng loạt. Để bảo vệ nghiêm túc hơn, chỉ cho đăng nhập bằng khóa và, nếu muốn, dùng thêm fail2ban — công cụ này có thể chặn địa chỉ thông qua ufw.

Nhật ký ufw

Bật ghi nhật ký bằng sudo ufw logging on; các mức là low, medium, high, full. Bản ghi được lưu vào /var/log/ufw.log (qua rsyslog) và vào nhật ký của nhân:

$ sudo journalctl -k | grep 'UFW BLOCK' | tail -2
Oct 14 10:12:03 web kernel: [UFW BLOCK] IN=eth0 OUT= SRC=45.155.205.1 DST=192.0.2.10 PROTO=TCP SPT=51544 DPT=3389
Oct 14 10:12:09 web kernel: [UFW BLOCK] IN=eth0 OUT= SRC=89.248.165.7 DST=192.0.2.10 PROTO=TCP SPT=40312 DPT=23

Các trường SRC và DPT cho biết ai đã gõ cửa và vào cổng nào. Nếu một dịch vụ không phản hồi và trong nhật ký có UFW BLOCK cho cổng của nó, nghĩa là chưa có quy tắc cho phép.

ufw và Docker: vì sao cổng vẫn mở bất chấp quy tắc

Đây là cái bẫy nổi tiếng nhất. Khi công bố cổng (-p 8080:80), Docker tự thêm quy tắc NAT và chuỗi DOCKER, và lưu lượng tới container đi qua forward, bỏ qua các quy tắc vào của ufw. Kết quả là ufw status không hiển thị cổng 8080, nhưng từ bên ngoài vẫn truy cập được.

Các cách xử lý:

  • Chỉ công bố cổng trên localhost: -p 127.0.0.1:8080:80, còn ra ngoài thì qua reverse proxy (nginx).
  • Thêm quy tắc riêng vào chuỗi DOCKER-USER — Docker không ghi đè chuỗi này.
  • Không công bố cổng của các container nội bộ, mà kết nối chúng qua mạng Docker.

Đặt lại và tắt

$ sudo ufw disable     # tắt, quy tắc vẫn được giữ lại
$ sudo ufw reset       # xóa mọi quy tắc và tắt
$ sudo ufw reload      # đọc lại cấu hình

Trước khi reset, ufw lưu bản sao các file quy tắc vào /etc/ufw/ với hậu tố ngày tháng. Bản thân quy tắc nằm trong /etc/ufw/user.rules và user6.rules — không sửa tay các file này, chỉ dùng lệnh.

Kiến thức nền về nftables

nftables là sự thay thế hiện đại cho iptables trong nhân Linux. Trên Debian 10+ và Ubuntu 20.10+, lệnh iptables mặc định chạy qua lớp tương thích iptables-nft, nên các quy tắc của ufw cũng nằm trong nftables. Xem mọi thứ đã nạp vào nhân:

$ sudo nft list ruleset

Cấu trúc nftables: một bảng (họ ip, ip6 hoặc inet cho cả hai) chứa các chuỗi gắn với các điểm netfilter, còn chuỗi chứa các quy tắc. Firewall tối thiểu cho máy chủ trong file /etc/nftables.conf:

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        ct state established,related accept
        ct state invalid drop
        iif "lo" accept
        ip protocol icmp accept
        meta l4proto ipv6-icmp accept
        tcp dport { 22, 80, 443 } accept
    }
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Áp dụng và bật khi khởi động:

$ sudo nft -c -f /etc/nftables.conf   # chỉ kiểm tra cú pháp
$ sudo systemctl enable --now nftables

Có thể thêm quy tắc ngay trong lúc chạy, nhưng chúng sẽ mất sau khi khởi động lại nếu không ghi vào file:

$ sudo nft add rule inet filter input tcp dport 5432 ip saddr 10.0.0.5 accept
$ sudo nft -a list chain inet filter input   # -a hiển thị handle của quy tắc
$ sudo nft delete rule inet filter input handle 9

Ưu điểm chính của nftables là các tập hợp ({ 22, 80, 443 }) và một bảng inet duy nhất cho cả IPv4 lẫn IPv6. Không chạy đồng thời dịch vụ nftables.service của riêng bạn với ufw: flush ruleset sẽ xóa sạch quy tắc của ufw.

Lỗi thường gặp

  • Bật ufw mà chưa có quy tắc cho SSH — mất quyền truy cập. Cứu nguy bằng console của nhà cung cấp (VNC/serial): sudo ufw allow OpenSSH hoặc sudo ufw disable.
  • Đã mở cổng nhưng dịch vụ vẫn không truy cập được — dịch vụ đang lắng nghe trên 127.0.0.1, không phải địa chỉ bên ngoài. Kiểm tra bằng ss -tlnp.
  • Còn một firewall đám mây — nhiều nhà cung cấp có nhóm bảo mật; cổng cũng phải mở ở đó.
  • deny không có tác dụng — quy tắc nằm dưới quy tắc cho phép; dùng insert 1.

Tóm lại

Cấu hình ufw cơ bản gồm default deny incoming, cho phép SSH và các cổng dịch vụ, ufw enable và kiểm tra bằng status numbered. Để truy cập có chọn lọc, dùng quy tắc với from và port; để bảo vệ SSH, dùng limit; và khi làm việc với Docker, nhớ rằng nó bỏ qua ufw. Khi cần NAT hay các tập quy tắc phức tạp, chuyển sang nftables. Bảo vệ máy chủ bằng firewall được thực hành cụ thể trong khóa học Linux.

Câu hỏi thường gặp

ufw khác iptables ở điểm nào?

ufw là lớp bao ngoài với cú pháp đơn giản, tự sinh quy tắc iptables hoặc nftables. iptables và nftables là công cụ mức thấp, cho quyền kiểm soát đầy đủ nhưng đòi hỏi nhiều kiến thức hơn.

Quy tắc ufw có còn sau khi khởi động lại không?

Có. Sau sudo ufw enable, firewall tự chạy khi máy khởi động, còn quy tắc được lưu trong /etc/ufw/user.rules và user6.rules.

Có cần mở cổng cho kết nối đi ra không?

Với chính sách allow outgoing thì không. ufw tự cho qua các gói phản hồi của kết nối đi ra nhờ theo dõi trạng thái.

Làm sao cho phép ping khi ufw đang bật?

Mặc định ufw đã cho phép các gói ICMP echo-request vào, quy tắc này nằm trong /etc/ufw/before.rules. Để chặn ping, đổi ACCEPT thành DROP trong file đó rồi chạy sudo ufw reload.

CentOS và Rocky Linux có ufw không?

Công cụ chuẩn ở đó là firewalld với lệnh firewall-cmd. Có thể cài ufw từ EPEL, nhưng không nên dùng chung với firewalld.

Học chủ đề này qua video

Chủ đề này được giảng chi tiết kèm thực hành trong khóa học “Linux: с нуля до уверенного администрирования”.

Đến khóa học