Cách cấu hình nftables trên Linux: firewall thực chiến từ cơ bản đến production

nftables là gì? Tại sao thay thế iptables?

Nếu bạn đã quen với iptables trong nhiều năm quản trị Linux, đây là lúc cần làm quen với người kế nhiệm: nftables. Từ kernel Linux 3.13 (2014) và chính thức thay thế iptables mặc định trên Debian 10, RHEL 8, Ubuntu 20.04 trở đi, nftables mang lại kiến trúc firewall gọn, nhất quán và hiệu năng cao hơn hẳn.

Bài viết này hướng dẫn bạn hiểu rõ cách cấu hình nftables trên Linux từ nền tảng đến production: cú pháp ruleset, quản lý tables/chains/rules, stateful firewall, NAT, rate limiting, và troubleshooting thực tế.

Vì sao iptables “hết thời”?

iptables không thực sự biến mất — nó vẫn chạy thông qua lớp compatibility iptables-nft trên nhiều distro hiện đại. Tuy nhiên, kiến trúc gốc của nó có nhiều hạn chế:

  • Nhiều công cụ rời rạc: iptables (IPv4), ip6tables (IPv6), arptables (ARP), ebtables (bridge) — mỗi loại một công cụ riêng, không nhất quán.
  • Không có atomic rule update: Khi thay đổi ruleset lớn, có khoảng thời gian ngắn ruleset không đồng nhất.
  • Hiệu năng kém với ruleset lớn: Linear scan qua từng rule — 10.000 rule đồng nghĩa 10.000 phép so sánh.
  • Cú pháp phức tạp, khó đọc: Nhiều flag viết tắt, dễ nhầm lẫn.

nftables giải quyết tất cả vấn đề trên: một công cụ duy nhất xử lý IPv4/IPv6/ARP/bridge, atomic ruleset loading, cú pháp nhất quán và dễ đọc, hỗ trợ set/map cho tra cứu O(1) thay vì O(n).

📖 Tài liệu chính thống: wiki.nftables.orgnetfilter.org/projects/nftables.

Cài đặt nftables

Kiểm tra trạng thái hiện tại

Trước khi cài, kiểm tra xem distro của bạn đã có nftables chưa:

# Kiểm tra nft version
nft --version
# Output mẫu:
# nftables v1.0.6 (Lester Gooch #6)

# Kiểm tra service
systemctl status nftables

# Xem ruleset đang chạy
nft list ruleset

Cài trên các distro phổ biến

# Debian/Ubuntu
sudo apt update && sudo apt install nftables -y
sudo systemctl enable --now nftables

# RHEL/CentOS/AlmaLinux/Rocky Linux 8+
sudo dnf install nftables -y
sudo systemctl enable --now nftables

# Arch Linux
sudo pacman -S nftables
sudo systemctl enable --now nftables

Tắt iptables để tránh xung đột (nếu cần)

# Kiểm tra iptables legacy vs nft backend
iptables --version
# Output mẫu: iptables v1.8.7 (nf_tables)  ← đây là nft backend, không cần lo
# Hoặc: iptables v1.8.7 (legacy)            ← cần chuyển sang nft

# Trên Debian/Ubuntu, chuyển backend:
sudo update-alternatives --set iptables /usr/sbin/iptables-nft
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-nft

Kiến trúc nftables: Tables, Chains, Rules

Hiểu đúng kiến trúc là nền tảng để cấu hình đúng. nftables tổ chức theo 3 tầng:

Table (bảng)

Table là container chứa chains. Mỗi table thuộc một address family:

  • ip — chỉ IPv4
  • ip6 — chỉ IPv6
  • inet — cả IPv4 lẫn IPv6 (khuyến nghị dùng)
  • arp, bridge, netdev — các use case đặc biệt
# Tạo table
nft add table inet my_firewall

# Xem tất cả tables
nft list tables

# Xóa table (và toàn bộ chains/rules bên trong)
nft delete table inet my_firewall

Chain (chuỗi)

