安装 MySQL 只要一条命令。真正的工作在后面:给应用的用户、一种不把 3306 端口暴露在互联网上就能从自己电脑访问数据库的方法、适合小服务器的内存设置,以及不用你操心就能自动运行的备份。本指南在 Ubuntu 24.04 上把这四件事都讲清楚。每一步都在我们的 Ubuntu 24.04 镜像上执行过,下面的数字都来自那台服务器。
用有 sudo 权限的用户执行命令。Ubuntu 配置指南会创建一个。
1. 安装
sudo apt update
sudo apt install -y mysql-server
mysql --version
在我们的服务器上,安装用了 51 秒,装上的是 MySQL 8.0.46。它会立即启动,每次开机自动启动,并且只在服务器本机上监听:普通连接是 127.0.0.1:3306,MySQL 较新的 X 协议是 127.0.0.1:33060。此时外部还什么都访问不到。
2. 创建数据库和用户
在 Ubuntu 上,MySQL 的 root 账户使用套接字认证,所以 sudo mysql 不用密码就能登录。为你的应用创建数据库和用户:
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;
按应用的连接方式测试一下:
mysql -u app -p app -e "SELECT CURRENT_USER();"
应该输出 app@localhost。密码错误会得到 ERROR 1045 (28000): Access denied for user 'app'@'localhost'。这个用户在 app 里可以做任何事,在它之外什么都不能做。
3. 从你的电脑连接:SSH 隧道
要在自己的电脑上用 DBeaver、MySQL Workbench 或 mysql 命令行这类桌面客户端,也不要开放端口。通过 SSH 转发一个:
ssh -L 3307:127.0.0.1:3306 deploy@YOUR.SERVER.IP
NAT 套餐要加上 -p 和控制面板里的专属 SSH 端口。保持这个窗口打开,把客户端指向主机 127.0.0.1、端口 3307、用户 app。本地一侧用 3307,是为了不和你电脑上可能运行的 MySQL 冲突。在我们的测试中,服务器通过隧道立刻响应,而直接连接它地址上的 3306 则被拒绝。
4. 给另一台服务器直接访问
有时应用运行在第二台服务器上,必须直接连接数据库。这时数据库需要一个带独立 IPv4 的套餐,因为 NAT 套餐只转发你的 SSH 端口。共三处修改,都只限于应用服务器的地址(这里是 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';
如果 ufw 还没启用,先允许 SSH(sudo ufw allow OpenSSH),再运行 sudo ufw enable。详细内容见 ufw 指南。
我们分别检查了两道锁。有防火墙规则但没有对应的 MySQL 用户时,服务器以 error 1130: Host '…' is not allowed to connect to this MySQL server 拒绝。加上用户后,连接成功。去掉防火墙规则后,连接直接超时。互联网上的其他任何地址都会遇到同样的超时。
5. 更省内存
空闲且没有自己的数据时,MySQL 8.0 在我们的服务器上用了 383 MB。其中大部分是 Performance Schema,一个预先占用内存的诊断功能。在小 VPS 上把它关掉,并自己设定主缓存的大小:
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
重启后它只用了 165 MB。buffer pool 用来缓存数据和索引,对同时运行应用的 2 GB 服务器来说,256 MB 比较合适。如果数据库是服务器上的主要负载、而且已经比缓存还大,就把它调大。max_connections = 50 对一个使用连接池的应用来说绰绰有余。你会失去 performance_schema 的统计数据;如果哪天需要深入排查慢查询,再把它打开。
6. 每晚备份
mysqldump --single-transaction 能在不锁住应用的情况下,得到 InnoDB 表的一致性副本。把它放进一个小脚本:
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
每一行都有它的道理:
umask 077让转储文件只有 root 能读(-rw-------),因为里面是你的全部数据。pipefail让mysqldump失败时整个脚本也失败。没有它,gzip会写出一个空空的小压缩包并报告成功。我们故意弄坏了命令,脚本果然以代码 2 退出。find … -mtime +14 -delete保留两周的副本。- 脚本以 root 运行,所以
mysqldump通过套接字登录,不需要把密码写进任何文件。
从没恢复过的备份还不算数。把它恢复到一个临时数据库里看看数据:
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"
在我们的测试中,恢复出来的表和原表的行完全一样。同一块磁盘上的副本在你失去服务器时帮不上忙,所以时不时用 scp 或 restic 把它们拉到另一台机器上。Managed Backups 还会额外提供整台服务器的每日恢复点。
选哪个套餐
Micro(2 vCPU、2 GB、25 GB,$5/月)可以承载按上面调好的 MySQL 加一个网页应用。如果数据库本身超过几个 GB,Small(4 GB、35 GB,$8/月)能让你给 buffer pool 1 GB 或更多。两者都是 NAT 套餐,第 3 步的 SSH 隧道照样可用。第 4 步需要独立 IPv4:Micro-IP 为 $10/月。
更喜欢 PostgreSQL?PostgreSQL 指南按同样的思路编写。所有套餐都在 VPS 里,支付方式为 Base、Ethereum 或 Polygon 网络上的 USDT、USDC 或 ETH。
评论
暂无评论。来做第一个吧。