❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.

Khi bạn thuê một VPS và đưa lên internet, nó giống như đặt một căn nhà giữa ngã tư đông đúc vậy. Ai cũng có thể đi ngang, gõ cửa, thậm chí thử mở khóa. Firewall chính là cánh cổng giúp bạn kiểm soát ai được vào, ai bị chặn lại.

linux b10 firewall

Bài này mình sẽ đi qua 2 công cụ firewall phổ biến nhất trên Linux VPS: UFW cho Ubuntu/Debian và firewalld cho AlmaLinux/Rocky/RHEL. Cả hai đều là frontend của iptables/nftables phía dưới, nhưng cách dùng khác nhau hoàn toàn.

Firewall là gì và tại sao VPS cần nó?

Firewall (tường lửa) là lớp bảo vệ nằm giữa VPS của bạn và internet. Nhiệm vụ của nó đơn giản: kiểm tra mọi kết nối đến và đi, rồi quyết định cho phép hay chặn dựa trên các rule bạn đặt ra.

Một VPS mới tinh thường mở toang tất cả các port. Nghĩa là nếu bạn chạy MySQL trên port 3306, ai trên internet cũng có thể thử kết nối vào. Bot quét port chạy 24/7, và VPS của bạn sẽ bị “gõ cửa” liên tục chỉ vài phút sau khi online.

Firewall giúp bạn:

  • Chỉ mở đúng port cần thiết (SSH, HTTP, HTTPS)
  • Chặn truy cập vào các service nội bộ (database, cache, admin panel)
  • Giới hạn truy cập theo IP hoặc subnet
  • Giảm bề mặt tấn công đáng kể

Trên Linux, iptables (và nftables ở kernel mới) là engine xử lý firewall thực sự. Nhưng viết rule iptables trực tiếp khá phức tạp, nên người ta tạo ra các tool frontend dễ dùng hơn. Ubuntu/Debian dùng UFW, còn RHEL-based (AlmaLinux, Rocky, CentOS) dùng firewalld.

UFW trên Ubuntu/Debian

UFW viết tắt của Uncomplicated Firewall. Đúng như tên gọi, nó được thiết kế để đơn giản nhất có thể. Trên Ubuntu, UFW được cài sẵn nhưng mặc định tắt.

Kiểm tra trạng thái

sudo ufw status

Nếu chưa bật, bạn sẽ thấy Status: inactive. Khi đã bật và có rule, nó sẽ hiện danh sách các rule đang active.

Muốn xem chi tiết hơn với output dạng verbose:

sudo ufw status verbose

Thiết lập default policy

Trước khi bật UFW, bạn nên set default policy. Nguyên tắc là: chặn hết traffic đến, cho phép hết traffic đi ra.

sudo ufw default deny incoming
sudo ufw default allow outgoing

Với policy này, mọi kết nối từ bên ngoài vào sẽ bị chặn trừ khi bạn cho phép rõ ràng. Còn VPS vẫn kết nối ra ngoài bình thường (cập nhật package, gửi email, gọi API,…).

Bật UFW

⚠️ Luôn allow SSH trước khi bật UFW! Nếu bạn bật firewall mà chưa mở port 22, bạn sẽ bị lock out khỏi VPS ngay lập tức. Lúc đó phải vào console từ panel nhà cung cấp để sửa.

sudo ufw allow 22/tcp
sudo ufw enable

UFW sẽ hỏi xác nhận vì nó có thể làm gián đoạn kết nối SSH hiện tại. Gõ y để tiếp tục. Thực tế nếu bạn đã allow port 22 thì kết nối hiện tại không bị ảnh hưởng.

Các lệnh quản lý rule

Mở port cho service:

# Mở HTTP
sudo ufw allow 80/tcp

# Mở HTTPS sudo ufw allow 443/tcp

# Mở cả HTTP và HTTPS cùng lúc sudo ufw allow 80,443/tcp

