Quản trị VPS

Tách Database sang VPS riêng: Private VPC và tường lửa an toàn

Hướng dẫn cấu hình Private VPC, bind-address, tường lửa UFW và đo kiểm độ trễ mạng nội bộ dưới 1ms khi tách Database sang một máy chủ VPS độc lập.

Tách Database sang VPS riêng cấu hình Private VPC tường lửa và đo kiểm độ trễ
MỤC LỤC

Trong lộ trình chuyển dịch website từ Single-VPS sang cụm Multi-Server, bước đi giúp giải phóng hiệu năng rõ rệt nhất là tách hệ quản trị cơ sở dữ liệu (MySQL, MariaDB hoặc PostgreSQL) sang một máy chủ VPS chuyên dụng. Khi tách riêng, bạn có thể dành khoảng 75% đến 80% dung lượng RAM vật lý cho bộ đệm InnoDB Buffer Pool mà không lo bị các tiến trình web (PHP-FPM, Node.js) tranh chấp tài nguyên dẫn tới nguy cơ kích hoạt Linux OOM Killer. Đồng thời, toàn bộ năng lực đọc ghi ngẫu nhiên (IOPS) của ổ cứng NVMe sẽ được ưu tiên phục vụ các truy vấn dữ liệu.

Tuy nhiên, điểm mấu chốt khi đưa cơ sở dữ liệu sang máy chủ mới nằm ở tầng mạng. Nếu cấu hình sai card mạng hoặc để lưu lượng truy vấn đi qua Internet, độ trễ mạng sẽ tăng vọt từ mức 0.05ms (cục bộ) lên tới hàng chục mili-giây, kéo tụt tốc độ phản hồi của toàn bộ website. Ngoài ra, việc mở cổng cơ sở dữ liệu ra bên ngoài mà thiếu lớp kiểm soát truy cập sẽ mở rộng bề mặt dễ bị tấn công trước các đợt dò quét mật khẩu (brute-force) tự động.

Bài viết này hướng dẫn bạn quy trình thiết lập mạng riêng nội bộ (Private VPC), giới hạn cổng kết nối qua bind-address và tường lửa UFW, phân quyền truy cập theo địa chỉ IP nguồn, cùng các bước đo kiểm nhằm duy trì độ trễ giữa Web Server và Database Server dưới 0.8ms.

Kiến trúc tách Database sang VPS riêng qua Private VPC

Yêu cầu hạ tầng trước khi cấu hình

Trước khi tiến hành cấu hình, bạn cần chuẩn bị hai máy chủ đáp ứng các tiêu chí sau:

  1. Cùng nhà cung cấp và trung tâm dữ liệu: Hai VPS cần được đặt trong cùng một trung tâm dữ liệu, lý tưởng nhất là chung một Availability Zone. Bạn nên tránh đặt Web Server và Database Server ở hai nhà cung cấp khác nhau, bởi việc kết nối qua Internet giữa hai bên sẽ khiến độ trễ tăng cao và thiếu ổn định.
  2. Kích hoạt mạng nội bộ: Hầu hết các nhà cung cấp hạ tầng điện toán đám mây hiện nay (như Vietnix, Bizfly Cloud, Hetzner Cloud, DigitalOcean, AWS) đều hỗ trợ tính năng mạng riêng nội bộ (Private VPC) miễn phí hoặc với chi phí thấp. Mỗi VPS khi kích hoạt sẽ có thêm một card mạng thứ hai (ví dụ eth1 hoặc ens10).
  3. Quy ước dải mạng nội bộ:
  • Dải mạng con (Subnet): 10.0.0.0/24
  • Máy chủ Web (Web-01): 10.0.0.10
  • Máy chủ Database (DB-01): 10.0.0.20

Bước 1: Thiết lập card mạng nội bộ qua Netplan

Trên các bản phân phối Linux như Ubuntu 22.04 LTS hoặc 24.04 LTS, cấu hình mạng được quản lý tập trung thông qua Netplan.

Trước tiên, bạn đăng nhập SSH vào máy chủ Database (DB-01) và kiểm tra danh sách card mạng hiện có:

bash
ip -br link

Kết quả trả về thường hiển thị dạng:

text
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP> 
eth0             UP             52:54:00:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP> 
eth1             DOWN           52:54:00:78:9a:bc <BROADCAST,MULTICAST> 

Trong đó, eth0 là card mạng kết nối Internet (IP public), còn eth1 là card mạng nội bộ đang ở trạng thái chưa kích hoạt (DOWN).

Mở tệp cấu hình Netplan trên DB-01:

bash
sudo nano /etc/netplan/01-netcfg.yaml

Thiết lập địa chỉ IP tĩnh cho eth1 mà không khai báo gateway (nhằm tránh xung đột với cổng định tuyến mặc định ra Internet của eth0):

yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: true
    eth1:
      addresses:
        - 10.0.0.20/24
      mtu: 1500

Lưu tệp và áp dụng cấu hình:

bash
sudo netplan apply

Kiểm tra card mạng eth1 đã nhận IP thành công:

bash
ip -4 addr show dev eth1

Dòng thông tin inet 10.0.0.20/24 brd 10.0.0.255 scope global eth1 cho thấy card mạng đã hoạt động. Bạn thực hiện thao tác tương tự trên máy chủ Web-01 với địa chỉ IP tương ứng là 10.0.0.10/24.

Bước 2: Cấu hình MySQL lắng nghe trên card mạng nội bộ

Theo mặc định sau khi cài đặt, MySQL chỉ lắng nghe kết nối cục bộ trên địa chỉ loopback 127.0.0.1. Khi chuyển sang mô hình máy chủ độc lập, người quản trị đôi khi cấu hình bind-address = 0.0.0.0 để cho phép kết nối từ xa.

Thiết lập 0.0.0.0 sẽ mở cổng 3306 ra mọi giao diện mạng, bao gồm cả IP công cộng. Điều này làm tăng bề mặt dễ bị tấn công do các botnet trên Internet liên tục dò quét cổng và thử mật khẩu, gây lãng phí tài nguyên CPU của máy chủ.

Giải pháp an toàn là gắn dịch vụ MySQL vào đúng địa chỉ IP của card mạng nội bộ:

Mở tệp cấu hình MySQL trên DB-01:

bash
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Tìm tham số bind-address và chuyển sang IP nội bộ của DB-01:

ini
[mysqld]
# Chỉ chấp nhận kết nối trên card mạng nội bộ
bind-address            = 10.0.0.20

# Tắt phân giải DNS ngược để tăng tốc bắt tay kết nối (TCP Handshake)
skip-name-resolve

Lưu tệp và khởi động lại dịch vụ MySQL:

bash
sudo systemctl restart mysql

Kiểm tra cổng lắng nghe bằng lệnh ss:

bash
sudo ss -tulpn | grep 3306

Kết quả hợp lệ hiển thị như sau:

text
tcp   LISTEN 0      151       10.0.0.20:3306       0.0.0.0:*    users:(("mysqld",pid=14205,fd=31))

Khi cột Local Address hiển thị 10.0.0.20:3306 (thay vì 0.0.0.0:3306), dịch vụ MySQL đã được giới hạn an toàn trong phạm vi mạng nội bộ.

Bước 3: Cấu hình tường lửa UFW bảo vệ cổng cơ sở dữ liệu

Song song với bind-address, lớp bảo vệ tiếp theo theo nguyên tắc thiết lập tường lửa bảo vệ VPS là sử dụng UFW để kiểm soát lưu lượng ngay tại tầng nhân Linux.

Trên máy chủ DB-01, bạn thiết lập chính sách mặc định là chặn toàn bộ lưu lượng đến:

bash
# Thiết lập chính sách mặc định
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Cho phép SSH nội bộ từ máy chủ Web (hoặc IP VPN quản trị)
sudo ufw allow in on eth1 from 10.0.0.10 to any port 22 proto tcp comment "Internal SSH from Web-01"

# Nếu bạn cần SSH khẩn cấp từ IP tĩnh văn phòng qua card eth0 (thay thế bằng IP thực tế của bạn)
# sudo ufw allow in on eth0 from 118.69.xxx.xxx to any port 22 proto tcp comment "Admin Office SSH"

# Chỉ cho phép duy nhất IP nội bộ của Web-01 kết nối vào cổng MySQL trên card eth1
sudo ufw allow in on eth1 from 10.0.0.10 to any port 3306 proto tcp comment "Allow MySQL from Web-01"

# Bật tường lửa
sudo ufw enable

Xác nhận lại trạng thái tường lửa:

bash
sudo ufw status verbose

Kết quả kiểm tra:

text
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp on eth1             ALLOW IN    10.0.0.10                  # Internal SSH from Web-01
3306/tcp on eth1           ALLOW IN    10.0.0.10                  # Allow MySQL from Web-01

Với cấu hình này, các gói tin gửi tới cổng 3306 từ Internet (eth0) hoặc từ bất kỳ địa chỉ IP nào khác ngoài 10.0.0.10 sẽ bị tường lửa loại bỏ (DROP) ngay lập tức.

Bước 4: Phân quyền tài khoản MySQL theo IP nguồn

Trong cơ sở dữ liệu MySQL, quyền truy cập của người dùng luôn gắn liền với máy chủ nguồn (Host). Một sai lầm phổ biến trong thực tế là cấp quyền dạng 'username'@'%' (trong đó ký tự % đại diện cho mọi địa chỉ IP).

