先界定这次检查的范围:我们只关心 MySQL 和 Redis 这两个服务实际监听的网络地址,以及这个监听行为对 WordPress/LAMP 站点的影响。换句话说,要回答三个问题——服务在听什么地址、配置和启动参数是否一致、以及改动监听后业务是否还能正常走通。整个过程按“盘点、核对、小步调整、验证、回滚准备”的顺序推进,每一步都有明确的执行位置和预期现象,方便你边做边复核。
第一步:用 ss 定位实际监听地址,而不是猜
很多暴露问题的根源,是配置文件和实际运行状态不一致。比如 MySQL 的 bind-address 写的是 127.0.0.1,但启动参数里又叠加了 --bind-address=0.0.0.0,最终生效的是后者。所以第一步不要看配置文件,先看操作系统眼里这两个服务到底在听什么。
执行下面的命令,分别查看 MySQL(默认端口 3306)和 Redis(默认端口 6379)的监听状态:
ss -lntp | grep -E ':(3306|6379)\b'预期你会看到两类结果。一类是 127.0.0.1:3306 或 ::1:3306,说明只监听回环地址,本机之外无法直接访问,这是安全状态;另一类是 0.0.0.0:3306 或具体的公网/内网 IP 地址,说明服务对所有网络接口或特定外部接口开放,这就是需要处理的对象。
如果 ss 输出为空,先确认服务是否在运行,再用 systemctl status mysql 或 systemctl status redis 查看进程状态。另外注意,如果服务器上有多个 PHP-FPM 池或 Docker 容器,ss 输出里可能有多条记录,逐一核对端口对应的进程 PID 和程序名,避免把容器内部的监听误判为宿主机暴露。
这里有一个容易忽略的细节:ss 显示的地址是内核视角的 socket 绑定结果,它已经综合了配置文件、启动参数和环境变量。所以只要 ss 显示 0.0.0.0,无论配置文件里写的是什么,实际就是暴露的。
第二步:核对配置、启动参数和云安全组三层来源
定位到监听异常后,需要找出是谁把地址设成了 0.0.0.0。常见来源有三个,按优先级排查:
| 排查来源 | MySQL 执行位置 | Redis 执行位置 |
|---|---|---|
| 主配置文件 | /etc/mysql/mysql.conf.d/mysqld.cnf 或 /etc/my.cnf 中的 bind-address | /etc/redis/redis.conf 中的 bind 指令 |
| 启动参数/覆盖文件 | systemctl cat mysql 查看 ExecStart 行是否带 --bind-address;检查 /etc/mysql/conf.d/ 下的追加配置 | systemctl cat redis 查看 ExecStart 行;检查 /etc/redis/redis.conf 末尾的 include 或覆盖段 |
| 云平台安全组/防火墙 | 云控制台的入站规则是否放行了 3306/6379 | 同左 |
对 MySQL,执行 grep -r "bind-address" /etc/mysql/ 可以一次扫出所有配置文件里的设置;对 Redis,执行 grep -E "^(bind|protected-mode)" /etc/redis/redis.conf。注意 Redis 的 bind 指令可以跟多个地址,比如 bind 127.0.0.1 192.168.1.10,这表示同时监听回环和内网地址,是否要保留取决于你的业务拓扑。
云安全组的核查容易被漏掉。即使你把服务绑定了 127.0.0.1,如果云平台的安全组或主机防火墙(iptables/nftables)仍然放行了 3306/6379 的入站流量,外部请求虽然无法到达服务,但端口扫描依然会显示为“开放”,这会给攻击者留下错误印象,也可能掩盖其他配置问题。所以安全组的规则要一并检查和收敛。
第三步:判断业务依赖,别急着改
在动手改监听地址之前,先确认是否有业务确实需要从外部访问这两个服务。对 WordPress/LAMP 站点来说,最常见的依赖关系是:
- Web 服务器(Nginx/Apache)和 PHP-FPM 进程需要连接 MySQL,通常通过
127.0.0.1:3306或 Unix socket 连接; - Redis 作为对象缓存或会话存储,PHP 的
redis扩展或 WordPress 的缓存插件(如 Redis Object Cache)通过127.0.0.1:6379连接; - 远程开发或管理工具,比如本地的 MySQL Workbench、RedisInsight,如果之前是通过公网 IP 直连的,改成回环后这些工具会失效,需要改用 SSH 隧道。
一个快速判断方法:在服务器上执行 lsof -i :3306 -i :6379 或 ss -tnp | grep -E ':(3306|6379)',看当前有哪些进程建立了到这两个端口的连接。如果连接来源全部是本机 IP(127.0.0.1 或内网地址),那基本可以确定业务只走本机回环,改成 127.0.0.1 不会影响现有访问。
如果确实存在远程连接需求,不要直接把监听改成回环,而是改成内网地址(如 192.168.x.x),并确保云安全组只放行来源 IP 为你办公网络或跳板机的规则。
第四步:小步调整,先改配置再重启
确认业务依赖后,按“先 MySQL 后 Redis”的顺序逐个调整,避免两个服务同时变动导致问题难以定位。
MySQL 调整步骤:
- 备份当前配置:
cp /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf.bak.$(date +%F) - 编辑配置文件,将
bind-address改为127.0.0.1:
[mysqld]
bind-address = 127.0.0.1- 如果之前是通过启动参数覆盖的,还需要检查
systemctl cat mysql的ExecStart行,去掉多余的--bind-address参数。 - 执行
mysqladmin -u root -p ping确认服务可用,再执行systemctl restart mysql。 - 重启后立即执行
ss -lntp | grep 3306,确认监听地址已变为127.0.0.1。
Redis 调整步骤:
- 备份配置:
cp /etc/redis/redis.conf /etc/redis/redis.conf.bak.$(date +%F) - 编辑配置文件,将
bind指令改为bind 127.0.0.1,并确认protected-mode yes已启用:
bind 127.0.0.1
protected-mode yes- 执行
redis-cli ping确认服务可响应,再执行systemctl restart redis。 - 重启后执行
ss -lntp | grep 6379确认监听地址。
注意:Redis 的 protected-mode 只有在没有设置密码且没有显式绑定地址时才会生效。如果你已经设置了 requirepass,protected-mode 的作用会减弱,但绑定回环仍然是第一道防线。
第五步:防火墙兜底,防止重启后配置回弹
配置文件的修改可能在服务升级或配置管理工具(如 Ansible、Puppet)重新下发时被覆盖。为了在配置回弹时仍能兜底,建议在主机防火墙层加一条临时规则,明确拒绝外部对 3306/6379 的访问。
以 nftables 为例(大多数现代发行版默认使用),添加两条规则:
nft add rule inet filter input tcp dport 3306 ip saddr != 127.0.0.1 drop
nft add rule inet filter input tcp dport 6379 ip saddr != 127.0.0.1 drop如果服务器用的是 iptables:
iptables -A INPUT -p tcp --dport 3306 ! -s 127.0.0.1 -j DROP
iptables -A INPUT -p tcp --dport 6379 ! -s 127.0.0.1 -j DROP执行后可以用 nft list ruleset 或 iptables -L -n 确认规则已生效。但要注意,这些规则是临时的,重启后不会保留。要持久化,需要根据发行版使用 nftables.service 的配置文件或 iptables-persistent 工具保存。
防火墙规则的意义在于:即使某天配置文件被改回 0.0.0.0,防火墙仍然会拦截外部流量,给你留出发现和修复的时间窗口。但不要把它当作长期的解决方案——它只是过渡期的兜底。