Cho phép truy cập từ IP hoặc subnet cụ thể:

# Cho phép một IP cụ thể truy cập tất cả port
sudo ufw allow from 203.0.113.50

# Cho phép cả subnet sudo ufw allow from 192.168.1.0/24

# Cho phép một IP chỉ truy cập port cụ thể sudo ufw allow from 203.0.113.50 to any port 3306

Chặn port:

# Chặn MySQL từ bên ngoài
sudo ufw deny 3306
# Chặn một IP cụ thể
sudo ufw deny from 198.51.100.0/24

Xem rule có đánh số:

sudo ufw status numbered

Output sẽ kiểu như:

Status: active
To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere
[ 4] 3306                       DENY IN     Anywhere

Xóa rule:

# Xóa theo nội dung rule
sudo ufw delete allow 80/tcp
# Xóa theo số thứ tự (lấy từ status numbered)
sudo ufw delete 2

Reset toàn bộ:

sudo ufw reset

Lệnh này xóa sạch tất cả rule và tắt UFW. Nó sẽ backup rule cũ vào file trước khi xóa, nên không sợ mất hoàn toàn.

UFW với application profile

UFW có sẵn một số application profile. Xem danh sách bằng:

sudo ufw app list

Bạn có thể allow theo tên app thay vì port number:

sudo ufw allow 'Nginx Full'
sudo ufw allow 'OpenSSH'

Tiện hơn so với nhớ port number, nhất là với các service dùng nhiều port.

firewalld trên AlmaLinux/Rocky/RHEL

firewalld là firewall manager mặc định trên các distro RHEL-based. Khác với UFW dùng kiểu “allow port X, deny port Y” đơn giản, firewalld tổ chức rule theo zone. Mỗi zone là một bộ rule áp dụng cho network interface hoặc source IP.

Kiểm tra trạng thái

# Xem firewalld có đang chạy không
sudo firewall-cmd --state

# Bật firewalld sudo systemctl start firewalld

# Bật firewalld khi khởi động sudo systemctl enable firewalld

Xem toàn bộ cấu hình hiện tại:

sudo firewall-cmd --list-all

Output mẫu:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

Khái niệm Zone

Zone là điểm khác biệt lớn nhất giữa firewalld và UFW. Thay vì rule áp dụng chung cho cả server, firewalld cho phép bạn gán mỗi network interface hoặc source IP vào một zone khác nhau, và mỗi zone có bộ rule riêng.

Các zone quan trọng nhất:

  • public (mặc định): Dùng cho mạng không tin tưởng. Chỉ cho phép các service bạn chỉ định. Đây là zone bạn sẽ dùng nhiều nhất trên VPS.
  • trusted: Cho phép mọi kết nối. Dùng cho mạng nội bộ mà bạn tin tưởng hoàn toàn (ví dụ: VPN internal).
  • drop: Chặn mọi kết nối đến mà không phản hồi gì. Kẻ tấn công không biết port có tồn tại hay không. Dùng khi muốn “giấu” VPS.
  • internal: Tương tự trusted nhưng cho mạng nội bộ cụ thể.
  • dmz: Cho các server cần expose ra ngoài nhưng giới hạn quyền truy cập vào mạng nội bộ.

Xem zone đang active:

sudo firewall-cmd --get-active-zones

Xem danh sách tất cả zone có sẵn:

sudo firewall-cmd --get-zones

Quản lý rule với firewall-cmd

firewalld có 2 loại config: runtime (có hiệu lực ngay, mất khi restart) và permanent (lưu vĩnh viễn, cần reload để áp dụng). Luôn thêm --permanent rồi --reload để rule không bị mất.

Mở service:

# Mở HTTP
sudo firewall-cmd --add-service=http --permanent

# Mở HTTPS sudo firewall-cmd --add-service=https --permanent

# Apply thay đổi sudo firewall-cmd --reload