Chain chứa các rules. Có 2 loại chain:

  • Base chain: Hook vào netfilter hooks (input, forward, output, prerouting, postrouting). Đây là entry point của traffic.
  • Regular chain: Chain thông thường, chỉ được gọi khi base chain jump/goto tới.
# Tạo base chain cho traffic vào
nft add chain inet my_firewall input { type filter hook input priority 0 \; policy drop \; }

# Tạo base chain cho traffic ra
nft add chain inet my_firewall output { type filter hook output priority 0 \; policy accept \; }

# Tạo base chain forward
nft add chain inet my_firewall forward { type filter hook forward priority 0 \; policy drop \; }

Priority xác định thứ tự xử lý khi nhiều chains cùng hook: số nhỏ hơn = ưu tiên cao hơn. Giá trị thường dùng: 0 (filter), 100 (mangle), -100 (raw).

Rule (quy tắc)

Rule là đơn vị nhỏ nhất — một điều kiện match + một action (accept, drop, reject, log, jump, etc.).

# Cho phép loopback
nft add rule inet my_firewall input iifname "lo" accept

# Cho phép established/related connections
nft add rule inet my_firewall input ct state established,related accept

# Cho phép SSH
nft add rule inet my_firewall input tcp dport 22 accept

# Drop invalid packets
nft add rule inet my_firewall input ct state invalid drop

Cấu hình Stateful Firewall thực tế

Dưới đây là ruleset hoàn chỉnh cho một server Linux production — web server đơn giản với SSH, HTTP, HTTPS:

Tạo file cấu hình /etc/nftables.conf

#!/usr/sbin/nft -f

# Xóa toàn bộ ruleset hiện tại (atomic flush + load)
flush ruleset

table inet firewall {

    # --- Sets cho whitelist/blacklist ---
    set blocked_ips {
        type ipv4_addr
        flags dynamic, timeout
        timeout 1h
    }

    set admin_ips {
        type ipv4_addr
        elements = { 192.168.1.0/24, 10.0.0.1 }
    }

    # --- Chain: kiểm tra rate limit SSH ---
    chain ssh_ratelimit {
        # Giới hạn 5 kết nối SSH mới mỗi phút từ 1 IP
        ct state new tcp dport 22 limit rate over 5/minute \
            add @blocked_ips { ip saddr timeout 10m } drop
        ct state new tcp dport 22 accept
    }

    # --- Chain chính: INPUT ---
    chain input {
        type filter hook input priority filter
        policy drop

        # Cho phép loopback
        iifname "lo" accept

        # Drop invalid
        ct state invalid drop

        # Cho phép established/related
        ct state { established, related } accept

        # Drop traffic từ blocked_ips
        ip saddr @blocked_ips drop

        # ICMP (ping): giới hạn rate để chống flood
        ip protocol icmp icmp type { echo-request } limit rate 10/second accept
        ip6 nexthdr icmpv6 icmpv6 type { echo-request } limit rate 10/second accept

        # SSH: dùng chain riêng với rate limit
        tcp dport 22 jump ssh_ratelimit

        # Web
        tcp dport { 80, 443 } accept

        # Log và drop tất cả còn lại
        log prefix "[nft-drop] " flags all limit rate 5/second
        drop
    }

    # --- Chain: OUTPUT ---
    chain output {
        type filter hook output priority filter
        policy accept
        # Output mặc định accept — có thể restrict thêm nếu cần
    }

    # --- Chain: FORWARD ---
    chain forward {
        type filter hook forward priority filter
        policy drop
        # Server không làm router → drop hết forward
        ct state { established, related } accept
    }
}

Áp dụng và kiểm tra

# Kiểm tra cú pháp trước khi áp dụng
nft -c -f /etc/nftables.conf
# Nếu không có output → syntax OK

# Áp dụng ruleset
sudo nft -f /etc/nftables.conf

# Xem ruleset đang chạy
nft list ruleset

# Xem chain cụ thể
nft list chain inet firewall input

# Xem set blocked_ips
nft list set inet firewall blocked_ips

Output mẫu sau khi áp dụng:

