十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Redis 外网访问配置与排错:bind、protected-mode 及安全组

Redis 外网访问配置与排错:bind、protected-mode 及安全组 Connection refused这四个字我大概见过几百次了。绝大多数情况下问的人第一句话都是我在 redis.conf 里把 bind 改成 0.0.0.0 了为什么还是连不上。说实话Redis 想被外网访问改的东西不多但坑特别密——bind、protected-mode、requirepass、systemd 的启动参数、Docker 的端口映射、云厂商的安全组任何一环没对上症状看起来都是同一句连不上但根因完全不在一个地方。这篇文章就把让 Redis 外网可访问这件事从原理到落地拆一遍包括我这些年踩过的具体坑、每种部署形态下该改哪几行、以及配置改完之后还剩哪几层门要过。不管你是刚装完 Redis 的新手还是被线上连接问题折腾过的老手应该都能从里面找到点能直接抄作业的东西。1. 默认装完的 Redis 只认本机bind 与 protected-mode 的联手拦截很多人以为 Redis 默认就是能被别人连的恰恰相反。从 3.2 版本开始官方给的默认配置就明确写着两行不太起眼、但决定了你能不能从外网连进来的设置。你要是直接apt install redis-server或者解压源码make完就启动不做任何改动那么恭喜这台机器之外的任何 IP 都连不上本地却一切正常——这就是所有连不上问题的起点。先建立一个基本认知Redis 不是一个默认面向网络的服务。它设计之初的定位就是跑在可信内网里的、给本机或同机架应用用的数据服务。它没有传输层加密TLS 是 6.0 才加的而且默认关、没有请求级别的细粒度风控、协议是明文文本一个CONFIG SET就能让服务端往磁盘上写文件。官方知道这一点所以默认配置一直在往收的方向调早期版本默认bind 0.0.0.0后来慢慢收成了只绑回环地址。1.1 bind 从监听哪些网卡说起bind这一行的含义比很多人想的要具体。它不是说允许哪些 IP 连进来而是说服务端要在哪几块网卡上开监听套接字。这是一条 TCP 层的指令跟后面的认证、白名单是两码事。现在打开配置文件你大概率会看到这样一行bind 127.0.0.1 -::1这里有两个细节值得说。第一127.0.0.1是 IPv4 回环地址只有从本机发起的连接才会走这块网卡服务器上那块公网网卡、内网网卡Redis 压根没在上面开监听。第二-::1前面那个短横线是 Redis 6 之后引入的语法意思是这个地址如果绑不上就跳过别让启动失败。老版本写法是bind 127.0.0.1 ::1如果机器上禁用了 IPv6Redis 启动会直接报错退出报的还是一句很难看懂的Could not create server TCP listening socket ::1:6379: bind: Cannot assign requested address。这个坑我在一批老 CentOS 机器上踩过当时排查了半天才发现是 IPv6 被内核参数关掉了。想验证当前到底监听了哪些地址最直接的办法是看端口ss -lntp | grep 6379如果输出里Local Address:Port那一列是127.0.0.1:6379那外部必然连不上如果是0.0.0.0:6379或者*:6379说明所有网卡都在监听如果是172.17.0.2:6379这种具体内网地址那就只在那块网卡上可达。这个命令我基本是下意识就会敲的它比翻配置文件快得多而且能直接反映服务真实的运行状态——配置文件改了但服务没重启这里看到的还是旧状态。1.2 protected-mode 拦下来的那条错误信息光改bind很多时候还不够因为还有第二道闸protected-mode。protected-mode yes这道保护从 3.2 版本开始默认开启。它的逻辑是当既没有显式配置 bind 地址、也没有给默认用户设置密码时Redis 只接受来自回环地址的连接。注意这里的条件——它同时要求没有配 bind和没有设密码。所以你会看到一种很有意思的现象有人只加了requirepass没改bind外部还是连不上有人只改了bind 0.0.0.0没设密码反而能连上了。被 protected mode 拦住的时候报错信息其实相当直白长这样DENIED Redis is running in protected mode because protected mode is enabled and no password is set for the default user. In this mode connections are only accepted from the loopback interface.这条信息值得仔细读因为它把可选的解法都列出来了从回环地址连上去执行CONFIG SET protected-mode no、改配置文件重启、启动时加--protected-mode no、或者设置绑定地址或认证密码。我的建议一直是选最后一条——设密码 显式 bind而不是简单粗暴地把 protected-mode 关掉。原因后面第 2 节会展开。还有一个容易被忽略的点protected mode 的拒绝发生在 TCP 连接建立之后。也就是说对端telnet是能连通端口的只有在发出第一条命令比如PING之后才会收到那条 DENIED 然后被断开。这一点非常关键它意味着telnet 能通不等于Redis 能用排查的时候别被 telnet 的成功骗了。1.3 连接被拒和连接超时不是一回事排查 Redis 连通性第一件事是分清客户端给你的到底是哪种失败。客户端表现含义大概率原因Connection refusedTCP SYN 收到了 RST端口没有监听或监听的地址不包含目标网卡或防火墙配置成 REJECTConnection timed outSYN 发出去没有任何回应中间有 DROP 规则的防火墙、云安全组未放行、路由不可达能连上但马上断开日志里出现 DENIEDTCP 层通了应用层拒绝protected mode 生效或 ACL 拒绝能连上但报NOAUTH Authentication required认证未通过服务端设了 requirepass客户端没带密码能连上但报WRONGPASS密码错误密码不一致或配置文件里的引号/特殊字符被吃掉了这个表我建议打印出来贴在工位上。因为refused和timeout这两个词一旦分清了排查范围能立刻缩小一半refused 往服务端和本机看timeout 往网络链路和防火墙看。我遇到过最典型的误判就是有人拿着 timeout 的报错去改redis.conf反复重启了十几次最后发现是云平台的安全组没放行 6379 端口。2. 改动之前必须先想清楚的三件事暴露范围、认证、回滚技术动作本身很简单改两行配置重启就完事。但真正决定这次改动是顺手还是事故的是动手之前的那几分钟思考。这一节我想聊的不是操作而是判断。2.1 先定义外网到底指哪一层外网可访问这个说法太笼统了它在不同人嘴里完全是不同的意思。动手之前先回答一个问题谁需要连它同机房另一台机器这其实不算外网走的是内网网卡。你把bind加上内网 IP 就行公网网卡完全不用开。这种情况最安全也最常见。同公司不同办公区的开发机走的是公司内网或专线仍然建议只绑内网 IP让网络设备去路由。公网服务器开发者从家里连这才是真正意义上的外网可访问也是风险最高的一种。这时候你的对手不是能不能连上而是怎么避免被扫到。Docker 容器里跑宿主机或同宿主其他容器要连这是另一种外网容器有独立的网络命名空间容器内部的回环地址和宿主机的完全是两回事。K8s 里跑其他命名空间或集群外要连又不一样走的是 Service、Ingress 或者 NodePort。把这四个字拆开之后你会发现真正需要对公网零限制开放的场景其实少之又少。绝大部分需求一个bind加上内网 IP或者一条白名单规则就解决了。我在实际项目里推行的原则是能走内网就不走公网能加白名单就不开全网能临时开放就不做永久配置。2.2 Redis 直接暴露在公网风险到底来自哪里我不想用危险这种空词糊弄过去具体说说风险从哪来。Redis 的协议是纯文本的没有请求签名、没有防重放、没有连接级身份绑定。一旦攻击者能连上并且你的实例没有密码他拿到的是完整的管理员权限包括但不限于CONFIG SET dir /root/.ssh配合CONFIG SET dbfilename authorized_keys然后SAVE可以直接往目标机器的 SSH 授权文件里写内容。这条路径是历史上被用过最多的手法之一。SLAVEOF/REPLICAOF让别人把 Redis 实例挂成从节点把数据同步走。FLUSHALL清空全部数据这不需要任何技巧一条命令。CONFIG GET *把配置里的所有信息读出来包括你可能写在配置文件里的其他凭据。这些都不是理论推演而是公开披露过、被自动化扫描工具批量利用过的路径。更麻烦的是6379 这个端口是扫描器的必扫项从一台公网机器上线到被扫很多时候以小时计。所以我的态度很明确如果你的实例要暴露在公网密码是必须项白名单是标配改端口是加分项三者都不做就是把家门钥匙插在门上。2.3 动手之前留一条回滚路径这一条是纯经验。我在生产环境改 Redis 配置之前习惯做三件事备份原配置文件cp redis.conf redis.conf.bak.$(date %F)带上日期改坏了直接换回来。确认当前服务的启动方式和配置来源ps -ef | grep redis-server看一眼实际命令行参数。这一步能救你很多次因为经常出现改了 A 文件但服务读的是 B 文件的情况。判断这个实例的数据能不能丢如果是纯缓存maxmemory-policy设了allkeys-lru之类重启没压力如果它承担了持久化存储的角色重启前确认一下 AOF/RDB 的状态别因为一次配置变更加上一次意外宕机导致数据回退。写下来好像都是废话但确实见过太多人直接vim redis.conf改完systemctl restart redis出问题之后连自己改了什么、原来是什么样都想不起来了。3. redis.conf 里真正挡路的四行配置逐行拆开讲准备工作做完进入正题。这一节把配置文件里跟外部访问直接相关的几项一个一个拆。3.1 bind写 0.0.0.0 之前先想清楚bind的三种典型写法适用场景完全不同# 写法一只监听本机默认状态最安全 bind 127.0.0.1 -::1 # 写法二监听指定网卡推荐用于内网互通 bind 127.0.0.1 172.16.10.21 -::1 # 写法三监听所有网卡风险最高仅在明确需要时使用 bind 0.0.0.0写法二是我的默认推荐。它同时保留了本机回环和内网地址本机的运维脚本、监控探针照常工作内网的其他机器也能连。写的时候注意把真正需要的地址都列上Redis 从 6 版本起支持一次绑定多个地址。这里有一个特别容易踩的坑bind 0.0.0.0和bind 127.0.0.1不能同时写。因为0.0.0.0已经覆盖了所有网卡再去绑127.0.0.1:6379会出现端口冲突Redis 启动直接失败报Could not create server TCP listening socket 127.0.0.1:6379: bind: Address already in use这句报错极具误导性很多人的第一反应是6379 端口被别的进程占了跑去lsof -i:6379又查不出来。实际上是它自己跟自己撞了。记住这个组合0.0.0.0 是独占写法要么只用它要么用具体地址列表。另外补充一个基于常见实践的补充说明Redis 7 之后bind指令的地址如果不想让启动失败都可以加-前缀。这个特性在容器化和多网卡环境下特别有用因为容器的 IP 经常是动态的写死一个地址很容易启动失败。3.2 protected-mode什么时候可以留着 yes网上大量教程的处理方式是把 protected-mode 改成 no 就完事了我不推荐这个做法理由很直接这道保护是免费的安全兜底关掉它换来的只是少设一个密码的便利。正确的处理顺序是这样先把requirepass设上下一小节讲。再把bind按上一小节的写法二配好。protected-mode保持yes不变。因为在有密码的前提下protected mode 根本不会拦你。它的触发条件是没配 bind 没设密码两个条件满足其一它就不生效了。所以完全没必要关它。那什么情况下可以关我能想到的合理场景只有一种临时的、生命周期以小时计的测试环境而且这台机器不在公网上。这种情况下CONFIG SET protected-mode no一条命令解决测试完记得CONFIG SET protected-mode yes改回来——或者干脆别改回来直接销毁实例。有一个细节要提醒CONFIG SET改的是运行时状态不写进配置文件。重启之后又会变回配置文件里的值。如果你想让改动永久生效需要执行CONFIG REWRITE它会把内存中的配置回写到配置文件里。不过CONFIG REWRITE有个前提——Redis 是通过配置文件启动的。如果你是用命令行参数直接拉起来的执行它会报The server is running without a config file。3.3 requirepass 与 Redis 6 之后的 ACL密码这一行看起来最简单requirepass YourStrongPasswordHere但有几个细节不注意就会踩坑。第一密码里带特殊字符的处理。如果你的密码里有#、空格、引号这类字符在配置文件里必须用引号包起来否则会被当成注释或者被截断requirepass a#b c\d我一般直接建议用引号包裹不管是哪种密码省心。同时避免在某些环境里使用美元符号一类的字符因为在 shell 或某些配置管理工具里容易发生变量替换。第二Redis 6 之后 requirepass 其实是个语法糖。Redis 6 引入了 ACL 系统requirepass在内部会被翻译成给default用户设置密码# 这两种写法在 Redis 6 里效果基本等价 requirepass mypassword user default on mypassword ~* all理解这一点很重要因为如果你同时在配置文件里写了requirepass和user default ...以哪个为准、会不会互相覆盖是很多人困惑的地方。我的建议是要么只用 requirepass要么完全走 ACL 写 user 行不要混着写。第三从库需要单独配一个东西。如果你配了主从从节点要用masterauth指定主节点的密码否则复制会一直失败日志里反复刷NOAUTH Authentication required。这个跟requirepass是两回事经常被漏掉。第四命令行的连接方式。设了密码之后redis-cli需要这样连redis-cli -h 172.16.10.21 -p 6379 -a YourStrongPasswordHere注意这里加引号是对的shell 会把特殊字符交给 redis-cli 原样处理。不过命令行带-a有个副作用redis-cli 会提示 Using a password with -a or -u option on the command line interface may not be safe并且密码会出现在进程列表里。生产环境更推荐用--user加环境变量或者干脆进交互模式之后再AUTH。3.4 配置文件到底加载的是哪一个这一条严格来说不算配置项但它导致的改了不生效比任何配置项都多。判断方法很简单进去问 Redis 自己redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379 CONFIG GET dir 127.0.0.1:6379 INFO server | grep -E config_file|executable输出里的config_file就是它实际加载的配置文件路径。如果这个路径跟你编辑的文件不是同一个那问题就找到了。常见的几种改错了文件的情形从源码编译安装配置文件在/usr/local/redis/redis.conf但你以为在/etc/redis/。用 systemd 启的服务ExecStart里写死了配置路径你在别处改了没用。Docker 容器里改了容器内的文件但容器重启后配置被镜像里的原始文件覆盖了实际是容器重建改动丢失。存在多个实例多端口、多配置文件你改的是 A 实例的配置连的是 B 实例。我个人的习惯是改完配置后立刻用INFO server确认一遍config_file再看一眼CONFIG GET bind和CONFIG GET protected-mode的运行时值。三个值都对了再去排查网络能省掉一大半无用功。4. 三种部署形态的落地改法手工启动、systemd 托管、Docker 容器配置项搞清楚了接下来按部署方式讲具体改法。之所以要分开讲是因为这三种形态下配置文件在哪里和参数有没有被覆盖的答案完全不同。4.1 源码安装或手工启动这种方式最直接Redis 读什么完全取决于你启动时给什么参数。标准流程# 1. 编辑配置文件 vim /usr/local/redis/redis.conf # 需要改动的关键行 # bind 0.0.0.0 # protected-mode yes # requirepass YourStrongPasswordHere # daemonize yes # 2. 启动 /usr/local/redis/bin/redis-server /usr/local/redis/redis.conf # 3. 确认监听地址 ss -lntp | grep 6379一个实操心得启动时加上配置文件的绝对路径。redis-server如果不带参数启动会用内置的默认配置等于你辛苦改的文件根本没被读。而且默认配置下daemonize是 no进程会占着终端加上又容易搞不清 PID。带上路径并且配daemonize yes才是能长期跑起来的形态。还有一个细节daemonize yes之后日志默认是写到文件而不是终端的由logfile决定。如果logfile是空字符串日志会输出到/dev/null也就是什么都看不到。排查启动问题时我会临时把它设成一个具体路径比如/var/log/redis/redis.log一眼就能看到启动过程中的报错。4.2 systemd 托管下的改法与覆盖坑用包管理器装的 Redisapt install redis-server或yum install redis基本都走 systemd 托管。配置文件通常在/etc/redis/redis.confDebian 系或/etc/redis.conf部分 RHEL 系启动单元在/lib/systemd/system/redis-server.service或/usr/lib/systemd/system/redis.service。改完配置之后systemctl restart redis-server # 或 redis看发行版 systemctl status redis-server这里最大的坑是systemd 的 unit 文件里可能用命令行参数覆盖配置文件。打开 unit 文件看ExecStart那一行有时候会写成这样ExecStart/usr/bin/redis-server /etc/redis/redis.conf --bind 127.0.0.1这种情况下你在redis.conf里怎么写bind都没用命令行参数优先级更高。这种参数被覆盖的坑在自动生成的 unit 文件、云平台定制的镜像里尤其常见。排查方法还是那个ps -ef | grep redis-server看完整的启动命令行。如果修改了 unit 文件本身记得执行systemctl daemon-reload systemctl restart redis-server漏掉daemon-reload改动不会生效这个错误我犯过不止一次。另外Debian 系的 Redis 包有一层额外的机制/etc/redis/redis.conf里某些配置项经过打包方的预处理比如bind可能会被写成bind 127.0.0.1 ::1而supervised那一行被设成systemd。看到supervised systemd这个值不用改它是告诉 Redis 交由 systemd 管理进程生命周期跟外部访问无关。4.3 Docker 里的 bind 与端口映射容器场景是踩坑重灾区值得单独讲清楚。先说核心结论容器里跑的 Redisbind必须包含0.0.0.0或者容器的那块网卡地址否则宿主机再怎么映射端口也连不上。原因是容器有独立的网络命名空间容器内的127.0.0.1指的是容器自己不是宿主机的回环。如果你把宿主机上的配置文件直接挂载进容器里面还写着bind 127.0.0.1那么容器内的 Redis 只监听容器自己的回环宿主机的端口映射Docker 的-p走的是 DNAT打进来会被拒绝表现为Connection reset或者干脆 timeout。一个能用的启动命令长这样docker run -d --name redis-01 \ -p 6379:6379 \ -v /data/redis/redis.conf:/usr/local/etc/redis/redis.conf \ -v /data/redis/data:/data \ redis:7-alpine \ redis-server /usr/local/etc/redis/redis.conf对应的容器内配置文件需要包含bind 0.0.0.0 protected-mode yes requirepass YourStrongPasswordHere appendonly yes dir /data用 docker-compose 的话services: redis: image: redis:7-alpine container_name: redis-01 restart: always ports: - 127.0.0.1:6379:6379 # 只映射到宿主机回环最安全 # - 6379:6379 # 映射到所有宿主机网卡注意风险 volumes: - ./redis.conf:/usr/local/etc/redis/redis.conf:ro - ./data:/data command: [redis-server, /usr/local/etc/redis/redis.conf]这里给你三个我总结出来的经验点第一端口映射的目标地址决定暴露范围。写-p 6379:6379是映射到宿主机所有网卡写-p 127.0.0.1:6379:6379是只映射到宿主机回环。如果你的 Redis 只是给宿主机上的应用用后面这种写法是更好的选择——外面怎么扫都扫不到因为宿主机回环根本不在公网可达范围内。第二挂载配置文件要设成只读:ro。防止容器内的CONFIG REWRITE把它改乱了导致下次重启行为和你的预期不一致。第三容器里的dir一定要指向挂载出来的数据卷。常见错误是没改dir数据写在容器的可写层容器一删数据全没。不过这属于持久化的范畴跟连通性无关顺便提一句。如果你是用docker network create建的自定义网络容器间互连可以用容器名当主机名比如redis://redis-01:6379这时候bind 0.0.0.0依然是必须的因为 Docker 内置 DNS 解析出来的是容器的网络地址不是回环。5. 配置改完还是连不上按网络分层逐级排查到这一步配置该改的都改了服务也重启了。如果还是连不上别急着怀疑 Redis问题大概率在网络链路上。这一节讲一套我从下往上、逐层排除的排查方法。5.1 安全组、firewalld、iptables 三层过滤公网机器上从外部进来的包要过好几道关任何一道没开都白搭。第一层是云平台的安全组或网络 ACL。这是最外层也是最多人漏掉的一层。它跟操作系统完全无关你在机器上怎么改防火墙都没用必须在云控制台里配置入方向的规则放行 TCP 6379。强烈建议这里只放行具体的来源 IP不要图省事写成0.0.0.0/0。第二层是 firewalldCentOS 7 / RHEL 系默认。常用命令# 放行单个来源 IP firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.10 port protocoltcp port6379 accept firewall-cmd --reload # 查看规则是否生效 firewall-cmd --list-all第三层是 iptables很多云镜像里依然存在。注意一条经验iptables 和 firewalld 不要同时手工维护因为 firewalld 底层就是 iptables两套规则叠加会互相干扰。选一套用到底。# iptables 写法 iptables -I INPUT -s 203.0.113.10 -p tcp --dport 6379 -j ACCEPT # 注意要先放行已建立连接再写拒绝规则顺序很重要 service iptables save一个很典型的坑Docker 会自己往 iptables 的DOCKER-USER链或nat表里插规则。如果你在宿主机上用 iptables 限制了 6379但容器是通过 Docker 的端口映射暴露的那么流量实际上是在nat表的PREROUTING阶段就被 DNAT 到容器了根本走不到你写的那条INPUT规则上。这种情况下要限制访问得写在DOCKER-USER链里或者干脆用-p 127.0.0.1:6379:6379从映射层面就限制死。这个坑我印象很深当时花了一整个下午才想明白为什么防火墙规则看起来生效了但实际没用。5.2 用 nc 和 telnet 把问题定位到具体一层排查的核心思路是从最近的地方开始一层一层往外走每一步只验证一件事。# 第 1 步服务端本机回环验证 Redis 进程本身活着 redis-cli -h 127.0.0.1 -p 6379 PING # 期望PONG 或者 NOAUTH Authentication required # 第 2 步服务端本机走内网/公网 IP验证 bind 是否包含这块网卡 redis-cli -h 172.16.10.21 -p 6379 PING # 期望同上如果 refused说明 bind 没包含这个地址 # 第 3 步客户端机器上测 TCP 层可达性 nc -vz 172.16.10.21 6379 # 或者 telnet 172.16.10.21 6379 # 期望succeeded / Connectedtimeout 说明被防火墙挡了 # 第 4 步在客户端机器上真正执行业务命令 redis-cli -h 172.16.10.21 -p 6379 -a YourStrongPasswordHere PING这四步的价值在于它把连不上这个大问题拆成了四个能独立回答的小问题。第 1 步失败说明 Redis 都没起来跟网络无关第 1 步成功第 2 步失败说明是bind的问题第 2 步成功第 3 步失败说明是防火墙或安全组第 3 步成功第 4 步失败说明是认证或 ACL。每一步都能把排查范围砍掉一半。nc -vz这个组合我强烈推荐-v输出详细信息-z只扫描不发数据比 telnet 更好用因为 telnet 的报错文字经常含糊不清。5.3 几种典型症状的成因对照把常见的报错和成因整理成一张表遇到问题直接对照症状最可能的成因优先检查本机127.0.0.1都连不上Redis 进程未启动、端口被改、崩溃systemctl status、ss -lntp、日志本机 IP 连不上回环能连bind没包含该地址CONFIG GET bindnc超时安全组未放行、iptables DROP、路由问题云控制台、iptables -L -nnc成功但 Redis 报 DENIEDprotected mode 生效且没设密码CONFIG GET protected-mode、CONFIG GET requirepass报NOAUTH服务端有密码客户端没带客户端连接配置报WRONGPASS密码不一致或配置里特殊字符被截断用CONFIG GET requirepass对比需先认证Docker 环境全都不通容器内bind还是回环地址进入容器ss -lntp容器重启后配置失效配置未挂载写在容器可写层docker inspect看 Mounts最后一行那个坑我想多说一句。很多人调试的时候直接docker exec -it redis-01 bash进去改/usr/local/etc/redis/redis.conf改完重启容器发现配置又回去了。原因就是这个文件在容器的可写层里容器停止后如果没配持久化卷重建时用的是镜像里的原始文件。在容器里改配置永远要改挂载出来的那个宿主机文件。6. 打开外网访问之后怎么把它管住连通性只是起点。真正见功夫的是连通之后怎么让这个口子开得可控。这一节聊几个成本低、收益明显的收敛手段。6.1 白名单和改端口成本最低的两件事白名单前面已经说过就是在安全组和防火墙两个层面都只放行来源 IP。这里补充一个实践建议写白名单的时候别只写单个 IP而是写一个明确的网段比如办公区的出口网段。这样同事换机器不用重新申请。同时保留一条注释写明这个网段是干什么用的半年后回来看才不至于一脸茫然。改端口是另一件几乎零成本的事。把 6379 改成一个不常见的高位端口比如 16379 或 26379 之外的自定义值port 16379它带来的好处很直接全网扫描器默认扫 6379改了端口之后能被自动扫到的概率会大幅下降。当然这不是安全措施只是降低噪音。要记住改端口之后客户端连接、bind相关验证、防火墙规则、监控探针、Docker 端口映射全都要跟着改容易漏。我建议把它作为一次性的规划动作在实例创建时就定好不要等上线后临时改。6.2 重命名和禁用高危命令这是一条被很多人忽略、但性价比极高的措施。Redis 支持在配置文件里给命令改名rename-command FLUSHALL rename-command FLUSHDB rename-command CONFIG CONFIG_9f3a2c rename-command KEYS 写空字符串等于禁用该命令。这样做的好处是即使密码泄露攻击者能造成的破坏也被限制住了——没有CONFIG就没法改dir和dbfilename没有FLUSHALL数据清理就得多费一番手脚。不过要提醒两点第一rename-command改名后主从复制、集群命令、一些客户端库的内置操作可能受影响最典型的是CONFIG很多运维脚本和监控组件依赖它改名之后要同步调整。第二重命名之后原命令就彻底不存在了别指望能从客户端用别名调回来。我一般只禁用FLUSHALL、FLUSHDB、KEYS这三个CONFIG保留但改成难猜的名字并且确认监控脚本不受影响。在 Redis 6 的 ACL 体系下其实有更优雅的做法直接给业务账号分配命令白名单。比如只允许读写 string 和 hash 类型其他一律拒绝。这种方式比rename-command更细粒度也更符合最小权限原则但配置复杂度上升看团队运维成熟度决定用不用。6.3 长期维护时值得盯的几个点配置改完不是终点跑起来之后有几个指标值得定期看连接数INFO clients里的connected_clients。外网开放之后连接数异常上涨往往意味着有人在扫或者有客户端没做好连接池复用。拒绝连接数INFO stats里的rejected_connections配合maxclients一起看。如果它一直在涨说明连接池配置有问题。慢查询SLOWLOG GET 10。外网访问天然比内网延迟高一些在高延迟下会变成慢查询的操作比如大 key 的HGETALL会浮现出来。日志里的认证失败定期grep一下日志中的WRONGPASS或AUTH相关记录能发现异常扫描的迹象。还有一个容易忽视的点是密码轮换。requirepass换密码需要重启或者CONFIG SET配合CONFIG REWRITE而重启会中断连接。如果业务不能接受中断就得走双密码过渡的方案——Redis 6 的 ACL 支持给同一用户配多个密码可以先加新密码等所有客户端切换完再删旧密码。这个思路在做变更时很实用。6.4 更稳妥的替代路径最后说点实在的。如果你的真实需求只是偶尔从本地连一下开发环境的 Redis那其实有一条比开放公网简单得多、也安全得多的路用 SSH 端口转发把远程的 6379 临时映射到本地。ssh -L 16379:127.0.0.1:6379 useryour-server这条命令执行之后本地连127.0.0.1:16379就等价于连服务器上的127.0.0.1:6379。服务端 Redis 保持默认的bind 127.0.0.1不变防火墙不用开安全组不用动公网上不留任何额外端口。用完关掉终端就行。这个方案的好处是零暴露面缺点是只适合人在电脑前的场景不适合常驻的服务调用。但对于开发调试、临时数据查看这类需求我觉得它比把 Redis 开放到公网优雅太多。我在好几个团队都推过这个做法刚开始有人嫌麻烦用过一次之后就都改口了——毕竟少一次安全事件省下的时间远超敲那一条命令的成本。如果你的场景确实是常驻的跨网络调用那再考虑前面讲的完整方案绑指定网卡、设强密码、加白名单、改端口、禁用高危命令。这几件事都做到位Redis 的外网访问就不是一个需要提心吊胆的口子了。我个人这些年操作下来最深的体会是Redis 的连通性问题90% 的时间都花在确认到底是哪一层在拦上而不是在解决上。先分清 refused 还是 timeout先确认服务真正加载的是哪个配置文件、真正监听的是哪块网卡剩下的基本都是按图索骥。真正需要警惕的不是连不上的时候而是某一天你随手把protected-mode设成 no、把bind写成 0.0.0.0、还顺手关掉了防火墙结果它安安静静地连上了——那种顺畅往往才是问题的开始。
返回列表