firewalld có sẵn định nghĩa cho rất nhiều service (http, https, ssh, mysql, postgresql,…). Xem danh sách đầy đủ:

sudo firewall-cmd --get-services

Mở port cụ thể:

# Mở port 8080
sudo firewall-cmd --add-port=8080/tcp --permanent

# Mở range port sudo firewall-cmd --add-port=3000-3100/tcp --permanent

sudo firewall-cmd --reload

Xóa rule:

# Xóa service
sudo firewall-cmd --remove-service=http --permanent

# Xóa port sudo firewall-cmd --remove-port=8080/tcp --permanent

sudo firewall-cmd --reload

Giới hạn truy cập theo IP (rich rule):

# Cho phép IP cụ thể truy cập port 3306
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.50" port port="3306" protocol="tcp" accept'

# Chặn một IP sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" drop'

sudo firewall-cmd --reload

Gán source IP vào zone:

# Đưa subnet nội bộ vào zone trusted
sudo firewall-cmd --permanent --zone=trusted --add-source=10.0.0.0/8
sudo firewall-cmd --reload

So sánh UFW và firewalld

Tiêu chíUFWfirewalld
Distro mặc địnhUbuntu, DebianAlmaLinux, Rocky, RHEL, Fedora
Độ phức tạpĐơn giản, dễ họcPhức tạp hơn, nhiều khái niệm
Cách tổ chức ruleFlat list (allow/deny)Zone-based
Runtime vs PermanentMọi thay đổi lưu ngayCần --permanent + --reload
Service profilesApplication profile đơn giảnService definitions chi tiết
Rich rulesHạn chếHỗ trợ tốt (rich rule syntax)
Phù hợp vớiVPS đơn giản, web serverHệ thống phức tạp, nhiều network zone
Backendiptables/nftablesnftables (mới) / iptables (cũ)

Nói ngắn gọn: UFW đơn giản và đủ dùng cho hầu hết VPS. firewalld mạnh hơn nếu bạn cần quản lý nhiều zone, nhiều network interface, hoặc rule phức tạp.

Setup firewall cho VPS mới (step-by-step)

Đây là quy trình mình recommend cho bất kỳ VPS mới nào. Thứ tự các bước rất quan trọng, đặc biệt bước 1.

Trên Ubuntu (UFW)

# Bước 1: Allow SSH TRƯỚC — bước này bắt buộc
sudo ufw allow 22/tcp

# Bước 2: Set default policy sudo ufw default deny incoming sudo ufw default allow outgoing

# Bước 3: Bật firewall sudo ufw enable

# Bước 4: Mở HTTP/HTTPS (nếu chạy web server) sudo ufw allow 80/tcp sudo ufw allow 443/tcp

# Bước 5: Verify sudo ufw status verbose

Output sau bước 5 nên trông như thế này:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere

Trên AlmaLinux (firewalld)

# Bước 1: Kiểm tra SSH đã được allow chưa (thường có sẵn)
sudo firewall-cmd --list-services
# Nếu không thấy "ssh" trong danh sách:
sudo firewall-cmd --add-service=ssh --permanent

# Bước 2: Bật firewalld sudo systemctl start firewalld sudo systemctl enable firewalld

# Bước 3: Mở HTTP/HTTPS sudo firewall-cmd --add-service=http --permanent sudo firewall-cmd --add-service=https --permanent

# Bước 4: Default zone "public" đã deny mọi thứ ngoài service được allow # Không cần set thêm gì

# Bước 5: Apply và verify sudo firewall-cmd --reload sudo firewall-cmd --list-all

Output sau bước 5:

public (active)
  target: default
  interfaces: eth0
  services: dhcpv6-client http https ssh
  ports:
  ...

Trên AlmaLinux/Rocky, firewalld thường được bật sẵn và SSH đã được allow. Nhưng luôn kiểm tra trước khi thêm rule, đừng assume.

Ví dụ thực tế

Web server cơ bản