table inet firewall {
    set blocked_ips {
        type ipv4_addr
        size 65535
        flags dynamic,timeout
        timeout 1h
    }
    set admin_ips {
        type ipv4_addr
        elements = { 10.0.0.1, 192.168.1.0/24 }
    }
    chain ssh_ratelimit {
        ...
    }
    chain input {
        type filter hook input priority filter; policy drop;
        iifname "lo" accept
        ct state invalid drop
        ...
    }
    ...
}

Cấu hình NAT với nftables

nftables xử lý NAT rất gọn — không cần bật iptables masquerade riêng:

Masquerade (SNAT động) cho router/gateway

table inet nat {
    chain prerouting {
        type nat hook prerouting priority dstnat
        policy accept
    }

    chain postrouting {
        type nat hook postrouting priority srcnat
        policy accept

        # Masquerade tất cả traffic ra interface WAN
        oifname "eth0" masquerade
    }
}
# Bật IP forwarding
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

DNAT — Port forwarding

table inet nat {
    chain prerouting {
        type nat hook prerouting priority dstnat
        policy accept

        # Forward port 8080 ngoài vào port 80 server nội bộ
        tcp dport 8080 dnat to 192.168.1.100:80

        # Forward toàn bộ traffic tới 203.0.113.1 vào server nội bộ
        ip daddr 203.0.113.1 dnat to 192.168.1.50
    }
    ...
}

Sets và Maps: sức mạnh của nftables

Đây là điểm khác biệt lớn nhất so với iptables: setsmaps cho phép tra cứu O(1) thay vì linear scan.

Named sets (tĩnh)

table inet firewall {
    set trusted_networks {
        type ipv4_addr
        flags interval            # cho phép CIDR range
        elements = {
            10.0.0.0/8,
            172.16.0.0/12,
            192.168.0.0/16
        }
    }

    chain input {
        type filter hook input priority filter
        policy drop

        # Cho phép traffic từ trusted networks
        ip saddr @trusted_networks accept
    }
}

Dynamic sets với timeout (rate limiting / auto-blacklist)

table inet firewall {
    # Dynamic set: tự động xóa sau timeout
    set port_scanners {
        type ipv4_addr
        flags dynamic, timeout
        timeout 30m
        gc-interval 5m      # garbage collection mỗi 5 phút
    }

    chain input {
        type filter hook input priority filter
        policy drop

        # Detect port scan: >20 new connections/minute → blacklist 30 phút
        ct state new limit rate over 20/minute \
            add @port_scanners { ip saddr } \
            log prefix "[port-scan] " drop

        ip saddr @port_scanners drop
        ...
    }
}

Maps: routing theo giá trị

table inet firewall {
    # Map: port → server nội bộ
    map port_to_server {
        type inet_service : ipv4_addr
        elements = {
            80  : 192.168.1.10,
            443 : 192.168.1.10,
            8080 : 192.168.1.20,
            3306 : 192.168.1.30
        }
    }

    chain prerouting {
        type nat hook prerouting priority dstnat
        # DNAT theo map
        dnat to tcp dport map @port_to_server
    }
}

Quản lý rules runtime (không cần reload)

Một điểm mạnh của nftables là có thể thêm/xóa/sửa rule live mà không ảnh hưởng ruleset đang chạy:

# Thêm IP vào blacklist tức thì (không cần reload config)
nft add element inet firewall blocked_ips { 1.2.3.4 }

# Thêm với timeout cụ thể
nft add element inet firewall blocked_ips { 1.2.3.4 timeout 2h }

# Xóa IP khỏi blacklist
nft delete element inet firewall blocked_ips { 1.2.3.4 }

# Thêm rule vào chain (append)
nft add rule inet firewall input tcp dport 8443 accept

# Thêm rule vào đầu chain (insert)
nft insert rule inet firewall input tcp dport 8443 accept

# Xem handle của rules để xóa chính xác
nft -a list chain inet firewall input
# Output:
# chain input {
#   ...
#   tcp dport 22 accept # handle 7
#   tcp dport { 80, 443 } accept # handle 8

