版本: v1.1.0 | 更新日期: 2024年11月
🆕 版本更新说明
v1.1.0 (2024-11-06)
- ✅ 安全改进:仅在提供远程用户参数时才启用远程访问
- ✅ 更清晰的提示:明确告知用户是否启用远程访问功能
- ✅ 问题修复:解决用户遇到的 "Host is not allowed to connect" 错误
- ✅ 文档增强:新增常见问题解答和故障排除指南
v1.0.0 (初始版本)
- 一键安装 MariaDB
- 自动配置安全选项
- 可选的远程访问配置
📋 目录
简介
MariaDB 是 MySQL 的一个开源分支,由 MySQL 原始开发者创建,完全兼容 MySQL,并提供了更好的性能和更多的功能。本指南提供了一个一键安装脚本,可以快速在 Debian/Ubuntu 系统上部署 MariaDB 数据库服务。
为什么选择 MariaDB?
- ✅ 完全开源:真正的开源项目,社区活跃
- ✅ 高性能:相比 MySQL 有更好的性能优化
- ✅ 完全兼容:与 MySQL 命令和语法完全兼容
- ✅ 功能丰富:提供更多存储引擎和功能
- ✅ 积极维护:更新频繁,安全补丁及时
功能特性
本安装脚本提供以下功能:
🚀 一键安装
- 自动安装 MariaDB Server 和 Client
- 自动配置系统服务
- 自动设置开机自启动
🔐 安全配置
- 设置强密码策略
- 删除匿名用户
- 删除测试数据库
- 密码强度验证
🌐 远程访问
- 配置远程访问权限
- 创建远程管理用户
- 自动配置防火墙规则
✅ 自动验证
- 验证服务运行状态
- 测试数据库连接
- 检查端口监听
- 显示详细配置信息
🎨 友好界面
- 彩色输出,清晰易读
- 实时进度显示
- 详细的错误提示
- 完整的安装摘要
系统要求
操作系统
- Debian 10/11/12
- Ubuntu 18.04/20.04/22.04/24.04
- 其他基于 Debian 的发行版
硬件要求
- 最低配置:1 核 CPU,512 MB RAM,5 GB 硬盘
- 推荐配置:2 核 CPU,2 GB RAM,20 GB 硬盘
软件要求
- Python 3.6 或更高版本
- root 或 sudo 权限
- 网络连接(用于下载软件包)
快速开始
方法一:仅设置 root 密码
# 下载脚本
wget https://your-url/install_mariadb.py
# 或者直接创建脚本文件(参见文末完整脚本)
# 添加执行权限
chmod +x install_mariadb.py
# 运行安装(仅设置 root 密码)
sudo python3 install_mariadb.py "MyRootPass123!"
方法二:设置 root 和远程用户
# 运行安装(设置 root 密码和远程访问用户)
sudo python3 install_mariadb.py "MyRootPass123!" "appuser" "AppUserPass123!"
方法三:使用默认远程用户名
# 默认创建名为 appuser 的远程用户,密码与 root 相同
sudo python3 install_mariadb.py "MyRootPass123!" "appuser"
详细使用说明
命令格式
sudo python3 install_mariadb.py <root密码> [远程用户名] [远程用户密码]
参数说明
| 参数 | 必需 | 说明 | 示例 |
|---|---|---|---|
| root密码 | ✅ 是 | MariaDB root 用户的密码 | MyRootPass123! |
| 远程用户名 | ❌ 否 | 远程访问的用户名(默认:appuser) | appuser |
| 远程用户密码 | ❌ 否 | 远程用户的密码(默认:与 root 密码相同) | AppUserPass123! |
密码强度要求
为了保证数据库安全,建议密码满足以下条件:
- ✅ 长度至少 8 位
- ✅ 包含大写字母
- ✅ 包含小写字母
- ✅ 包含数字
- ✅ 包含特殊字符(如 !@#$%^&*)
示例强密码:
MyDatabase@2024Secure#Pass123MariaDB$trongPwd!
安装步骤详解
脚本会自动执行以下步骤:
步骤 1:更新系统软件包
apt update
更新软件包列表,确保安装最新版本的 MariaDB。
步骤 2:安装 MariaDB
apt install -y mariadb-server mariadb-client
安装 MariaDB 服务器和客户端程序。
步骤 3:启动服务
systemctl start mariadb
systemctl enable mariadb
启动 MariaDB 服务并设置开机自启动。
步骤 4:配置 root 密码
执行以下安全配置:
- 设置 root 用户密码
- 删除匿名用户
- 禁用 root 远程登录(仅允许本地)
- 删除测试数据库
- 刷新权限
步骤 5:创建远程访问用户(可选)
如果提供了远程用户信息,脚本会:
- 创建新用户
- 授予所有权限
- 允许从任何主机连接
步骤 6:配置远程访问
修改配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf:
- 将
bind-address从127.0.0.1改为0.0.0.0 - 允许外部网络访问
步骤 7:配置防火墙
如果系统安装了 UFW 防火墙:
ufw allow 3306/tcp
步骤 8:重启服务
systemctl restart mariadb
使配置生效。
步骤 9:验证安装
验证以下内容:
- ✅ 服务运行状态
- ✅ 端口监听(3306)
- ✅ root 用户登录
- ✅ 远程用户配置
配置说明
主要配置文件
| 文件路径 | 说明 |
|---|---|
/etc/mysql/mariadb.conf.d/50-server.cnf | MariaDB 服务器配置文件 |
/etc/mysql/mariadb.conf.d/50-client.cnf | 客户端配置文件 |
/etc/mysql/my.cnf | 主配置文件 |
重要目录
| 目录路径 | 说明 |
|---|---|
/var/lib/mysql/ | 数据库数据存储目录 |
/var/log/mysql/ | 日志文件目录 |
/var/run/mysqld/ | 运行时文件(如 socket 文件) |
连接方式
本地连接
# 使用 root 用户连接
mysql -u root -p
# 连接后输入密码
远程连接
# 从其他机器连接
mysql -h <服务器IP> -u appuser -p
# 示例
mysql -h 192.168.1.100 -u appuser -p
应用程序连接
Python(PyMySQL):
import pymysql
connection = pymysql.connect(
host='服务器IP',
user='appuser',
password='AppUserPass123!',
database='your_database',
charset='utf8mb4'
)
Java(JDBC):
String url = "jdbc:mariadb://服务器IP:3306/your_database";
String user = "appuser";
String password = "AppUserPass123!";
Connection conn = DriverManager.getConnection(url, user, password);
Node.js(mysql2):
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: '服务器IP',
user: 'appuser',
password: 'AppUserPass123!',
database: 'your_database'
});
PHP(MySQLi):
$conn = new mysqli("服务器IP", "appuser", "AppUserPass123!", "your_database");
常见问题
1. 远程连接错误:"Host 'xxx' is not allowed to connect"
问题:执行脚本后,使用客户端远程连接数据库时报错:
null, message from server: "Host '121.225.142.53' is not allowed to connect to this MariaDB server"
原因分析:
- 您在运行脚本时只提供了 root 密码,没有创建远程访问用户
- root 用户被脚本限制为仅本地访问(安全考虑)
- 没有指定远程用户参数时,脚本不会配置远程访问功能
解决方案:
方案 A:创建远程访问用户(推荐)
# 登录服务器,执行以下命令
mysql -u root -p
-- 创建远程用户
CREATE USER 'appuser'@'%' IDENTIFIED BY 'YourPassword123!';
-- 授予权限
GRANT ALL PRIVILEGES ON *.* TO 'appuser'@'%' WITH GRANT OPTION;
-- 刷新权限
FLUSH PRIVILEGES;
-- 退出
EXIT;
然后使用 appuser 连接:
mysql -h 服务器IP -u appuser -p
方案 B:重新运行脚本(推荐)
# 使用完整参数重新配置
sudo python3 install_mariadb.py "YourRootPassword" "appuser" "YourUserPassword"
脚本检测到已安装会询问是否继续配置,输入 y 即可。
重要提示:
- ⚠️ 从 1.1.0 版本开始,脚本必须提供远程用户名参数才会启用远程访问
- ✅ 这样的设计更安全,避免无意中暴露数据库给外网
- ✅ 使用专用远程用户而非 root 用户是最佳实践
2. 安装失败:权限不足
问题:执行脚本时提示权限错误
解决方案:
# 确保使用 sudo 运行
sudo python3 install_mariadb.py "YourPassword123!"
2. 需要配置 bind-address 才能远程连接
重要说明:如果您只运行了 sudo python3 install_mariadb.py "密码",脚本会:
- ✅ 配置 root 用户(仅本地访问)
- ❌ 不会配置远程访问
- ❌ 不会修改 bind-address
- ❌ 不会创建远程用户
要启用远程访问,必须提供远程用户参数:
sudo python3 install_mariadb.py "RootPass123!" "appuser" "UserPass123!"
3. 端口被占用
问题:3306 端口已被其他服务占用
解决方案:
# 查看占用端口的进程
sudo netstat -tulpn | grep 3306
# 或
sudo ss -tulpn | grep 3306
# 停止占用的服务
sudo systemctl stop mysql # 如果是 MySQL
4. 远程连接失败(进阶排查)
问题:已创建远程用户,但仍无法从远程主机连接到 MariaDB
可能原因和解决方案:
原因 1:防火墙阻止
# 检查防火墙状态
sudo ufw status
# 允许 3306 端口
sudo ufw allow 3306/tcp
# 或允许特定 IP
sudo ufw allow from 192.168.1.0/24 to any port 3306
原因 2:bind-address 配置错误
# 检查配置
sudo cat /etc/mysql/mariadb.conf.d/50-server.cnf | grep bind-address
# 应该显示:bind-address = 0.0.0.0
# 如果不是,手动修改后重启
sudo systemctl restart mariadb
原因 3:用户权限不足
# 登录 MariaDB
mysql -u root -p
# 检查用户权限
SELECT User, Host FROM mysql.user;
# 如果没有 '%' 的 Host,需要创建
CREATE USER 'appuser'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'appuser'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
原因 4:云服务器安全组未开放
如果使用云服务器(阿里云、腾讯云、AWS 等),需要在控制台的安全组中开放 3306 端口。
5. 忘记 root 密码
解决方案:
# 1. 停止 MariaDB 服务
sudo systemctl stop mariadb
# 2. 以安全模式启动(跳过权限检查)
sudo mysqld_safe --skip-grant-tables &
# 3. 登录(无需密码)
mysql -u root
# 4. 重置密码
USE mysql;
UPDATE user SET password=PASSWORD('新密码') WHERE User='root';
FLUSH PRIVILEGES;
EXIT;
# 5. 停止安全模式进程
sudo killall mysqld_safe
sudo killall mysqld
# 6. 正常启动服务
sudo systemctl start mariadb
6. 服务无法启动
解决方案:
# 查看服务状态
sudo systemctl status mariadb
# 查看错误日志
sudo tail -f /var/log/mysql/error.log
# 检查配置文件语法
sudo mysqld --help --verbose
# 常见问题:磁盘空间不足
df -h
# 常见问题:配置文件错误
sudo cp /etc/mysql/mariadb.conf.d/50-server.cnf.backup /etc/mysql/mariadb.conf.d/50-server.cnf
7. 中文乱码问题
解决方案:
编辑配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf:
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
重启服务:
sudo systemctl restart mariadb
安全建议
1. 限制远程访问 IP
不要将数据库暴露给整个互联网,只允许特定 IP 访问:
# 删除所有 IP 的访问规则
sudo ufw delete allow 3306/tcp
# 只允许特定 IP 访问
sudo ufw allow from 192.168.1.100 to any port 3306
# 允许 IP 段访问
sudo ufw allow from 192.168.1.0/24 to any port 3306
2. 定期更新密码
# 登录 MariaDB
mysql -u root -p
# 修改密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
FLUSH PRIVILEGES;
3. 最小权限原则
不要给所有用户 ALL PRIVILEGES,根据需要分配权限:
-- 创建只读用户
CREATE USER 'readonly'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON database_name.* TO 'readonly'@'%';
-- 创建特定数据库的管理员
CREATE USER 'dbadmin'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON specific_db.* TO 'dbadmin'@'%';
FLUSH PRIVILEGES;
4. 启用 SSL/TLS 加密连接
# 检查 SSL 是否启用
mysql -u root -p -e "SHOW VARIABLES LIKE '%ssl%';"
# 如果未启用,编辑配置文件
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
# 添加以下内容
[mysqld]
ssl-ca=/etc/mysql/ssl/ca-cert.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem
5. 定期备份数据库
# 备份所有数据库
sudo mysqldump -u root -p --all-databases > backup_$(date +%Y%m%d).sql
# 备份特定数据库
sudo mysqldump -u root -p database_name > database_backup.sql
# 自动备份脚本(添加到 crontab)
# 每天凌晨 2 点备份
0 2 * * * /usr/bin/mysqldump -u root -p'密码' --all-databases | gzip > /backup/mysql_$(date +\%Y\%m\%d).sql.gz
6. 监控和日志
# 启用慢查询日志
[mysqld]
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow-query.log
long_query_time=2
# 查看日志
sudo tail -f /var/log/mysql/error.log
sudo tail -f /var/log/mysql/slow-query.log
7. 禁用不必要的功能
-- 禁用 LOCAL INFILE(防止本地文件读取漏洞)
[mysqld]
local-infile=0
-- 禁用远程 root 登录(如果不需要)
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
FLUSH PRIVILEGES;
服务管理
基本命令
# 启动服务
sudo systemctl start mariadb
# 停止服务
sudo systemctl stop mariadb
# 重启服务
sudo systemctl restart mariadb
# 重新加载配置(无需重启)
sudo systemctl reload mariadb
# 查看服务状态
sudo systemctl status mariadb
# 启用开机自启动
sudo systemctl enable mariadb
# 禁用开机自启动
sudo systemctl disable mariadb
# 查看是否开机自启动
sudo systemctl is-enabled mariadb
查看运行信息
# 查看进程
ps aux | grep mysql
# 查看监听端口
sudo netstat -tulpn | grep 3306
sudo ss -tulpn | grep 3306
# 查看连接数
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"
# 查看数据库列表
mysql -u root -p -e "SHOW DATABASES;"
# 查看用户列表
mysql -u root -p -e "SELECT User, Host FROM mysql.user;"
性能优化
编辑 /etc/mysql/mariadb.conf.d/50-server.cnf:
[mysqld]
# 基本优化
max_connections=200
thread_cache_size=100
table_open_cache=2000
# InnoDB 优化(根据可用内存调整)
innodb_buffer_pool_size=1G # 建议设置为可用内存的 50-70%
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT
# 查询缓存(MariaDB 10.3+)
query_cache_type=1
query_cache_size=64M
query_cache_limit=2M
# 临时表
tmp_table_size=64M
max_heap_table_size=64M
# 日志
slow_query_log=1
long_query_time=2
故障排除
诊断命令
# 1. 检查服务状态
sudo systemctl status mariadb
# 2. 查看错误日志
sudo tail -100 /var/log/mysql/error.log
# 3. 检查端口监听
sudo ss -tulpn | grep 3306
# 4. 测试连接
mysql -u root -p -e "SELECT 1;"
# 5. 检查磁盘空间
df -h
# 6. 检查进程
ps aux | grep mysql
# 7. 检查配置文件语法
sudo mysqld --help --verbose | grep -A 1 'Default options'
常见错误及解决方案
错误 1:Can't connect to local MySQL server through socket
# 检查 socket 文件
ls -la /var/run/mysqld/mysqld.sock
# 如果不存在,服务可能未启动
sudo systemctl start mariadb
# 检查配置文件中的 socket 路径
cat /etc/mysql/mariadb.conf.d/50-server.cnf | grep socket
错误 2:Access denied for user
# 确认用户名和密码正确
# 检查用户权限
mysql -u root -p -e "SELECT User, Host FROM mysql.user;"
# 重新授权
GRANT ALL PRIVILEGES ON *.* TO 'username'@'host' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;
错误 3:Too many connections
# 临时增加连接数
mysql -u root -p -e "SET GLOBAL max_connections=500;"
# 永久修改:编辑配置文件
[mysqld]
max_connections=500
# 重启服务
sudo systemctl restart mariadb
错误 4:Table is marked as crashed
# 修复表
mysql -u root -p
USE database_name;
REPAIR TABLE table_name;
# 或使用 mysqlcheck
mysqlcheck -u root -p --auto-repair --all-databases
完全卸载重装
如果问题无法解决,可以完全卸载后重新安装:
# 1. 停止服务
sudo systemctl stop mariadb
# 2. 卸载软件包
sudo apt remove --purge mariadb-server mariadb-client -y
# 3. 删除数据和配置(注意:会丢失所有数据)
sudo rm -rf /var/lib/mysql
sudo rm -rf /etc/mysql
sudo rm -rf /var/log/mysql
# 4. 清理残留
sudo apt autoremove -y
sudo apt autoclean
# 5. 重新安装
sudo python3 install_mariadb.py "YourPassword123!"
性能监控
使用 MySQL 命令监控
-- 查看当前连接
SHOW PROCESSLIST;
-- 查看状态变量
SHOW STATUS;
SHOW STATUS LIKE 'Threads%';
SHOW STATUS LIKE 'Connections';
-- 查看系统变量
SHOW VARIABLES;
SHOW VARIABLES LIKE 'max_connections';
-- 查看表状态
SHOW TABLE STATUS FROM database_name;
-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS\G
使用 mytop 监控
# 安装 mytop
sudo apt install mytop -y
# 运行监控
mytop -u root -p
使用 mysqltuner
# 下载并运行
wget http://mysqltuner.pl/ -O mysqltuner.pl
chmod +x mysqltuner.pl
sudo ./mysqltuner.pl --user root --pass '密码'
数据库操作示例
创建数据库和用户
-- 创建数据库
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建用户
CREATE USER 'myapp_user'@'%' IDENTIFIED BY 'SecurePass123!';
-- 授权
GRANT ALL PRIVILEGES ON myapp.* TO 'myapp_user'@'%';
FLUSH PRIVILEGES;
-- 验证
SHOW GRANTS FOR 'myapp_user'@'%';
导入和导出数据
# 导出数据库
mysqldump -u root -p database_name > backup.sql
# 导出数据库结构(不含数据)
mysqldump -u root -p --no-data database_name > structure.sql
# 导出特定表
mysqldump -u root -p database_name table_name > table_backup.sql
# 导入数据库
mysql -u root -p database_name < backup.sql
# 或在 MySQL 中导入
mysql -u root -p
USE database_name;
SOURCE /path/to/backup.sql;
升级 MariaDB
# 1. 备份数据
sudo mysqldump -u root -p --all-databases > backup_before_upgrade.sql
# 2. 查看当前版本
mysql --version
# 3. 更新软件包列表
sudo apt update
# 4. 升级 MariaDB
sudo apt upgrade mariadb-server mariadb-client
# 5. 运行升级脚本
sudo mysql_upgrade -u root -p
# 6. 重启服务
sudo systemctl restart mariadb
卸载说明
如果需要卸载 MariaDB:
# 1. 备份数据(重要!)
sudo mysqldump -u root -p --all-databases > final_backup.sql
# 2. 停止服务
sudo systemctl stop mariadb
# 3. 卸载软件包
sudo apt remove --purge mariadb-server mariadb-client -y
# 4. 删除数据目录(如果需要)
sudo rm -rf /var/lib/mysql
# 5. 删除配置文件(如果需要)
sudo rm -rf /etc/mysql
# 6. 清理
sudo apt autoremove -y
sudo apt autoclean
总结
本安装脚本提供了一个快速、安全、可靠的方式来部署 MariaDB 数据库服务。通过自动化安装和配置过程,您可以在几分钟内拥有一个生产就绪的数据库环境。
关键要点
- ✅ 使用强密码保护数据库
- ✅ 限制远程访问 IP 范围
- ✅ 定期备份数据库
- ✅ 监控数据库性能
- ✅ 及时更新安全补丁
- ✅ 遵循最小权限原则
相关资源
完整安装脚本
将以下脚本保存为 install_mariadb.py,然后按照上述说明运行。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MariaDB 一键安装脚本
使用方法:
sudo python3 install_mariadb.py <root密码> [远程用户名] [远程用户密码]
示例:
sudo python3 install_mariadb.py MyRootPass123! appuser AppUserPass123!
sudo python3 install_mariadb.py MyRootPass123! # 只设置 root 密码
"""
import os
import sys
import subprocess
import time
import re
# 颜色输出
class Colors:
GREEN = '\033[0;32m'
YELLOW = '\033[1;33m'
RED = '\033[0;31m'
BLUE = '\033[0;34m'
CYAN = '\033[0;36m'
NC = '\033[0m' # No Color
BOLD = '\033[1m'
def print_step(message):
"""打印步骤信息"""
print(f"\n{Colors.CYAN}{'='*60}{Colors.NC}")
print(f"{Colors.GREEN}{Colors.BOLD}▶ {message}{Colors.NC}")
print(f"{Colors.CYAN}{'='*60}{Colors.NC}\n")
def print_success(message):
"""打印成功信息"""
print(f"{Colors.GREEN}✓ {message}{Colors.NC}")
def print_error(message):
"""打印错误信息"""
print(f"{Colors.RED}✗ {message}{Colors.NC}")
def print_warning(message):
"""打印警告信息"""
print(f"{Colors.YELLOW}⚠ {message}{Colors.NC}")
def print_info(message):
"""打印信息"""
print(f"{Colors.BLUE}ℹ {message}{Colors.NC}")
def run_command(command, show_output=True, check=True):
"""执行系统命令"""
try:
if show_output:
result = subprocess.run(command, shell=True, check=check,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
text=True, encoding='utf-8')
if result.stdout:
print(result.stdout)
if result.stderr and result.returncode != 0:
print_error(result.stderr)
return result.returncode == 0
else:
result = subprocess.run(command, shell=True, check=check,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return result.returncode == 0
except subprocess.CalledProcessError as e:
print_error(f"命令执行失败: {command}")
print_error(f"错误: {e}")
return False
def check_root():
"""检查是否为 root 用户"""
if os.geteuid() != 0:
print_error("此脚本需要 root 权限运行!")
print_info("请使用: sudo python3 install_mariadb.py <密码>")
sys.exit(1)
def validate_password(password):
"""验证密码强度"""
if len(password) < 8:
print_warning("警告: 密码长度少于 8 位,建议使用更强的密码")
return False
has_upper = bool(re.search(r'[A-Z]', password))
has_lower = bool(re.search(r'[a-z]', password))
has_digit = bool(re.search(r'\d', password))
has_special = bool(re.search(r'[!@#$%^&*(),.?":{}|<>]', password))
strength = sum([has_upper, has_lower, has_digit, has_special])
if strength < 3:
print_warning("警告: 密码强度较弱,建议包含大小写字母、数字和特殊字符")
return False
return True
def check_mariadb_installed():
"""检查 MariaDB 是否已安装"""
result = subprocess.run("which mysql", shell=True,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return result.returncode == 0
def install_mariadb():
"""安装 MariaDB"""
print_step("步骤 1: 更新系统软件包")
if not run_command("apt update"):
print_error("更新软件包列表失败!")
return False
print_success("软件包列表更新完成")
print_step("步骤 2: 安装 MariaDB")
print_info("正在安装 MariaDB Server 和 Client...")
# 设置非交互式安装
os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
if not run_command("apt install -y mariadb-server mariadb-client"):
print_error("MariaDB 安装失败!")
return False
print_success("MariaDB 安装完成")
# 查看安装版本
result = subprocess.run("mysql --version", shell=True,
capture_output=True, text=True)
if result.returncode == 0:
print_info(f"安装版本: {result.stdout.strip()}")
return True
def start_mariadb():
"""启动 MariaDB 服务"""
print_step("步骤 3: 启动 MariaDB 服务")
# 启动服务
if not run_command("systemctl start mariadb", show_output=False):
print_error("启动 MariaDB 失败!")
return False
print_success("MariaDB 服务已启动")
# 设置开机自启
if not run_command("systemctl enable mariadb", show_output=False):
print_warning("设置开机自启失败")
else:
print_success("已设置开机自启动")
# 等待服务完全启动
print_info("等待服务完全启动...")
time.sleep(2)
# 检查服务状态
result = subprocess.run("systemctl is-active mariadb", shell=True,
capture_output=True, text=True)
if result.stdout.strip() == "active":
print_success("MariaDB 服务运行正常")
return True
else:
print_error("MariaDB 服务未正常运行")
return False
def configure_root_password(password):
"""配置 root 密码"""
print_step("步骤 4: 配置 root 密码")
# 转义密码中的特殊字符
escaped_password = password.replace("'", "\\'").replace('"', '\\"')
sql_commands = f"""
ALTER USER 'root'@'localhost' IDENTIFIED BY '{escaped_password}';
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
"""
# 写入临时 SQL 文件
sql_file = "/tmp/mariadb_setup.sql"
with open(sql_file, 'w') as f:
f.write(sql_commands)
try:
if run_command(f"mysql < {sql_file}", show_output=False):
print_success("root 密码设置成功")
print_success("已删除匿名用户")
print_success("已删除测试数据库")
return True
else:
print_error("配置失败")
return False
finally:
# 删除临时文件
if os.path.exists(sql_file):
os.remove(sql_file)
def create_remote_user(root_password, username, user_password):
"""创建远程访问用户"""
print_step("步骤 5: 创建远程访问用户")
escaped_root_pass = root_password.replace("'", "\\'").replace('"', '\\"')
escaped_user_pass = user_password.replace("'", "\\'").replace('"', '\\"')
sql_commands = f"""
CREATE USER IF NOT EXISTS '{username}'@'%' IDENTIFIED BY '{escaped_user_pass}';
GRANT ALL PRIVILEGES ON *.* TO '{username}'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
"""
sql_file = "/tmp/create_user.sql"
with open(sql_file, 'w') as f:
f.write(sql_commands)
try:
if run_command(f"mysql -u root -p'{escaped_root_pass}' < {sql_file}", show_output=False):
print_success(f"远程用户 '{username}' 创建成功")
print_success(f"用户 '{username}' 已授予所有权限")
return True
else:
print_error("创建远程用户失败")
return False
finally:
if os.path.exists(sql_file):
os.remove(sql_file)
def configure_remote_access():
"""配置远程访问"""
print_step("步骤 6: 配置远程访问")
config_file = "/etc/mysql/mariadb.conf.d/50-server.cnf"
# 备份原配置文件
backup_file = f"{config_file}.backup"
if not os.path.exists(backup_file):
run_command(f"cp {config_file} {backup_file}", show_output=False)
print_info(f"已备份配置文件到: {backup_file}")
# 读取配置文件
with open(config_file, 'r') as f:
content = f.read()
# 修改 bind-address
if 'bind-address' in content:
# 注释掉原来的 bind-address
content = re.sub(r'^bind-address\s*=.*$', '# bind-address = 127.0.0.1',
content, flags=re.MULTILINE)
# 添加新的配置
if '[mysqld]' in content:
content = content.replace('[mysqld]',
'[mysqld]\n# 允许远程访问\nbind-address = 0.0.0.0')
print_success("已修改 bind-address 为 0.0.0.0")
else:
# 如果没有 bind-address,添加一个
if '[mysqld]' in content:
content = content.replace('[mysqld]',
'[mysqld]\nbind-address = 0.0.0.0')
print_success("已添加 bind-address = 0.0.0.0")
# 写回配置文件
with open(config_file, 'w') as f:
f.write(content)
print_success("远程访问配置完成")
return True
def configure_firewall():
"""配置防火墙"""
print_step("步骤 7: 配置防火墙")
# 检查 UFW 是否安装
result = subprocess.run("which ufw", shell=True,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if result.returncode == 0:
# UFW 已安装
print_info("检测到 UFW 防火墙")
# 检查 UFW 状态
result = subprocess.run("ufw status", shell=True,
capture_output=True, text=True)
if "inactive" in result.stdout.lower():
print_warning("UFW 防火墙未启用")
print_info("跳过防火墙配置(您可以稍后手动配置)")
else:
# 添加规则
if run_command("ufw allow 3306/tcp", show_output=False):
print_success("已添加防火墙规则:允许 3306 端口")
else:
print_warning("添加防火墙规则失败(可能已存在)")
else:
print_warning("未检测到 UFW 防火墙")
print_info("如果您使用其他防火墙,请手动开放 3306 端口")
return True
def restart_mariadb():
"""重启 MariaDB 服务"""
print_step("步骤 8: 重启 MariaDB 服务")
if run_command("systemctl restart mariadb", show_output=False):
print_success("MariaDB 服务重启成功")
time.sleep(2)
# 检查服务状态
result = subprocess.run("systemctl is-active mariadb", shell=True,
capture_output=True, text=True)
if result.stdout.strip() == "active":
print_success("服务运行正常")
return True
print_error("MariaDB 服务重启失败")
return False
def verify_installation(root_password, remote_user=None):
"""验证安装"""
print_step("步骤 9: 验证安装")
# 检查服务状态
result = subprocess.run("systemctl is-active mariadb", shell=True,
capture_output=True, text=True)
if result.stdout.strip() == "active":
print_success("✓ 服务运行正常")
else:
print_error("✗ 服务未运行")
return False
# 检查监听端口
result = subprocess.run("netstat -tulpn | grep 3306 || ss -tulpn | grep 3306",
shell=True, capture_output=True, text=True)
if "3306" in result.stdout:
if "0.0.0.0:3306" in result.stdout:
print_success("✓ 正在监听所有接口 (0.0.0.0:3306)")
else:
print_success("✓ 正在监听 3306 端口")
else:
print_warning("⚠ 未检测到 3306 端口监听")
# 测试 root 登录
escaped_password = root_password.replace("'", "\\'").replace('"', '\\"')
result = subprocess.run(f"mysql -u root -p'{escaped_password}' -e 'SELECT VERSION();'",
shell=True, capture_output=True, text=True)
if result.returncode == 0:
print_success("✓ root 用户登录成功")
version = result.stdout.strip().split('\n')[-1] if result.stdout else "未知"
print_info(f" MariaDB 版本: {version}")
else:
print_error("✗ root 用户登录失败")
return False
# 查看用户列表
if remote_user:
result = subprocess.run(
f"mysql -u root -p'{escaped_password}' -e \"SELECT User, Host FROM mysql.user WHERE User IN ('root', '{remote_user}');\"",
shell=True, capture_output=True, text=True)
if result.returncode == 0:
print_success(f"✓ 用户配置正确")
print(result.stdout)
return True
def print_summary(root_password, remote_user=None, remote_password=None):
"""打印安装摘要"""
print(f"\n{Colors.GREEN}{'='*60}{Colors.NC}")
print(f"{Colors.GREEN}{Colors.BOLD}{' 🎉 MariaDB 安装配置完成!':^60}{Colors.NC}")
print(f"{Colors.GREEN}{'='*60}{Colors.NC}\n")
# 获取服务器 IP
result = subprocess.run("hostname -I | awk '{print $1}'", shell=True,
capture_output=True, text=True)
server_ip = result.stdout.strip() if result.returncode == 0 else "服务器IP"
print(f"{Colors.BOLD}📋 配置信息:{Colors.NC}")
print(f" • MariaDB 版本: ", end="")
result = subprocess.run("mysql --version", shell=True, capture_output=True, text=True)
if result.returncode == 0:
print(result.stdout.strip())
print(f"\n{Colors.BOLD}👤 用户信息:{Colors.NC}")
print(f" • root 用户密码: {Colors.YELLOW}{root_password}{Colors.NC}")
if remote_user and remote_password:
print(f" • 远程用户名: {Colors.YELLOW}{remote_user}{Colors.NC}")
print(f" • 远程用户密码: {Colors.YELLOW}{remote_password}{Colors.NC}")
print(f"\n{Colors.BOLD}🔌 连接方式:{Colors.NC}")
print(f" • 本地连接:")
print(f" {Colors.CYAN}mysql -u root -p{Colors.NC}")
if remote_user:
print(f"\n • 远程连接:")
print(f" {Colors.CYAN}mysql -h {server_ip} -u {remote_user} -p{Colors.NC}")
print(f"\n{Colors.BOLD}🛠 服务管理:{Colors.NC}")
print(f" • 启动: {Colors.CYAN}systemctl start mariadb{Colors.NC}")
print(f" • 停止: {Colors.CYAN}systemctl stop mariadb{Colors.NC}")
print(f" • 重启: {Colors.CYAN}systemctl restart mariadb{Colors.NC}")
print(f" • 状态: {Colors.CYAN}systemctl status mariadb{Colors.NC}")
print(f"\n{Colors.BOLD}📁 重要文件:{Colors.NC}")
print(f" • 配置文件: /etc/mysql/mariadb.conf.d/50-server.cnf")
print(f" • 数据目录: /var/lib/mysql")
print(f" • 日志文件: /var/log/mysql/error.log")
print(f"\n{Colors.BOLD}⚠️ 安全提醒:{Colors.NC}")
print(f" • 已允许外网访问 (0.0.0.0:3306)")
print(f" • 建议配置防火墙限制访问 IP")
print(f" • 定期备份数据库")
print(f" • 定期更新密码")
if remote_user:
print(f"\n{Colors.BOLD}🔒 防火墙建议:{Colors.NC}")
print(f" # 只允许特定 IP 访问")
print(f" {Colors.CYAN}ufw delete allow 3306/tcp{Colors.NC}")
print(f" {Colors.CYAN}ufw allow from 你的IP地址 to any port 3306{Colors.NC}")
print(f"\n{Colors.GREEN}{'='*60}{Colors.NC}\n")
def main():
"""主函数"""
# 检查 root 权限
check_root()
# 解析命令行参数
if len(sys.argv) < 2:
print_error("缺少必要参数!")
print_info("\n使用方法:")
print(f" {Colors.CYAN}sudo python3 {sys.argv[0]} <root密码> [远程用户名] [远程用户密码]{Colors.NC}")
print(f"\n示例:")
print(f" {Colors.CYAN}sudo python3 {sys.argv[0]} MyRootPass123! appuser AppUserPass123!{Colors.NC}")
print(f" {Colors.CYAN}sudo python3 {sys.argv[0]} MyRootPass123!{Colors.NC}")
sys.exit(1)
root_password = sys.argv[1]
remote_user = sys.argv[2] if len(sys.argv) > 2 else None
remote_password = sys.argv[3] if len(sys.argv) > 3 else None
# 验证密码
print_info("验证密码强度...")
validate_password(root_password)
if remote_password:
validate_password(remote_password)
print(f"\n{Colors.BLUE}{'='*60}{Colors.NC}")
print(f"{Colors.BOLD}{Colors.BLUE}{' MariaDB 一键安装脚本':^60}{Colors.NC}")
print(f"{Colors.BLUE}{'='*60}{Colors.NC}\n")
print_info("准备安装 MariaDB...")
print_info(f"root 密码: {'*' * len(root_password)}")
if remote_user:
print_info(f"远程用户: {remote_user}")
print_info(f"远程密码: {'*' * len(remote_password if remote_password else root_password)}")
else:
print_warning("未指定远程用户,将不启用远程访问功能")
print_info("如需远程访问,请提供远程用户名和密码参数")
# 检查是否已安装
if check_mariadb_installed():
print_warning("检测到 MariaDB 已安装")
response = input("是否继续配置? (y/N): ")
if response.lower() != 'y':
print_info("安装已取消")
sys.exit(0)
skip_install = True
else:
skip_install = False
try:
# 安装 MariaDB
if not skip_install:
if not install_mariadb():
print_error("安装失败!")
sys.exit(1)
# 启动服务
if not start_mariadb():
print_error("启动服务失败!")
sys.exit(1)
# 配置 root 密码
if not configure_root_password(root_password):
print_error("配置 root 密码失败!")
sys.exit(1)
# 创建远程用户
if remote_user:
# 如果没有指定远程密码,使用 root 密码
final_remote_password = remote_password if remote_password else root_password
if not create_remote_user(root_password, remote_user, final_remote_password):
print_warning("创建远程用户失败,但可以继续")
# 配置远程访问
if not configure_remote_access():
print_error("配置远程访问失败!")
sys.exit(1)
# 配置防火墙
configure_firewall()
else:
print_warning("跳过远程访问配置(未指定远程用户)")
print_info("仅允许本地连接,bind-address 保持默认配置")
# 重启服务
if not restart_mariadb():
print_error("重启服务失败!")
sys.exit(1)
# 验证安装
if not verify_installation(root_password, remote_user):
print_error("验证安装失败!")
sys.exit(1)
# 打印摘要
final_remote_password = remote_password if remote_password else root_password if remote_user else None
print_summary(root_password, remote_user, final_remote_password)
except KeyboardInterrupt:
print_error("\n\n安装已被用户中断!")
sys.exit(1)
except Exception as e:
print_error(f"\n发生错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()
版权声明
本脚本和文档遵循 MIT 许可证,可自由使用和修改。
作者:[您的名字]
最后更新:2024年11月6日
版本:v1.1.0
许可证:MIT License
反馈与贡献
如果您在使用过程中遇到问题或有改进建议,欢迎反馈!
祝您使用愉快! 🎉