VPS chạy Nginx/Apache, chỉ cần mở 3 port: SSH (22), HTTP (80), HTTPS (443).

UFW:

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

firewalld:

sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

Database server: chặn MySQL từ bên ngoài

MySQL chạy trên port 3306. Bạn muốn chỉ có app server (IP 10.0.0.5) mới kết nối được, chặn hết phần còn lại.

UFW:

# Chặn 3306 từ tất cả
sudo ufw deny 3306
# Cho phép riêng app server
sudo ufw allow from 10.0.0.5 to any port 3306

firewalld:

# Dùng rich rule để chỉ cho phép IP cụ thể
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.5" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload
# Không add service mysql vào zone public — mặc định đã bị chặn rồi

Lưu ý: MySQL mặc định bind trên 127.0.0.1 (chỉ localhost). Nếu bạn thay đổi bind-address trong config MySQL thì mới cần lo chuyện firewall cho port 3306.

Docker + Firewall: cái bẫy mà nhiều người gặp

⚠️ Docker bypass UFW! Đây là lỗi rất phổ biến. Docker tự thêm rule vào iptables, bỏ qua hoàn toàn UFW. Nghĩa là dù bạn deny port 3306 trong UFW, nếu có container expose port 3306, nó vẫn accessible từ internet.

Khi bạn chạy docker run -p 3306:3306 mysql, Docker sẽ tạo rule iptables riêng trong chain DOCKER, nằm ngoài tầm kiểm soát của UFW. Nhiều người tưởng firewall đang chặn nhưng thực tế port vẫn mở toang.

Cách xử lý trên Ubuntu (UFW):

Tạo hoặc sửa file /etc/docker/daemon.json:

{
  "iptables": false
}

Sau đó restart Docker:

sudo systemctl restart docker

Tuy nhiên, cách này có side effect: Docker container sẽ không tự tạo NAT rule, bạn phải tự quản lý networking. Cách khác mềm dẻo hơn là dùng chain DOCKER-USER trong iptables:

# Chặn truy cập từ ngoài vào container port 3306
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 3306 -j DROP
# Cho phép IP cụ thể
sudo iptables -I DOCKER-USER -i eth0 -s 10.0.0.5 -p tcp --dport 3306 -j ACCEPT

Nhớ save iptables rule để không mất khi reboot:

sudo apt install iptables-persistent
sudo netfilter-persistent save

Trên AlmaLinux (firewalld):

firewalld và Docker cũng có xung đột tương tự, nhưng Docker từ version 20.10+ đã hỗ trợ firewalld tốt hơn. Nếu bạn dùng Docker trên AlmaLinux, đảm bảo Docker service start sau firewalld và kiểm tra bằng firewall-cmd --list-all sau khi start container.

Cách an toàn nhất cho cả hai distro: không expose port ra host nếu không cần. Dùng Docker network internal và để container giao tiếp với nhau qua network name thay vì publish port.

# Thay vì: docker run -p 3306:3306 mysql
# Dùng Docker network:
docker network create app-net
docker run --network app-net --name db mysql
docker run --network app-net --name app myapp
# app kết nối MySQL qua hostname "db", không cần expose port

Lỗi thường gặp

1. Quên allow SSH rồi bật firewall

Đây là lỗi kinh điển. Bạn bật UFW hoặc firewalld mà chưa mở port 22, kết nối SSH hiện tại có thể vẫn sống (vì nó đã established), nhưng khi disconnect là không vào lại được.

Cách khắc phục: Vào VPS console qua web panel của nhà cung cấp (noVNC, IPMI, hoặc tương tự). Từ đó chạy:

# UFW
sudo ufw allow 22/tcp
# Hoặc nếu muốn reset hết
sudo ufw disable
# firewalld
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --reload

Phòng ngừa: Luôn mở SSH trước khi làm bất kỳ thứ gì khác với firewall. Tạo thói quen.

