Quản trị VPS

Firewall VPS nên mở những cổng nào?

Cách xác định cổng cần mở cho web, SSH, database và Docker mà không công khai dịch vụ nội bộ hoặc tự khóa đường quản trị VPS.

Cổng mạng và firewall VPS
Mục lục

Khi triển khai VPS phục vụ website, nhu cầu mở kết nối từ Internet (inbound public) thường chỉ dừng ở hai cổng quen thuộc: TCP 80 (HTTP) và TCP 443 (HTTPS). Cổng SSH (mặc định 22 hoặc cổng tùy biến) là đường quản trị sống còn, chỉ nên mở trong phạm vi kiểm soát thay vì để mở rộng cho toàn bộ Internet.

Những dịch vụ dữ liệu và xử lý nội bộ như MySQL, PostgreSQL, Redis, application port phía sau reverse proxy, dashboard quản trị hay Docker API hoàn toàn không có lý do để public ra ngoài. Nếu các tiến trình này chỉ phục vụ ứng dụng trên cùng máy chủ hoặc trong mạng riêng nội bộ, hãy ràng buộc chúng trên interface loopback (127.0.0.1), mạng container riêng hoặc private network.

Một cấu hình firewall chuẩn không đơn thuần là danh sách các con số. Bạn cần xác định rõ giao thức (TCP/UDP), nguồn kết nối (source IP), network interface tiếp nhận, cả hai ngăn xếp IPv4/IPv6 và lớp firewall nào đang thực thi quy tắc đó.

Bảng quyết định cổng cho VPS chạy website

Dịch vụCổng mặc địnhCó nên public ra Internet?Phạm vi kết nối phù hợp
HTTPTCP 80Có, nếu VPS nhận traffic trực tiếpMọi IP; hoặc chỉ IP của CDN/Load Balancer nếu kiến trúc yêu cầu
HTTPSTCP 443Có, nếu VPS nhận traffic trực tiếpMọi IP; hoặc chỉ IP của CDN/Load Balancer nếu kiến trúc yêu cầu
SSHTCP 22 (hoặc custom)Càng hẹp càng an toànIP tĩnh quản trị, mạng VPN, Bastion Host hoặc Cloud Console
Application backend3000, 8000, 8080…KhôngChỉ nghe trên 127.0.0.1 hoặc mạng nội bộ để Nginx reverse proxy gọi tới
MySQL / MariaDBTCP 3306KhôngLoopback nếu cùng máy, hoặc private network chỉ cho phép IP app server
PostgreSQLTCP 5432KhôngLoopback nếu cùng máy, hoặc private network chỉ cho phép IP app server
Redis / MemcachedTCP 6379, 11211Tuyệt đối khôngLoopback hoặc private network, có đặt mật khẩu xác thực bổ sung
Dashboard / MonitoringTùy dịch vụKhông mặc định publicTruy cập qua VPN, SSH tunnel, access proxy hoặc IP quản trị
Docker Daemon API2375, 2376Tuyệt đối khôngDùng UNIX socket cục bộ (/var/run/docker.sock), không mở qua TCP

Khái niệm "không public" không có nghĩa là dịch vụ đó ngừng hoạt động. Nó có nghĩa dịch vụ chỉ lắng nghe trên giao diện mạng cục bộ, hoặc firewall chỉ cho phép đúng địa chỉ IP nguồn hợp lệ kết nối tới.

Kiểm tra dịch vụ đang lắng nghe trước khi viết quy tắc firewall

Cổng mạng chỉ là một quy ước định tuyến. Mặc dù SSH thường gắn với cổng 22, HTTP gắn với 80 và HTTPS là 443, một tiến trình ứng dụng bất kỳ hoàn toàn có thể lắng nghe trên cổng 8080, và một service ngoài ý muốn cũng có thể đang mở sẵn trên hệ thống mà bạn chưa biết.