第六步:业务连通性验证,按访问路径逐项确认
改动监听地址后,最直接的后果是依赖这两个服务的业务可能断连。验证不能只看服务本身是否启动,要按实际业务路径逐项确认。
WordPress 站点访问验证:
- 用浏览器访问站点首页和一篇带数据库查询的文章页,确认页面正常渲染;
- 登录 WordPress 后台,确认登录、发布文章、上传媒体等操作正常;
- 如果启用了 Redis 对象缓存,检查缓存是否命中,可以执行
redis-cli -h 127.0.0.1 ping确认连接,再观察 WordPress 的缓存插件状态页。
命令行连接验证:
# 本机连接 MySQL
mysql -h 127.0.0.1 -u wordpress_user -p -e "SELECT 1;"
# 本机连接 Redis
redis-cli -h 127.0.0.1 pingPHP-FPM 连接验证:
WordPress 的 wp-config.php 里定义了数据库连接常量,确认 DB_HOST 是 127.0.0.1 或 localhost(使用 Unix socket)。如果之前用的是公网 IP,这里也要一并修改:
define('DB_HOST', '127.0.0.1');对于 Redis 缓存插件,检查 wp-config.php 或插件设置中的连接地址是否也指向 127.0.0.1。
外部访问确认:
从另一台机器(比如你的办公电脑)执行 nc -zv 服务器IP 3306 和 nc -zv 服务器IP 6379,预期结果是连接被拒绝或超时。如果仍然能连通,说明防火墙规则没有生效,或者云安全组还在放行,需要回头检查。
第七步:回滚清单,给每个变更留一条退路
任何配置变更都可能引入新问题,所以回滚路径要提前准备好。把这次涉及的文件和命令整理成一张清单,放在服务器上的 /root/ 或运维文档里,方便随时取用。
| 变更项 | 变更前状态 | 回滚操作 | 预期恢复 |
|---|---|---|---|
MySQL bind-address | 0.0.0.0 | 恢复备份文件 cp mysqld.cnf.bak.日期 mysqld.cnf,执行 systemctl restart mysql | 监听恢复为 0.0.0.0,外部连接恢复 |
Redis bind 指令 | 0.0.0.0 | 恢复备份文件 cp redis.conf.bak.日期 redis.conf,执行 systemctl restart redis | 监听恢复为 0.0.0.0 |
| 防火墙规则 | 无 | 删除规则:nft delete rule inet filter input handle 编号 或 iptables -D INPUT ... | 外部流量不再被拦截 |
wp-config.php 的 DB_HOST | 公网 IP | 改回原值 | WordPress 恢复原连接方式 |
回滚的触发条件是:业务连通性验证失败,且无法在 15 分钟内定位原因。不要试图在回滚前反复调试——先恢复服务,再在维护窗口内排查。

复盘:把这次核查固化成巡检项
完成变更和验证后,花几分钟把这次的经验固化下来。至少做三件事:
- 把监听地址核查加入月度巡检脚本,用一条命令输出所有非回环监听的服务端口:
ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.1\|::1'这个输出里出现的任何端口,都需要说明为什么监听在非回环地址上。
- 在云安全组里收敛入站规则,把 3306 和 6379 的放行规则删掉,或改为仅允许特定来源 IP。安全组是云环境下的第一道边界,它的状态比主机防火墙更直观,也更容易被审计。
- 检查是否有其他服务存在同样问题,比如 PostgreSQL(5432)、MongoDB(27017)、Elasticsearch(9200)。用同样的
ss命令扫一遍所有监听端口,把暴露面清单完整拉出来。
数据库和缓存服务监听在回环地址上,是 Web 站点最基本的一条安全基线。这次核查的价值不在于改掉一个配置项,而在于你确认了“服务实际在听什么”和“业务真正需要什么”这两者之间是一致的。下次再做类似变更时,这套“盘点—核对—小步调整—验证—回滚”的流程可以直接复用。
- it2021
- it2021.com
- WordPress
- 云安全
- 平台安全





1F
ss那条命令确实比看配置文件靠谱,之前就被启动参数坑过
2F
Redis的protected-mode和requirepass一起配才稳,光绑回环也不够