# Xóa rule theo handle
nft delete rule inet firewall input handle 7

Logging và Monitoring

Cấu hình log với nftables

# Log tất cả traffic bị drop (với giới hạn rate để tránh flood log)
nft add rule inet firewall input \
    log prefix "[DROPPED] " flags all limit rate 10/minute drop

# Log với group (dùng ulogd2)
nft add rule inet firewall input \
    log group 0 prefix "[DROPPED] " drop

Xem log realtime

# Xem kernel log
journalctl -k -f | grep -E "\[nft|DROPPED|port-scan"

# Hoặc dmesg
dmesg -T -w | grep "\[DROPPED\]"

# Mẫu output:
# May 23 19:00:01 server kernel: [DROPPED] IN=eth0 OUT= MAC=... SRC=203.0.113.5 DST=10.0.0.1 PROTO=TCP SPT=55234 DPT=3389

Thống kê counter theo rule

# Thêm counter vào rule
nft add rule inet firewall input \
    tcp dport 443 counter accept

# Xem counter
nft list ruleset | grep -A1 "counter"
# Output:
# tcp dport 443 counter packets 15234 bytes 8234560 accept

Lưu và khôi phục ruleset

# Lưu ruleset hiện tại ra file
nft list ruleset > /etc/nftables.conf

# Load lại từ file
nft -f /etc/nftables.conf

# Đảm bảo nftables load khi boot
sudo systemctl enable nftables

# Lưu ruleset vào file mặc định của distro
# Debian/Ubuntu:
nft list ruleset | sudo tee /etc/nftables.conf

# RHEL/AlmaLinux:
sudo nft list ruleset > /etc/sysconfig/nftables.conf

Lỗi thường gặp và cách xử lý

1. “Operation not permitted” khi chạy nft

# Lỗi:
Error: Operation not permitted

# Giải thích: cần quyền root hoặc CAP_NET_ADMIN
# Xử lý:
sudo nft list ruleset

# Hoặc nếu cần chạy không phải root:
sudo setcap cap_net_admin+ep /usr/sbin/nft

2. “Could not process rule: No such file or directory” (module kernel)

# Lỗi:
Error: Could not process rule: No such file or directory

# Kiểm tra modules kernel
lsmod | grep nf_tables
modprobe nf_tables
modprobe nft_ct nft_limit nft_log nft_nat nft_masq

# Thêm vào /etc/modules để load khi boot
echo "nf_tables" | sudo tee -a /etc/modules

3. SSH bị lock out sau khi thay đổi firewall

# Phòng ngừa: LUÔN test với at/timeout trước
# Cách 1: dùng 'at' schedule flush
echo "nft flush ruleset" | at now + 5 minutes
# Áp dụng ruleset mới → nếu bị lock, sau 5 phút firewall tự flush

# Cách 2: dùng timeout trong shell
(sleep 300 && nft flush ruleset) &
nft -f /etc/nftables.conf
# Nếu bị lock → sau 5 phút firewall flush, SSH vào được

4. Rules không match — debug với trace

# Bật trace để xem packet đi qua rules nào
nft add rule inet firewall input \
    ip saddr 1.2.3.4 meta nftrace set 1

# Theo dõi trace realtime
nft monitor trace

# Output mẫu:
# trace id 12345678 inet firewall input packet: iifname "eth0" ip saddr 1.2.3.4 ...
# trace id 12345678 inet firewall input rule tcp dport 22 accept (handle 5)
# trace id 12345678 inet firewall input verdict accept

5. Xung đột với firewalld (RHEL/AlmaLinux)

# Nếu dùng firewalld, không nên dùng nft trực tiếp song song
# Kiểm tra:
systemctl is-active firewalld

# Nếu muốn dùng nft thuần, tắt firewalld:
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo systemctl mask firewalld
sudo systemctl enable --now nftables

nftables vs iptables: Bảng so sánh