Trước khi bật firewall hay thêm bớt quy tắc, bạn cần nắm rõ danh sách cổng đang mở trên máy chủ:

  • Tiến trình hoặc container nào đang chạy và lắng nghe kết nối.
  • Tiến trình đó đang lắng nghe trên địa chỉ nào: 127.0.0.1 (chỉ cục bộ), IP mạng nội bộ hay 0.0.0.0 (mọi interface mạng).
  • Giao thức sử dụng là TCP hay UDP.
  • Đang mở trên IPv4, IPv6 hay cả hai.
  • Ai hoặc dịch vụ nào thực sự cần kết nối tới cổng đó.
  • Dữ liệu đi thẳng từ người dùng Internet, đi qua CDN, Load Balancer hay qua tunnel VPN.

Trên máy chủ Linux, lệnh ss giúp kiểm tra nhanh các socket đang lắng nghe:

bash
sudo ss -tulpn

Kết quả từ câu lệnh này cần được đối chiếu trực tiếp với file cấu hình của Nginx, database và Docker Compose. Đừng vội đóng một cổng khi chưa hiểu nó thuộc về tiến trình nào, nhưng cũng tuyệt đối không để cổng đó public chỉ vì cảm giác "chắc nó đang phục vụ việc gì đó".

ListenerDịch vụInterface bindClient hợp lệMục đích
*:443Nginx reverse proxyPublic IPv4/IPv6Khách truy cập webNhận traffic HTTPS
127.0.0.1:3000Node.js backendLoopback nội bộNginx trên cùng VPSXử lý logic nội bộ
10.0.0.5:5432PostgreSQLPrivate IPApp server trong mạng LANTruy vấn dữ liệu nội bộ

Cổng 80 có cần mở khi website đã chuyển hoàn toàn sang HTTPS?

Hầu hết các website hiện đại đều đã cài đặt chứng chỉ SSL/TLS, nhưng bạn vẫn nên giữ cổng TCP 80 mở trên firewall.

Có hai lý do thực tế cho việc này:

  1. Chuyển hướng người dùng (Redirect): Khi khách truy cập gõ tên miền vào thanh địa chỉ trình duyệt mà không kèm tiền tố https://, trình duyệt mặc định gửi request qua cổng 80 (HTTP). Nginx cần nhận request này để trả về mã phản hồi 301 chuyển hướng người dùng sang https://. Nếu chặn cổng 80, người dùng sẽ gặp thông báo lỗi không thể kết nối thay vì được chuyển hướng mượt mà.
  2. Cấp và gia hạn chứng chỉ SSL tự động: Các công cụ phổ biến như Let's Encrypt (Certbot) mặc định sử dụng cơ chế HTTP-01 challenge để xác thực quyền sở hữu tên miền khi cấp mới hoặc gia hạn tự động mỗi 60-90 ngày. Cơ chế này đòi hỏi máy chủ Let's Encrypt phải truy cập được vào cổng 80 của VPS.

Nếu hệ thống nằm sau Cloudflare hoặc các dịch vụ CDN tương tự, bạn có thể cân nhắc cấu hình firewall ở tầng Cloud Firewall chỉ cho phép dải IP của CDN kết nối tới cổng 80 và 443 của VPS, ngăn chặn việc bot rà quét trực tiếp vào IP gốc (Origin IP).

Kiểm soát đường truy cập SSH

SSH là kênh quản trị tối cao nắm quyền kiểm soát toàn bộ VPS, không phải dịch vụ công cộng cho người dùng đại trà. Nếu doanh nghiệp có dải IP văn phòng cố định, hãy giới hạn rule firewall SSH chỉ cho phép nguồn từ dải IP này, hoặc kết nối thông qua VPN / Bastion Host.

Trường hợp đội ngũ quản trị dùng IP mạng động hoặc thường xuyên làm việc từ xa, việc khóa cứng một IP duy nhất có thể gây gián đoạn công việc. Khi đó, bạn cần thiết lập nhiều lớp bảo vệ kết hợp:

  • Bắt buộc xác thực bằng SSH key và tắt hẳn xác thực mật khẩu như đã hướng dẫn trong bài Dùng SSH key thế nào để giảm rủi ro mất quyền truy cập VPS?.
  • Đổi cổng SSH mặc định từ 22 sang một cổng số cao ngẫu nhiên (ví dụ 2222 hoặc 50222). Việc đổi cổng không làm SSH an toàn hơn về mặt mật mã học, nhưng giúp cắt giảm tới hơn 90% lượng log rác sinh ra từ các công cụ dò quét mật khẩu tự động quét cổng 22 trên toàn mạng.
  • Kích hoạt công cụ giới hạn tần suất truy cập như fail2ban để tự động chặn các IP cố tình thử sai nhiều lần.
  • Luôn chuẩn bị sẵn quyền truy cập web console hoặc chế độ rescue trên trang quản trị của nhà cung cấp dịch vụ đám mây để đề phòng sự cố mạng.

Sau khi đã hoàn thiện các bước khởi tạo cơ bản trong 12 việc cần làm ngay sau khi nhận bàn giao VPS mới, bạn sẽ tiến hành khóa chặt firewall mà không lo bị mất quyền điều khiển.

Database, Redis và backend app: Ràng buộc interface trước khi dùng firewall

Một sai lầm rất thường gặp là mở cổng MySQL (3306), PostgreSQL (5432) hoặc Redis (6379) ra ngoài Internet để các lập trình viên tiện dùng phần mềm giao diện như DBeaver hay TablePlus kết nối từ máy cá nhân.

Mật khẩu mạnh và kết nối mã hóa SSL không phải lý do để đưa một dịch vụ dữ liệu nội bộ ra ngoài Internet. Bất kỳ sơ hở bảo mật zero-day nào trên phần mềm database hoặc sự cố lộ thông tin cấu hình đều có thể biến máy chủ thành mục tiêu tấn công trực tiếp.

Giải pháp chuẩn kỹ thuật:

  • Nếu cơ sở dữ liệu và ứng dụng chạy chung trên một VPS: cấu hình database chỉ lắng nghe trên 127.0.0.1 (bind-address = 127.0.0.1 trong file cấu hình MySQL). Khi đó, dù firewall có mở hay đóng, hacker từ bên ngoài cũng không thể gửi gói tin tới database.
  • Khi cần truy cập database để bảo trì hoặc phân tích dữ liệu từ máy cá nhân: sử dụng tính năng SSH Tunnel (Port Forwarding) qua đường kết nối SSH có sẵn thay vì mở cổng database trên firewall.
  • Nếu database và ứng dụng nằm ở hai máy chủ riêng biệt: cấu hình database lắng nghe trên private IP của mạng nội bộ (VPC) và thiết lập firewall chỉ chấp nhận kết nối từ đúng địa chỉ IP riêng của máy chủ ứng dụng.

Nguyên tắc tương tự áp dụng cho cổng ứng dụng backend (Node.js port 3000, Python port 8000, Go port 8080). Hãy để Nginx đứng phía trước làm reverse proxy, còn ứng dụng chỉ bind trên 127.0.0.1. Cách thiết lập này giúp tập trung việc quản lý chứng chỉ SSL, nén dữ liệu, ghi log truy cập và chặn các request bất thường ngay tại tầng Nginx.

Thứ tự an toàn khi kích hoạt UFW để không tự khóa mình ở ngoài

Trên Ubuntu, UFW (Uncomplicated Firewall) là công cụ quản lý iptables phổ biến nhất nhờ cú pháp trực quan. Tuy nhiên, trên nhiều bản cài đặt hệ điều hành từ nhà cung cấp, UFW mặc định ở trạng thái tắt (inactive). Nếu bạn vội vàng chạy lệnh kích hoạt mà chưa cấu hình cổng cho SSH, firewall sẽ ngay lập tức ngắt phiên làm việc và chặn đứng mọi kết nối mới.

Hãy tuân thủ nghiêm ngặt quy trình từng bước sau:

Bước 1: Giữ nguyên phiên SSH hiện tại Tuyệt đối không đóng cửa sổ terminal đang thao tác cho đến khi bạn xác nhận phiên kết nối mới đã hoạt động ổn định.

Bước 2: Kiểm tra cổng SSH đang sử dụng Xác định cổng SSH máy chủ đang lắng nghe (mặc định 22 hoặc cổng tùy biến trong /etc/ssh/sshd_config).

Bước 3: Thiết lập chính sách mặc định Chặn toàn bộ lưu lượng chiều vào (incoming) và cho phép lưu lượng chiều ra (outgoing):

bash
sudo ufw default deny incoming
sudo ufw default allow outgoing

Bước 4: Mở cổng cho SSH trước tiên Nếu dùng cổng mặc định:

bash
sudo ufw allow 22/tcp

Nếu đã đổi sang cổng khác (ví dụ 2222):

bash
sudo ufw allow 2222/tcp

Nếu có IP tĩnh văn phòng cố định (ví dụ 1.2.3.4):

bash
sudo ufw allow from 1.2.3.4 to any port 2222 proto tcp

Bước 5: Mở cổng web cho Nginx

bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Bước 6: Kiểm tra lại các quy tắc trước khi bật

bash
sudo ufw show added

Bước 7: Kích hoạt UFW

bash
sudo ufw enable

Bước 8: Mở một cửa sổ terminal mới để kiểm tra Mở một cửa sổ dòng lệnh riêng biệt trên máy cá nhân của bạn và thử kết nối SSH vào VPS. Nếu kết nối thành công, bạn mới đóng phiên SSH cũ ở Bước 1. Nếu xảy ra sự cố, bạn vẫn còn phiên làm việc cũ đang mở để điều chỉnh quy tắc hoặc chạy sudo ufw disable.

Phối hợp giữa Cloud Firewall và Host Firewall

Nhiều nhà cung cấp dịch vụ hạ tầng đám mây (AWS Security Group, DigitalOcean Cloud Firewall, Hetzner Firewall, OVH Network Firewall) cung cấp sẵn lớp firewall phần cứng nằm ngoài máy chủ (Cloud Firewall). Trong khi đó, UFW hay nftables/iptables là phần mềm bảo vệ chạy trực tiếp bên trong hệ điều hành (Host Firewall).

Hai lớp bảo vệ này hoạt động song song và độc lập:

  • Cloud Firewall: Đóng vai trò lá chắn ngoài cùng, lọc bỏ toàn bộ các gói tin rác hoặc truy vấn vào cổng không hợp lệ trước khi chúng chạm tới card mạng của VPS. Điều này giúp tiết kiệm CPU và tài nguyên mạng của hệ điều hành khi bị quét cổng hay tấn công DDoS nhỏ.
  • Host Firewall (UFW): Đóng vai trò chốt chặn bên trong, kiểm soát chi tiết lưu lượng theo từng interface mạng (eth0, docker0, wg0) và bảo vệ máy chủ nếu cấu hình ở tầng cloud firewall vô tình bị nới lỏng.

Nếu Cloud Firewall mở cổng 3306 nhưng UFW trên VPS chặn, kết nối bên ngoài vẫn không thể vào được. Ngược lại, nếu UFW đã cho phép cổng 443 nhưng trên trang quản trị đám mây bạn quên mở cổng 443 trong Security Group, website vẫn sẽ báo lỗi time out. Khi chẩn đoán lỗi mạng, bạn luôn cần rà soát đồng thời cả hai lớp.

Lưu ý về địa chỉ IPv6

Nhiều nhà cung cấp VPS hiện nay tự động cấp phát cả địa chỉ IPv4 và IPv6 cho máy chủ. Các phần mềm web server hiện đại như Nginx mặc định lắng nghe trên cả hai giao thức (listen [::]:80 và listen [::]:443).

Một thiếu sót rất phổ biến là người quản trị cấu hình firewall cho IPv4 nhưng bỏ quên IPv6. Nếu UFW chưa kích hoạt hỗ trợ IPv6, hoặc Cloud Firewall chỉ áp dụng quy tắc cho IPv4, máy chủ của bạn có thể vô tình để lộ các dịch vụ nội bộ qua địa chỉ IPv6.

Hãy kiểm tra file /etc/default/ufw trên Ubuntu và đảm bảo dòng cấu hình sau đang được bật:

text
IPV6=yes

Khi kiểm tra trạng thái bằng lệnh sudo ufw status verbose, bạn sẽ thấy danh sách quy tắc xuất hiện theo từng cặp, bao gồm phiên bản cho IPv4 và phiên bản có đuôi (v6) cho IPv6. Nếu bản ghi DNS của tên miền có chứa bản ghi AAAA (trỏ về IPv6 của VPS), hãy kiểm tra kết nối website từ mạng hỗ trợ IPv6 để đảm bảo lưu lượng được định tuyến chính xác.

Tương tác giữa Docker và UFW: Vấn đề cổng bị bỏ qua

Nếu bạn sử dụng Docker trên VPS, đây là điểm kỹ thuật đặc biệt quan trọng: Docker tự động thao tác trực tiếp với các bảng iptables của Linux để xử lý việc chuyển tiếp gói tin (NAT).

Mặc định, khi bạn chạy container với tham số publish cổng dạng:

bash
docker run -d -p 8080:80 nginx

hoặc cấu hình trong file docker-compose.yml:

yaml
ports:
  - "8080:80"

Docker sẽ chèn các quy tắc vào chuỗi PREROUTING và DOCKER trong iptables. Cơ chế này khiến các gói tin gửi tới cổng 8080 được chuyển hướng thẳng vào container trước khi đi qua chuỗi quy tắc của UFW.

Hệ quả là dù bạn chưa từng cho phép cổng 8080 trong UFW, hay thậm chí bạn đã chạy lệnh sudo ufw deny 8080, người dùng ngoài Internet vẫn có thể truy cập thẳng vào container qua cổng 8080 của VPS. Lệnh sudo ufw status không phản ánh các quy tắc định tuyến này của Docker.

Cách xử lý đúng kỹ thuật:

Cách 1: Ràng buộc cổng vào địa chỉ loopback Nếu container chỉ cần giao tiếp với Nginx reverse proxy chạy trên cùng máy chủ, hãy luôn chỉ định rõ địa chỉ 127.0.0.1 trong cấu hình publish cổng:

yaml
ports:
  - "127.0.0.1:8080:80"

Khi đó, Docker chỉ lắng nghe cổng 8080 trên interface nội bộ của máy chủ, chặn đứng hoàn toàn khả năng kết nối từ card mạng công cộng.

