反向代理不能直接代理数据库tcp连接,需通过网络隔离、专用代理(如mysql router/proxysql)或http网关封装实现隐藏。核心是禁用数据库公网监听、防火墙限制访问、主从走内网,并分层收敛出口。

反向代理本身不能直接代理数据库连接(如 MySQL、PostgreSQL 的 TCP 端口),因为它天然面向 HTTP/HTTPS 协议。所谓“用反向代理隐藏数据库端口”,本质是不暴露数据库给公网,也不让应用直连数据库 IP:端口,而是通过中间服务层做协议转换或请求中转。对老旧主从架构数据库(例如 MySQL 5.7 主从 + PHP/Java 应用),真正可行且安全的隐藏方案,需结合网络隔离、代理网关与应用层改造三者协同。
必须先切断数据库的公网暴露路径
这是所有后续操作的前提。老旧数据库常因配置疏忽监听 0.0.0.0:3306,等同于把钥匙挂在门口:
- 修改数据库配置文件(如 my.cnf):将 bind-address = 127.0.0.1 或内网地址(如 192.168.10.10),禁止监听公网网卡
- 云服务器安全组 / 本地防火墙(iptables/ufw):只允许 Nginx 或应用服务器 IP(如 192.168.10.5)访问 3306 端口,拒绝其他所有来源
- 确认主从复制使用内网地址通信(如 CHANGE MASTER TO MASTER_HOST='192.168.10.11'),避免跨公网同步
用 HTTP 网关封装数据库查询(推荐轻量级方案)
老旧系统难以重构,但可加一层无状态 API 网关,把 SQL 查询转成 HTTPS 接口,彻底屏蔽端口与协议:
- 部署一个极简 Node.js/Python Flask 服务(监听 127.0.0.1:8081),它只接受 POST 请求,校验 Token 后执行预设 SQL(如 SELECT * FROM users WHERE id=?),返回 JSON
- 在宝塔或 Nginx 中为该网关配置反向代理:location /api/db/ { proxy_pass http://127.0.0.1:8081/; },对外仅暴露 https://api.example.com/api/db/
- 应用代码中把原生 MySQL 连接替换为调用该 HTTPS 接口,无需改动数据库本身,主从逻辑完全保留
若必须透传原生数据库协议,用专用代理工具替代 Nginx
Nginx 不支持 MySQL 协议转发,强行用 stream 模块做四层代理会丢失负载均衡智能性,且无法隐藏真实后端——这时应选用专为数据库设计的代理:
- MySQL Router(Oracle 官方):支持自动发现主从拓扑,可绑定到 127.0.0.1:6446,应用连接此端口,Router 内部按读写分离路由到真实主库/从库,对外不暴露 3306
- ProxySQL:更灵活,支持 SQL 重写、熔断、缓存;配置其监听 0.0.0.0:6033,后端指向 192.168.10.10:3306(主) 和 192.168.10.11:3306(从),再用防火墙封死外部对 3306 的直连
- 两者均需配合宝塔/Nginx 做最外层 HTTPS 终结(如用 Nginx 反代 ProxySQL 的管理接口),但数据链路本身走 TCP,不经过 HTTP 层
负载均衡与隐藏需分层实现
“完美隐藏”不是靠单一组件,而是分层收敛出口:
- 网络层:数据库只响应内网请求,防火墙默认 DROP 所有进 3306 的公网包
- 协议层:用 MySQL Router/ProxySQL 替代直连,统一入口端口(如 6033),内部自动选主从
- 应用层:业务代码不写死数据库地址,全部通过网关或代理端口访问
- 出口层:Nginx 对网关服务启用 SSL、强制 HTTPS、清除 Server 头、拦截敏感路径(如 location ~ ^/mysql.*$ { return 403; })