Tiêu chí iptables nftables
Hỗ trợ IPv4/IPv6 Hai công cụ riêng (iptables/ip6tables) Một công cụ (inet family)
Cú pháp Nhiều flag viết tắt, khó nhớ Nhất quán, dễ đọc
Hiệu năng ruleset lớn O(n) linear scan O(1) với sets/maps
Atomic update Không (có khoảng trống) Có (flush ruleset + load)
Dynamic sets Cần ipset riêng Built-in
NAT iptables + ip6tables riêng Một bảng, hỗ trợ cả IPv4/IPv6
Hỗ trợ distro hiện đại Legacy (còn compatibility layer) Mặc định từ Debian 10, RHEL 8, Ubuntu 20.04
Học mới Nhiều tài liệu cũ Tài liệu đang tăng nhanh

Checklist nghiệm thu cấu hình nftables production

Trước khi đưa vào production, kiểm tra đủ các mục sau:

  • nft -c -f /etc/nftables.conf không báo lỗi syntax
  • ✅ SSH vẫn hoạt động sau khi load ruleset
  • ✅ Các cổng cần thiết (80, 443, app port) đã được allow
  • ✅ Loopback (lo) đã được accept
  • ✅ ct state established,related đã được accept (stateful)
  • ✅ ICMP/ICMPv6 cần thiết đã được allow (không quá rộng)
  • ✅ Logging đã bật cho traffic bị drop (để troubleshoot sau này)
  • ✅ Rate limiting SSH chống brute-force
  • systemctl enable nftables đã chạy
  • ✅ Backup ruleset cũ trước khi thay đổi: nft list ruleset > /etc/nftables.conf.bak.$(date +%Y%m%d)
  • ✅ Test từ IP ngoài (không chỉ từ localhost)
  • ✅ Kiểm tra IPv6 riêng nếu server có IPv6 public

Bài tập lab

Sau khi đọc bài, hãy thực hành trên máy ảo (VM hoặc container) để đảm bảo không ảnh hưởng production:

Lab 1: Firewall cơ bản

  1. Cài nftables trên VM Ubuntu/AlmaLinux.
  2. Tạo ruleset: drop input mặc định, cho phép SSH/HTTP/HTTPS và loopback.
  3. Xác minh: thử kết nối SSH và curl từ máy khác.
  4. Thêm rate limit SSH: chặn IP sau 5 lần thất bại/phút.

Lab 2: Dynamic blacklist

  1. Tạo dynamic set blacklist với timeout 10 phút.
  2. Viết rule: nếu 1 IP tạo >10 kết nối mới/phút → add vào blacklist.
  3. Dùng nft monitorjournalctl -k xem log realtime.
  4. Test bằng hping3 hoặc vòng lặp curl nhanh.

Lab 3: NAT gateway

  1. Setup VM 2 card mạng (WAN + LAN).
  2. Cấu hình masquerade cho LAN clients ra internet.
  3. Thêm DNAT: port 8080 ngoài → port 80 máy trong LAN.
  4. Xác minh từ máy LAN curl thông internet, và từ ngoài curl port 8080.

Kết luận

nftables không chỉ là “iptables mới” — đây là kiến trúc firewall hiện đại hơn hẳn với sets/maps hiệu năng cao, atomic ruleset update, cú pháp nhất quán và hỗ trợ native cả IPv4/IPv6. Nếu bạn đang quản trị server Linux từ Debian 10, RHEL 8, Ubuntu 20.04 trở lên, đây là lúc làm chủ nftables thay vì chỉ dùng compatibility layer của iptables.

Bắt đầu ngay trên lab VM — từ ruleset đơn giản, dần thêm sets, NAT, logging — và bạn sẽ thấy nftables thực sự trực quan hơn iptables rất nhiều khi đã quen với cú pháp của nó.

Tài liệu tham khảo:

Tác giả: Mạnh Hoàng

Tôi là Hoàng Mạnh, người sáng lập blog SysadminSkills.com. Tôi viết về quản trị hệ thống, bảo mật máy chủ, DevOps và cách ứng dụng AI để tự động hóa công việc IT. Blog này là nơi tôi chia sẻ những gì đã học được từ thực tế – đơn giản, ngắn gọn và áp dụng được ngay.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *