📋 一、 方案概述
Cloudflare Tunnel(原 Argo Tunnel)是一种安全的内网穿透解决方案,它通过在你的内网服务器和 Cloudflare 全球网络之间建立加密隧道,将内网服务安全地暴露到公网。本教程针对 Docker 部署的 MySQL 服务,详细介绍如何通过 Cloudflare Tunnel 实现安全远程访问。
✅ 核心优势
- 无需公网 IP:服务器可完全位于 NAT 后方
- 内置安全层:流量在 Cloudflare 网络内加密传输
- 隐藏源站 IP:外部攻击者无法获取真实服务器地址
- 免费使用:个人项目和小型团队基本无需付费
- 支持多种协议:HTTP/HTTPS、TCP、SSH、RDP 等
🔧 二、 准备工作
2.1 必要条件
- Cloudflare 账号:免费注册即可
- 自有域名 :已接入 Cloudflare DNS 托管(本文以
purelylab.com为例) - 内网服务器:运行 Docker MySQL 服务的机器
- 出站网络:服务器能够访问 Cloudflare 服务(通常无限制)
2.2 检查 Docker MySQL 服务
确保 Docker MySQL 服务正常运行:
bash
# 检查 Docker MySQL 容器状态
docker ps | grep mysql
# 检查 MySQL 服务是否监听
docker exec -it mysql mysql -h 127.0.0.1 -P 3306 -u root -p
在您的 Docker 宿主机上执行上述命令
🏗️ 三、 服务端配置(Docker 宿主机)
3.1 创建 Cloudflare Tunnel
- 登录 one.dash.cloudflare.com/
- 进入 Networks → Tunnels
- 点击 Create a tunnel
- 选择 Cloudflared 作为连接器类型,点击 Next
- 输入隧道名称(如
docker-mysql-tunnel),点击 Save tunnel
3.2 安装 cloudflared 客户端
根据服务器系统选择安装方式:
CentOS/RHEL 系统
bash
# 下载最新版 cloudflared
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -O cloudflared
# 添加执行权限
chmod +x cloudflared
# 移动到系统路径
sudo mv cloudflared /usr/local/bin/
# 验证安装
cloudflared --version
Ubuntu/Debian 系统
bash
# 添加 Cloudflare 官方源
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /etc/apt/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
# 安装 cloudflared
sudo apt-get update
sudo apt-get install cloudflared
3.3 认证并运行隧道
-
在 Tunnel 创建页面,复制安装命令(类似以下格式):
bashsudo cloudflared service install <YOUR_TUNNEL_TOKEN> -
在服务器上执行该命令,cloudflared 将作为系统服务安装并自动启动
-
返回 Cloudflare 控制台,点击 Next ,隧道状态应显示为 Active (HEALTHY)
3.4 配置 MySQL 隧道路由
- 在隧道配置页面,切换到 Public Hostnames 标签
- 点击 Add a public hostname
- 按以下配置填写:
- Subdomain :
mysql(或自定义前缀,如db、mysql-prod) - Domain : 选择你的域名(如
purelylab.com) - Type :
TCP(关键:必须选择 TCP,不是 HTTP) - URL :
tcp://127.0.0.1:3306(如果 Docker MySQL 映射到宿主机 3306 端口)- 如果 MySQL 容器映射到其他端口:
tcp://127.0.0.1:<映射端口>
- 如果 MySQL 容器映射到其他端口:
- Subdomain :
- 点击 Save endpoint
💻 四、 客户端配置(访问端)
4.1 安装 cloudflared 客户端
Windows 系统
- 访问 github.com/cloudflare/...
- 下载
cloudflared-windows-amd64.exe - 将文件重命名为
cloudflared.exe - 复制到系统路径:
C:\Windows\System32\ - 验证安装:打开 PowerShell 或 CMD,输入
cloudflared --version
macOS 系统
bash
brew install cloudflare/cloudflare/cloudflared
Linux 系统
参考服务端安装步骤。
4.2 建立本地 TCP 代理
powershell
# 在任意 PowerShell 或 CMD 窗口中执行
cloudflared access tcp --hostname mysql.purelylab.com --listener 127.0.0.1:3306
参数说明:
--hostname: Cloudflare 控制台中配置的完整域名--listener: 本地监听的地址和端口
4.3 创建便捷启动脚本
Windows 一键启动脚本
创建 启动MySQL隧道.bat:
bash
@echo off
echo 正在启动 MySQL Cloudflare 隧道...
cloudflared access tcp --hostname mysql.purelylab.com --listener 127.0.0.1:3306
pause
创建 后台启动MySQL隧道.bat(无窗口):
bash
@echo off
start /B cloudflared access tcp --hostname mysql.purelylab.com --listener 127.0.0.1:3306
echo 隧道已在后台启动,可关闭此窗口
timeout /t 3
Linux/macOS 后台服务
bash
# 创建服务文件
sudo tee /etc/systemd/system/cloudflared-mysql.service > /dev/null << EOF
[Unit]
Description=Cloudflare Tunnel for MySQL
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/cloudflared access tcp --hostname mysql.purelylab.com --listener 127.0.0.1:3306
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# 启用并启动服务
sudo systemctl daemon-reload
sudo systemctl enable cloudflared-mysql
sudo systemctl start cloudflared-mysql
🔌 五、 连接 MySQL 数据库
5.1 验证代理状态
bash
# 查看 cloudflared 进程
ps aux | grep cloudflared
5.2 使用命令行连接
bash
# 通过本地代理连接
mysql -h 127.0.0.1 -P 3306 -u 用户名 -p
5.3 使用图形化工具连接
- Navicat/DataGrip/DBeaver/MySQL Workbench 等工具
- 连接配置:
- 主机/Host :
127.0.0.1 - 端口/Port :
3306 - 用户名/Username: 你的 MySQL 用户名
- 密码/Password: 你的 MySQL 密码
- 主机/Host :
5.4 验证连接
执行简单查询验证连接是否正常:
sql
SHOW DATABASES;
SELECT VERSION();
SELECT @@hostname as '主机名';
📁 六、 Docker Compose MySQL 配置最佳实践
6.1 Docker Compose 配置示例
创建 docker-compose.yml 文件:
yaml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql_server
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-StrongPassword123!}
MYSQL_DATABASE: ${MYSQL_DATABASE:-myapp}
MYSQL_USER: ${MYSQL_USER:-appuser}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-AppUserPass123!}
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- /opt/mysql/data:/var/lib/mysql
- /opt/mysql/conf:/etc/mysql/conf.d
- /opt/mysql/logs:/var/log/mysql
- /opt/mysql/init:/docker-entrypoint-initdb.d
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --default-authentication-plugin=mysql_native_password
- --max_connections=1000
- --innodb_buffer_pool_size=1G
networks:
- mysql_network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
networks:
mysql_network:
driver: bridge
6.2 目录结构说明
csharp
/opt/mysql/
├── data/ # MySQL 数据文件
├── conf/ # 配置文件
│ └── custom.cnf # 自定义配置
├── logs/ # 日志文件
├── init/ # 初始化脚本
│ └── 01-init.sql
└── backup/ # 备份目录
6.3 自定义配置文件
创建 /opt/mysql/conf/custom.cnf:
ini
[mysqld]
# 字符集设置
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 连接设置
max_connections = 1000
max_connect_errors = 1000
connect_timeout = 60
wait_timeout = 28800
interactive_timeout = 28800
# 日志设置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_error = /var/log/mysql/error.log
# InnoDB 设置
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
# 安全设置
skip_name_resolve = 1
local_infile = 0
symbolic-links = 0
6.4 启动 Docker MySQL
bash
# 创建目录
sudo mkdir -p /opt/mysql/{data,conf,logs,init,backup}
sudo chmod -R 755 /opt/mysql
# 启动服务
docker-compose up -d
# 查看日志
docker-compose logs -f mysql
🔐 七、 安全最佳实践
7.1 MySQL 权限管理
sql
-- 创建专用隧道用户
CREATE USER 'tunnel_user'@'%' IDENTIFIED BY 'StrongTunnelPass123!';
-- 仅授予必要权限
GRANT SELECT, INSERT, UPDATE, DELETE ON your_database.* TO 'tunnel_user'@'%';
-- 创建只读用户(用于监控)
CREATE USER 'monitor_user'@'%' IDENTIFIED BY 'MonitorPass123!';
GRANT SELECT, PROCESS, REPLICATION CLIENT ON *.* TO 'monitor_user'@'%';
-- 查看用户权限
SHOW GRANTS FOR 'tunnel_user'@'%';
7.2 Docker 安全配置
bash
# 设置正确的目录权限
sudo chown -R 999:999 /opt/mysql/data
sudo chown -R 999:999 /opt/mysql/logs
sudo chmod 755 /opt/mysql/conf
# 创建专用 Docker 网络
docker network create --subnet=172.20.0.0/16 mysql_network
# 使用非 root 用户运行容器
docker run --name mysql \
--user 999:999 \
--network mysql_network \
--ip 172.20.0.2 \
--restart unless-stopped \
-v /opt/mysql/data:/var/lib/mysql \
-p 127.0.0.1:3306:3306 \
-e MYSQL_ROOT_PASSWORD=your_secure_password \
-d mysql:8.0
7.3 Cloudflare Access 策略
- 进入 Zero Trust → Access → Applications
- 点击 Add an application ,选择 Self-hosted
- 配置应用:
- Application name :
Docker MySQL Database - Domain :
mysql.purelylab.com - Session Duration: 24h
- Application name :
- 创建访问策略:
- Policy name :
Restrict MySQL Access - Action :
Allow - Configure rules :
Email matches your-email@domain.comCountry equals CN(可选)
- Policy name :
- 保存后,访问 MySQL 前需通过 Cloudflare Access 验证
7.4 定期维护任务
bash
# 备份数据库
docker exec mysql mysqldump -u root -p your_database > /opt/mysql/backup/backup_$(date +%Y%m%d_%H%M%S).sql
# 清理旧备份(保留7天)
find /opt/mysql/backup -name "*.sql" -mtime +7 -delete
# 检查容器健康状态
docker ps --filter "name=mysql" --format "table {{.Names}}\t{{.Status}}"
# 查看资源使用
docker stats mysql --no-stream
🔧 八、 故障排查
8.1 常见问题及解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 隧道状态不健康 | cloudflared 服务未运行 | sudo systemctl status cloudflared |
| Docker 容器未启动 | 端口冲突或配置错误 | docker-compose logs mysql |
| MySQL 连接被拒绝 | 权限不足或防火墙 | 检查 MySQL 用户权限和 Docker 端口映射 |
| 域名无法解析 | DNS 配置错误 | 检查 Cloudflare DNS 记录 |
| 代理连接超时 | 隧道配置错误 | 检查 Tunnel 的 Public Hostname 配置 |
| 数据目录权限问题 | 文件系统权限错误 | sudo chown -R 999:999 /opt/mysql/data |
8.2 检查网络连接
bash
# 检查 Docker 网络
docker network inspect mysql_network
# 检查端口监听
sudo netstat -tlnp | grep 3306
# 测试本地连接
mysql -h 127.0.0.1 -P 3306 -u 用户名 -p -e "SELECT 1;"
8.3 查看日志文件
bash
# Docker MySQL 日志
docker logs mysql --tail 50
# Cloudflared 服务日志
sudo journalctl -u cloudflared -f
# MySQL 错误日志
docker exec mysql tail -f /var/log/mysql/error.log
8.4 调试命令
bash
# 测试 Cloudflare Tunnel
cloudflared tunnel list
cloudflared tunnel info docker-mysql-tunnel
# 验证 DNS 解析
nslookup mysql.purelylab.com
dig mysql.purelylab.com
# 测试 TCP 连接
nc -zv 127.0.0.1 3306
📊 九、 性能监控
9.1 Docker 监控命令
bash
# 查看容器资源使用
docker stats mysql
# 查看容器日志大小
docker exec mysql du -sh /var/log/mysql/
# 查看数据库连接数
docker exec mysql mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"
9.2 MySQL 性能监控
sql
-- 查看当前连接
SHOW PROCESSLIST;
-- 查看性能指标
SHOW STATUS LIKE 'Connections';
SHOW STATUS LIKE 'Max_used_connections';
SHOW STATUS LIKE 'Threads_connected';
-- 查看慢查询
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS\G
9.3 监控脚本示例
创建 /opt/mysql/scripts/monitor.sh:
bash
#!/bin/bash
# MySQL 监控脚本
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/opt/mysql/logs/monitor_${DATE}.log"
echo "=== MySQL 监控报告 ===" > $LOG_FILE
echo "时间: $(date)" >> $LOG_FILE
echo "" >> $LOG_FILE
# 检查容器状态
echo "1. Docker 容器状态:" >> $LOG_FILE
docker ps --filter "name=mysql" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" >> $LOG_FILE
echo "" >> $LOG_FILE
# 检查数据库连接
echo "2. 数据库连接状态:" >> $LOG_FILE
docker exec mysql mysql -u monitor_user -pMonitorPass123! -e "SHOW STATUS LIKE 'Threads_connected';" >> $LOG_FILE
echo "" >> $LOG_FILE
# 检查磁盘使用
echo "3. 磁盘使用情况:" >> $LOG_FILE
df -h /opt/mysql >> $LOG_FILE
echo "" >> $LOG_FILE
# 清理旧日志(保留7天)
find /opt/mysql/logs -name "monitor_*.log" -mtime +7 -delete
添加定时任务:
bash
# 每天凌晨检查
0 2 * * * /opt/mysql/scripts/monitor.sh
📁 十、 备份与恢复
10.1 自动备份脚本
创建 /opt/mysql/scripts/backup.sh:
bash
#!/bin/bash
# MySQL 自动备份脚本
BACKUP_DIR="/opt/mysql/backup"
DATE=$(date +%Y%m%d_%H%M%S)
MYSQL_CONTAINER="mysql"
MYSQL_USER="root"
MYSQL_PASS="your_secure_password"
# 创建备份目录
mkdir -p $BACKUP_DIR
echo "开始备份 MySQL 数据库..."
# 备份所有数据库
docker exec $MYSQL_CONTAINER mysqldump \
-u $MYSQL_USER \
-p$MYSQL_PASS \
--all-databases \
--single-transaction \
--routines \
--triggers \
--events \
> $BACKUP_DIR/full_backup_$DATE.sql
# 压缩备份文件
gzip $BACKUP_DIR/full_backup_$DATE.sql
# 清理旧备份(保留30天)
find $BACKUP_DIR -name "*.gz" -mtime +30 -delete
echo "备份完成: $BACKUP_DIR/full_backup_${DATE}.sql.gz"
10.2 恢复数据库
bash
# 解压备份文件
gunzip /opt/mysql/backup/full_backup_20250101_120000.sql.gz
# 恢复数据库
docker exec -i mysql mysql -u root -p < /opt/mysql/backup/full_backup_20250101_120000.sql
10.3 备份策略
| 备份类型 | 频率 | 保留时间 | 存储位置 |
|---|---|---|---|
| 完整备份 | 每天 | 30天 | 本地 /opt/mysql/backup |
| 增量备份 | 每小时 | 7天 | 本地 + 远程存储 |
| 逻辑备份 | 每周 | 90天 | 云端存储(可选) |
🎯 总结
通过 Cloudflare Tunnel 结合 Docker MySQL,您可以获得一个安全、稳定、易于管理的远程数据库访问解决方案。关键优势包括:
✅ 主要优点
- 安全可靠:端到端加密,隐藏源站 IP
- 配置简单:无需公网 IP,无需配置路由器
- 易于维护:Docker 容器化部署,数据持久化存储
- 完全免费:Cloudflare 提供免费套餐
🔧 核心配置步骤
- 准备环境:部署 Docker MySQL,配置数据持久化
- 创建隧道:在 Cloudflare 控制台创建 Tunnel
- 安装代理:在服务器安装 cloudflared
- 配置路由:设置 TCP 类型的 Public Hostname
- 客户端连接:通过本地代理访问数据库
- 安全加固:配置访问策略和权限控制
📁 目录结构总结
bash
/opt/mysql/
├── data/ # 数据文件(持久化)
├── conf/ # 配置文件
├── logs/ # 日志文件
├── init/ # 初始化脚本
├── backup/ # 备份文件
├── scripts/ # 管理脚本
└── docker-compose.yml
🚀 进阶功能
- 多环境部署:开发、测试、生产环境分离
- 自动备份:定时备份,防止数据丢失
- 监控告警:实时监控数据库状态
- 高可用方案:主从复制,读写分离
- 性能优化:根据业务需求调整配置