Để đảm bảo an toàn cho dữ liệu, bạn cần chỉ định chính xác địa chỉ IP nội bộ của Web Server (10.0.0.10):

Đăng nhập vào MySQL trên DB-01:

bash
sudo mysql -u root -p

Thực thi câu lệnh tạo người dùng và gán quyền hạn tối thiểu cần thiết:

sql
-- Tạo tài khoản ứng dụng chỉ cho phép kết nối từ 10.0.0.10
CREATE USER 'app_prod'@'10.0.0.10' IDENTIFIED BY 'MatKhauPhucTapItNhat32KyTuRanDom123!';

-- Cấp quyền vừa đủ trên cơ sở dữ liệu phục vụ website
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES 
ON production_db.* TO 'app_prod'@'10.0.0.10';

-- Nạp lại bảng phân quyền
FLUSH PRIVILEGES;

-- Kiểm tra lại danh sách người dùng
SELECT user, host FROM mysql.user WHERE user = 'app_prod';

Kết quả trả về hiển thị rõ:

text
+----------+-----------+
| user     | host      |
+----------+-----------+
| app_prod | 10.0.0.10 |
+----------+-----------+

Bước 5: Đo kiểm độ trễ và băng thông mạng nội bộ

Bước kiểm tra này giúp bạn xác định chất lượng đường truyền nội bộ trước khi đưa hệ thống vào phục vụ tải thực tế. Từ máy chủ Web-01, bạn thực hiện lần lượt 3 bước đo kiểm:

1. Đo độ trễ qua ICMP ping

Chạy 100 gói tin ping với tần suất nhanh để kiểm tra độ ổn định của switch mạng ảo:

bash
ping -c 100 -i 0.2 10.0.0.20

Quan sát kết quả ở dòng cuối cùng:

text
100 packets transmitted, 100 received, 0% packet loss, time 20184ms
rtt min/avg/max/mdev = 0.312/0.458/0.782/0.068 ms

Tiêu chuẩn nghiệm thu tham chiếu:

  • Độ trễ trung bình (avg): Thông thường nên duy trì dưới 1.0ms (mức 0.3ms – 0.6ms là rất lý tưởng trong cùng một Datacenter). Nếu độ trễ thường xuyên vượt trên 1.5ms – 2.0ms, bạn nên kiểm tra lại tình trạng nghẽn trên hạ tầng ảo hóa.
  • Tỷ lệ rớt gói (packet loss): Cần đạt 0.0% trong mạng nội bộ.
  • Độ lệch chuẩn (mdev): Nên giữ dưới 0.1ms – 0.2ms để hạn chế hiện tượng giật (jitter).

2. Đo băng thông qua iperf3

Khi chạy sao lưu cơ sở dữ liệu (mysqldump) hoặc tải các bảng dữ liệu lớn, băng thông mạng nội bộ ảnh hưởng trực tiếp đến thời gian hoàn thành tác vụ.

Cài đặt công cụ trên cả hai máy chủ:

bash
sudo apt install -y iperf3

Trên máy chủ DB-01, khởi chạy iperf3 ở chế độ máy chủ lắng nghe trên IP nội bộ:

bash
iperf3 -s -B 10.0.0.20

(Lưu ý tạm thời mở cổng 5201 trên UFW của DB-01 cho 10.0.0.10 nếu cần đo kiểm: sudo ufw allow from 10.0.0.10 to any port 5201 proto tcp).

Trên máy chủ Web-01, chạy lệnh kiểm tra băng thông với 4 luồng song song:

bash
iperf3 -c 10.0.0.20 -P 4

Kết quả mong đợi:

text
[SUM]   0.00-10.00  sec  1.10 GBytes   944 Mbits/sec                  receiver

Băng thông đo được xấp xỉ 940 Mbps cho thấy card mạng nội bộ đang hoạt động đúng với tốc độ thiết kế 1 Gbps.

3. Kiểm tra kết nối TCP và truy vấn SQL thực tế

Từ Web-01, kiểm tra khả năng bắt tay qua cổng TCP:

bash
nc -zv 10.0.0.20 3306

Kết quả hiển thị: Connection to 10.0.0.20 3306 port [tcp/mysql] succeeded!.

Tiếp tục thực hiện một truy vấn SQL thực tế từ dòng lệnh của Web-01:

bash
mysql -h 10.0.0.20 -u app_prod -p'MatKhauPhucTapItNhat32KyTuRanDom123!' production_db -e "SELECT @@hostname AS db_host, NOW() AS server_time;"

Khi câu lệnh trả về đúng tên máy chủ cơ sở dữ liệu và thời gian hiện tại, bạn có thể yên tâm rằng việc xác thực tài khoản và định tuyến mạng nội bộ đã sẵn sàng.

Bước 6: Tinh chỉnh tham số mạng Linux tránh treo kết nối

Khi Web Server và Database Server duy trì nhiều kết nối TCP đồng thời, thiết bị chuyển mạch ảo (vSwitch) của nhà cung cấp hạ tầng có thể tự động ngắt các kết nối rảnh rỗi (idle connection) mà không gửi cờ RST. Tình trạng này dễ khiến ứng dụng bị treo khi cố gắng tái sử dụng các kết nối đã đứt trong connection pool.

Để hạn chế rủi ro này, bạn nên cấu hình lại tham số TCP keepalive và bộ đệm mạng trên cả hai máy chủ:

Mở tệp cấu hình sysctl:

bash
sudo nano /etc/sysctl.d/99-network-tuning.conf

Thêm các tham số sau:

ini
# Rút ngắn thời gian gửi gói tin TCP Keepalive thăm dò (mặc định 7200s là quá lâu)
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 5

# Tăng hàng đợi kết nối mạng chờ xử lý
net.core.somaxconn = 4096

# Tăng kích thước bộ đệm nhận và gửi TCP cho mạng tốc độ cao
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

Áp dụng cấu hình ngay mà không cần khởi động lại máy chủ:

bash
sudo sysctl --system

Bảng kiểm tra nghiệm thu và phương án rollback

Trước khi chỉnh sửa tệp môi trường .env của ứng dụng chính thức, bạn nên soát lại toàn bộ tiêu chuẩn qua bảng kiểm tra dưới đây:

Hạng mục kiểm traLệnh xác minhKết quả đạt yêu cầuRủi ro nếu không đạt
Card mạng nội bộip -br a show eth1Hiển thị đúng IP 10.0.0.20/24Mất liên lạc mạng nội bộ
MySQL Bind Addressss -tulpn \| grep 3306Chỉ lắng nghe trên 10.0.0.20:3306Bị quét cổng từ ngoài Internet
Tường lửa UFWufw statusChặn mặc định, chỉ mở 3306 cho 10.0.0.10Bị tấn công leo thang đặc quyền
Phân quyền người dùngSELECT host FROM mysql.userChỉ gán duy nhất 10.0.0.10Lộ tài khoản nếu mật khẩu yếu
Độ trễ trung bình Pingping -c 50 10.0.0.20Độ trễ RTT ≤ 0.8msTTFB của website bị tăng cao
Bỏ qua DNS LookupTrong my.cnfĐã bật skip-name-resolveKết nối bị nghẽn vài giây

Chuyển đổi ứng dụng và phương án rollback

Sau khi các mục kiểm tra đều đạt yêu cầu, bạn tiến hành chuyển đổi tệp cấu hình trên Web Server:

ini
# Tệp .env cũ
# DB_HOST=127.0.0.1

# Cấu hình mới trỏ sang VPS Database chuyên dụng
DB_CONNECTION=mysql
DB_HOST=10.0.0.20
DB_PORT=3306
DB_DATABASE=production_db
DB_USERNAME=app_prod
DB_PASSWORD=MatKhauPhucTapItNhat32KyTuRanDom123!

Khởi động lại ứng dụng web (hoặc PHP-FPM / Docker) và theo dõi sát nhật ký lỗi error.log.

Phương án Rollback: Nếu trong vòng 15 phút đầu tiên sau khi chuyển đổi, bạn nhận thấy website phản hồi chậm bất thường hoặc phát sinh lỗi kết nối cơ sở dữ liệu chưa rõ nguyên nhân, hãy thực hiện rollback theo thứ tự sau:

  1. Mở tệp .env trên Web Server và đổi lại DB_HOST=127.0.0.1.
  2. Khởi động lại ứng dụng web.
  3. Khởi động lại dịch vụ MySQL cục bộ cũ trên Web Server.

Thao tác này đưa hệ thống quay lại trạng thái Single-VPS ban đầu một cách an toàn mà không làm gián đoạn dịch vụ của người dùng.

Lộ trình triển khai tiếp theo

Sau khi đã tách biệt cơ sở dữ liệu sang máy chủ riêng an toàn, bước tiếp theo trong lộ trình mở rộng quy mô là đưa máy chủ Web về mô hình phi trạng thái (stateless). Bạn có thể tham khảo bài viết so sánh giải pháp lưu trữ tệp tải lên giữa NFS, MinIO và S3 Object Storage để chuẩn bị phương án lưu trữ tập trung, trước khi đưa bộ cân bằng tải Nginx vào điều phối lưu lượng cho nhiều Web Server song song.

Nội dung hướng dẫn này có hữu ích với hệ thống của bạn không?

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