2. firewalld: dùng –permanent nhưng quên –reload

Bạn thêm rule với --permanent, tưởng nó đã hoạt động, nhưng thực tế chưa. Rule permanent chỉ lưu vào config file, chưa apply vào runtime. Phải chạy firewall-cmd --reload để nó có hiệu lực.

# SAI: rule chưa hoạt động
sudo firewall-cmd --add-service=http --permanent
# ĐÚNG: thêm rule + apply
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --reload

Ngược lại, nếu bạn thêm rule không có --permanent, nó hoạt động ngay nhưng sẽ mất khi restart firewalld hoặc reboot server.

3. Docker bypass UFW (đã nói ở trên)

Nhắc lại vì nó quan trọng: nếu bạn dùng Docker trên Ubuntu, đừng tin UFW là đủ. Kiểm tra bằng cách scan port từ bên ngoài để xác nhận. Không có gì thay thế được việc verify thực tế.

4. Mở quá nhiều port “cho chắc”

Một số người mở sẵn port 8080, 8443, 3000, 9090,… “phòng khi cần”. Nguyên tắc là: chỉ mở port nào đang thực sự dùng. Khi nào cần thêm thì mở, dùng xong thì đóng. Ít port mở = ít rủi ro.

Checkpoint: Verify firewall đang hoạt động

Setup xong rồi thì phải verify. Đừng tin lệnh status là đủ, hãy kiểm tra từ bên ngoài.

Kiểm tra port đang mở trên server

# Xem port nào đang listen
sudo ss -tlnp

Output cho bạn biết service nào đang chạy trên port nào. Nhưng đây chỉ là góc nhìn từ bên trong server.

Scan port từ bên ngoài bằng nmap

Từ máy local hoặc một VPS khác, chạy nmap để xem bên ngoài thấy gì:

# Scan các port phổ biến
nmap your-server-ip

# Scan port cụ thể nmap -p 22,80,443,3306 your-server-ip

# Scan tất cả 65535 port (lâu hơn) nmap -p- your-server-ip

Kết quả mong đợi cho web server cơ bản:

PORT    STATE    SERVICE
22/tcp  open     ssh
80/tcp  open     http
443/tcp open     https
3306/tcp filtered mysql

open nghĩa là port đang accessible. filtered nghĩa là firewall đang chặn (không phản hồi). closed nghĩa là port không có service nào listen nhưng firewall không chặn.

Test thử truy cập port bị chặn

# Từ máy khác, thử kết nối port 3306
nc -zv your-server-ip 3306
# Hoặc dùng telnet
telnet your-server-ip 3306

Nếu firewall hoạt động đúng, kết nối sẽ timeout hoặc bị refused. Nếu nó connect được thì bạn cần kiểm tra lại rule.

Verify firewall status

# UFW
sudo ufw status verbose
# firewalld
sudo firewall-cmd --list-all
sudo firewall-cmd --list-ports
sudo firewall-cmd --list-services

Kết hợp cả ss (bên trong) và nmap (bên ngoài) cho bạn bức tranh đầy đủ: service nào đang chạy, port nào đang mở, và firewall có thực sự chặn những gì cần chặn không.

📝 Bài tập checkpoint: Setup firewall trên VPS của bạn theo hướng dẫn ở trên. Sau đó từ máy local, dùng nmap scan server và so sánh kết quả với rule đã đặt. Thử tắt firewall, scan lại, rồi bật lại để thấy sự khác biệt. Đó là cách tốt nhất để hiểu firewall đang làm gì.

Chia sẻ:
Bài viết đã được kiểm duyệt bởi AZDIGI Team

Về tác giả

Trần Thắng

Trần Thắng

Chuyên gia tại AZDIGI với nhiều năm kinh nghiệm trong lĩnh vực web hosting và quản trị hệ thống.

Hơn 10 năm phục vụ 80.000+ khách hàng

Bắt đầu dự án web của bạn với AZDIGI