Cách 2: Sử dụng Docker network nội bộ Nếu cả Nginx và ứng dụng backend đều chạy dưới dạng container Docker trên cùng máy chủ, bạn thậm chí không cần publish cổng backend ra host. Hãy đặt các container vào chung một Docker network do bạn tự định nghĩa, và cấu hình Nginx kết nối tới backend thông qua tên service của container (ví dụ http://backend:80). Cách quản lý này đã được phân tích chi tiết trong bài Docker network cho website nhỏ.

Tuyệt đối không giải quyết vấn đề bằng cách tắt tính năng iptables: false trong daemon Docker (/etc/docker/daemon.json), vì thao tác này sẽ phá vỡ toàn bộ khả năng kết nối mạng ra ngoài Internet của các container.

Ba bước xác nhận sau khi điều chỉnh firewall

Sau khi hoàn tất cấu hình, bạn cần tiến hành kiểm thử theo ba bước độc lập để chắc chắn hệ thống vận hành đúng kỳ vọng:

1. Kiểm tra trạng thái dịch vụ cục bộ

Xác nhận tiến trình vẫn đang chạy ổn định, lắng nghe đúng IP và cổng dự kiến:

bash
sudo ss -tulpn

2. Kiểm tra quy tắc firewall đang áp dụng

Kiểm tra danh sách quy tắc đang có hiệu lực trên UFW:

bash
sudo ufw status verbose

Nếu có sử dụng Docker, kiểm tra thêm bảng iptables xem có cổng nào đang bị Docker expose ngoài ý muốn hay không:

bash
sudo iptables -t nat -L DOCKER -n -v

3. Kiểm thử kết nối từ môi trường mạng bên ngoài

Sử dụng một máy tính hoặc VPS khác nằm ngoài mạng nội bộ để kiểm tra thực tế:

  • Kiểm tra truy cập web: chạy lệnh curl -I https://tenmien.com và curl -I http://tenmien.com để xem HTTPS và HTTP redirect hoạt động chuẩn xác không.
  • Thử kết nối SSH: mở phiên SSH mới tới địa chỉ IP và cổng cấu hình.
  • Thử kết nối vào các cổng cần đóng (như 3306, 6379, 8080): lệnh kết nối phải rơi vào trạng thái timeout hoặc từ chối kết nối (Connection refused/filtered). Bạn có thể dùng nc -zv <IP-VPS> 3306 từ máy ngoài để kiểm tra.

Quản lý và lưu vết quy tắc firewall theo thời gian

Trong quá trình vận hành, firewall thường bị phình to bởi những quy tắc tạm thời được thêm vào trong lúc debug sự cố, chuyển dữ liệu hoặc thử nghiệm phần mềm mới. Một quy tắc mở cổng tạm nếu không được ghi chép sẽ nhanh chóng bị lãng quên và tồn tại âm thầm suốt nhiều năm, tạo ra lỗ hổng bảo mật tiềm tàng.

Khi quản trị hệ thống, bạn nên duy trì một tài liệu ghi chép ngắn gọn về cấu hình mạng:

  • Cổng được mở là gì, giao thức nào.
  • Dịch vụ nào đang sử dụng cổng này và ai chịu trách nhiệm quản lý.
  • Nguồn IP nào được phép truy cập.
  • Đây là quy tắc cố định hay tạm thời. Nếu tạm thời, ngày nào sẽ gỡ bỏ?

Định kỳ trong quy trình quản trị VPS hàng tháng, hãy rà soát lại toàn bộ danh sách cổng mở bằng sudo ufw status numbered. Bất kỳ quy tắc nào không còn mục đích sử dụng rõ ràng cần được xóa bỏ ngay lập tức bằng lệnh sudo ufw delete <số-thứ-tự-rule>.

Bên cạnh việc thiết lập firewall, bạn cũng cần kết hợp đồng bộ việc phân quyền tài khoản quản trị và hạn chế quyền sudo như phân tích trong bài Bảo mật tài khoản quản trị và quyền sudo trên VPS để tạo thành một hệ thống phòng thủ nhiều lớp vững chắc.

Checklist kiểm tra firewall cho VPS chạy website

  • ☐ Đã xác nhận quyền truy cập web console / rescue mode trên tài khoản nhà cung cấp đám mây.
  • ☐ Luôn giữ một phiên SSH đang hoạt động trước khi chỉnh sửa quy tắc hoặc kích hoạt firewall.
  • ☐ Đã kiểm kê toàn bộ tiến trình đang listen bằng lệnh sudo ss -tulpn.
  • ☐ Chính sách mặc định đã thiết lập: chặn toàn bộ chiều vào (deny incoming), cho phép chiều ra (allow outgoing).
  • ☐ Đã mở cổng SSH trước khi bật firewall và kiểm tra kết nối bằng một cửa sổ terminal mới.
  • ☐ Chỉ mở công khai cổng 80 và 443 cho lưu lượng web thông thường.
  • ☐ Database (MySQL, PostgreSQL), Redis và cổng application nội bộ được bind trên 127.0.0.1 hoặc private IP, không public ra Internet.
  • ☐ Đã kiểm tra cấu hình IPv6 trong UFW (IPV6=yes) và kiểm tra quy tắc cho cả IPv4 lẫn IPv6.
  • ☐ Nếu dùng Docker, các cổng nội bộ đã được bind chỉ định dạng 127.0.0.1:port:port hoặc dùng Docker network nội bộ để tránh việc Docker tự động vượt mặt UFW.
  • ☐ Đã kiểm tra kết nối thực tế từ một máy bên ngoài Internet đối với cả cổng mở và các cổng cần chặn.
  • ☐ Đã ghi chép mục đích của từng quy tắc để phục vụ việc rà soát định kỳ hàng tháng.

Quy tắc bất biến trong quản trị an ninh mạng là chỉ mở những gì thực sự cần thiết, cho đúng đối tượng cần kết nối. Nếu một cổng dịch vụ không phục vụ trực tiếp cho người dùng web công cộng, nó không có lý do để xuất hiện trên bản đồ cổng mở từ Internet.

Nguồn tham khảo

Chia sẻ bài viết hữu ích

Gửi bài viết này cho đồng nghiệp

Đọc tiếp

Bài nên đọc tiếp

Xem tất cả bài về Quản trị VPS