Cài MySQL chỉ mất một lệnh. Phần lớn công việc đến sau: người dùng cho ứng dụng, cách vào cơ sở dữ liệu từ máy tính của bạn mà không đưa cổng 3306 ra internet, thiết lập bộ nhớ cho máy chủ nhỏ, và bản sao lưu tự chạy không cần bạn. Hướng dẫn này đề cập cả bốn trên Ubuntu 24.04. Mọi bước đều chạy trên ảnh Ubuntu 24.04 của chúng tôi, và các con số dưới đây lấy từ chính máy chủ đó.
Chạy các lệnh bằng người dùng có sudo. Hướng dẫn thiết lập Ubuntu tạo sẵn một người.
1. Cài đặt
sudo apt update
sudo apt install -y mysql-server
mysql --version
Trên máy chủ của chúng tôi, việc cài mất 51 giây và cho MySQL 8.0.46. Nó khởi động ngay, khởi động lại mỗi lần boot và chỉ lắng nghe trên chính máy chủ: 127.0.0.1:3306 cho kết nối thường và 127.0.0.1:33060 cho giao thức X mới hơn của MySQL. Lúc này từ bên ngoài chưa vào được gì.
2. Tạo cơ sở dữ liệu và người dùng
Trên Ubuntu, tài khoản root của MySQL dùng xác thực qua socket, nên sudo mysql cho bạn vào mà không cần mật khẩu. Tạo cơ sở dữ liệu và người dùng cho ứng dụng:
sudo mysql
CREATE DATABASE app CHARACTER SET utf8mb4;
CREATE USER 'app'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost';
EXIT;
Thử theo đúng cách ứng dụng sẽ kết nối:
mysql -u app -p app -e "SELECT CURRENT_USER();"
Kết quả phải là app@localhost. Sai mật khẩu sẽ nhận ERROR 1045 (28000): Access denied for user 'app'@'localhost'. Người dùng này làm được mọi thứ trong app và không làm được gì bên ngoài.
3. Kết nối từ máy tính của bạn: đường hầm SSH
Để dùng một client máy tính như DBeaver, MySQL Workbench hay dòng lệnh mysql trên máy của bạn, đừng mở cổng nào. Chuyển tiếp một cổng qua SSH:
ssh -L 3307:127.0.0.1:3306 deploy@YOUR.SERVER.IP
Với gói NAT, thêm -p và cổng SSH riêng trong bảng điều khiển. Trong lúc cửa sổ đó còn mở, trỏ client tới host 127.0.0.1, cổng 3307, người dùng app. Phía máy bạn chúng tôi dùng 3307 để không đụng với MySQL có thể đang chạy trên máy tính của bạn. Trong lần thử, máy chủ trả lời ngay qua đường hầm, còn kết nối trực tiếp tới địa chỉ của nó ở cổng 3306 thì bị từ chối.
4. Truy cập trực tiếp cho một máy chủ khác
Đôi khi ứng dụng chạy trên máy chủ thứ hai và phải kết nối trực tiếp. Khi đó cơ sở dữ liệu cần một gói có IPv4 riêng, vì gói NAT chỉ chuyển tiếp cổng SSH của bạn. Có ba thay đổi, tất cả giới hạn trong địa chỉ của máy chủ ứng dụng (ở đây là 203.0.113.20):
sudo sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
sudo systemctl restart mysql
sudo ufw allow from 203.0.113.20 to any port 3306 proto tcp
CREATE USER 'app'@'203.0.113.20' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'203.0.113.20';
Nếu ufw chưa bật, hãy cho phép SSH trước (sudo ufw allow OpenSSH) rồi chạy sudo ufw enable. Chi tiết có trong hướng dẫn ufw.
Chúng tôi kiểm tra riêng từng ổ khóa. Có quy tắc tường lửa nhưng không có người dùng MySQL tương ứng, máy chủ từ chối với error 1130: Host '…' is not allowed to connect to this MySQL server. Khi đã thêm người dùng, kết nối đi qua. Khi gỡ quy tắc tường lửa, kết nối chỉ đơn giản là hết thời gian chờ. Mọi địa chỉ khác trên internet đều gặp đúng tình trạng hết thời gian chờ đó.
5. Dùng ít RAM hơn
Lúc rảnh và chưa có dữ liệu riêng, MySQL 8.0 dùng 383 MB trên máy chủ của chúng tôi. Phần lớn là của Performance Schema, một tính năng chẩn đoán giữ sẵn bộ nhớ. Trên VPS nhỏ, hãy tắt nó và tự đặt kích thước bộ đệm chính:
sudo tee /etc/mysql/mysql.conf.d/zz-small-vps.cnf >/dev/null <<'EOF'
[mysqld]
performance_schema = OFF
innodb_buffer_pool_size = 256M
max_connections = 50
EOF
sudo systemctl restart mysql
ps -o rss= -C mysqld
Sau khi khởi động lại, nó dùng 165 MB. buffer pool lưu đệm dữ liệu và chỉ mục của bạn, và 256 MB hợp với máy chủ 2 GB còn chạy cả ứng dụng. Tăng nó nếu cơ sở dữ liệu là việc chính của máy chủ và đã lớn hơn bộ đệm. max_connections = 50 là dư dả cho một ứng dụng có connection pool. Bạn mất số liệu thống kê của performance_schema. Bật lại nếu có lúc cần soi kỹ các truy vấn chậm.
6. Sao lưu mỗi đêm
mysqldump --single-transaction lấy một bản sao nhất quán của các bảng InnoDB mà không khóa ứng dụng. Đặt nó vào một script nhỏ:
sudo tee /usr/local/bin/mysql-backup >/dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
umask 077
mkdir -p /var/backups/mysql
mysqldump --single-transaction --routines --triggers app | gzip > /var/backups/mysql/app-$(date +%F).sql.gz
find /var/backups/mysql -name 'app-*.sql.gz' -mtime +14 -delete
EOF
sudo chmod 755 /usr/local/bin/mysql-backup
echo '0 3 * * * root /usr/local/bin/mysql-backup' | sudo tee /etc/cron.d/mysql-backup
sudo /usr/local/bin/mysql-backup && sudo ls -l /var/backups/mysql
Mỗi dòng đều có lý do:
umask 077khiến bản dump chỉ root đọc được (-rw-------), vì nó chứa toàn bộ dữ liệu của bạn.pipefailkhiến cả script thất bại nếumysqldumpthất bại. Không có nó,gzipsẽ ghi ra một tệp nén rỗng tí xíu và báo thành công. Chúng tôi cố ý làm hỏng lệnh, và script kết thúc với mã 2 đúng như mong đợi.find … -mtime +14 -deletegiữ bản sao của hai tuần.- Script chạy bằng root, nên
mysqldumpđăng nhập qua socket và không có mật khẩu nào nằm trong tệp.
Bản sao lưu bạn chưa từng khôi phục thì chưa tính. Hãy khôi phục vào một cơ sở dữ liệu tạm và xem dữ liệu:
sudo mysql -e "CREATE DATABASE app_restore"
gunzip -c /var/backups/mysql/app-2026-10-25.sql.gz | sudo mysql app_restore
sudo mysql -e "SHOW TABLES FROM app_restore"
sudo mysql -e "DROP DATABASE app_restore"
Trong lần thử, bảng được khôi phục có đúng các hàng như bản gốc. Bản sao trên cùng ổ đĩa không bảo vệ bạn nếu mất máy chủ, nên thỉnh thoảng hãy chuyển chúng sang máy khác bằng scp hoặc restic. Managed Backups còn thêm các điểm khôi phục hằng ngày của toàn bộ máy chủ.
Chọn gói nào
Micro (2 vCPU, 2 GB, 25 GB, $5/tháng) chứa được MySQL chỉnh như trên cùng một ứng dụng web. Nếu bản thân cơ sở dữ liệu vượt quá vài gigabyte, Small với 4 GB và 35 GB giá $8/tháng cho phép bạn cấp cho buffer pool 1 GB hoặc hơn. Cả hai đều là gói NAT, và đường hầm SSH ở bước 3 dùng được trên chúng. Bước 4 cần IPv4 riêng: Micro-IP giá $10/tháng.
Thích PostgreSQL hơn? Hướng dẫn PostgreSQL đi theo cùng kế hoạch. Mọi gói đều có ở VPS, và thanh toán bằng USDT, USDC hoặc ETH trên Base, Ethereum hoặc Polygon.
Bình luận
Chưa có bình luận nào. Hãy là người đầu tiên.