相信不少人在装 Erlang 或者 RabbitMQ 的时候,都被这么一行红字卡住过:
libcrypto.so.10(OPENSSL_1.0.2)(64bit) is needed by erlang-22.0.7-1.el7.x86_64我第一次看到这行报错时,第一反应是去重装 Erlang,结果换了好几个版本,提示一字不差。后来才明白,问题根本不在 Erlang,而是它依赖的 OpenSSL 1.0.2 这个老版本库没有就位。这个坑,在 CentOS 7 停止维护之后特别容易踩,尤其是当你手里只有一个 minimal 镜像、yum 源还失效的时候,那叫一个酸爽。
这个报错本质上是一个典型的 Linux 依赖解析问题。它不挑人,新手会碰到,老手在 CentOS Stream、RHEL 9 上装老包时一样会碰到。这篇文章我会从报错信息本身的含义讲起,给你一套从“源失效”到“依赖满足”再到“Erlang 成功跑起来”的完整操作路径,同时把那些网上很少讲透的细节,比如符号版本、软链接为什么不能用、i686 和 x86_64 的坑,一次说清楚。
1. 报错拆解:先搞清楚这行红字到底在说什么
1.1 三块拼图:libcrypto.so.10、OPENSSL_1.0.2、64bit
先别急着上网找“修复包”,把这行报错拆开看,其实就三块信息。
libcrypto.so.10 是 OpenSSL 1.0.x 的共享库文件名。在 Linux 下,OpenSSL 1.0.x 编译出来的加密库叫 libcrypto.so.10 和 libssl.so.10,后面的 .10 叫 SONAME 版本号。OpenSSL 1.1.x 对应的是 libcrypto.so.1.1,OpenSSL 3.x 对应的是 libcrypto.so.3。所以当系统里只有 OpenSSL 1.1.1 或 3.0 时,是不会有 libcrypto.so.10 这个文件的。
括号里的 OPENSSL_1.0.2 是符号版本标记。这个容易被人忽略,却是最容易翻车的地方。它在编译时被写进二进制文件里,相当于一份 API 契约:Erlang 编译时用的 OpenSSL 版本是 1.0.2,那么运行时要求动态库里必须存在 OPENSSL_1.0.2 这一组符号版本。你可以把它理解成“库提供方承诺支持的接口版本号”,不太准确但好记。
64bit 表示需要的是 x86_64 位架构的库。如果系统里只装了一个 i686 的 libcrypto.so.10,rpm 依然会报错,因为架构不匹配。这也是很多人安装了“看起来对的包”却依然失败的原因。
1.2 Erlang 只是受害者:依赖链的真相
很多人看到“is needed by erlang”就以为 Erlang 坏了,其实 Erlang 是无辜的。
Linux 的 rpm 包管理器在安装软件时,会读取这个包里的 Require 依赖声明。erlang-22.0.7-1.el7.x86_64 这个包在构建时,编译环境里的 OpenSSL 是 1.0.2,于是 rpm 打包工具就把 libcrypto.so.10(OPENSSL_1.0.2)(64bit) 写进了依赖列表。安装时,包管理器去系统里找这个库文件,找不到,就中断安装。
我把这个报错截图上给我一个刚入行的同事看,他说了一句:“这不就是个 DLL 缺失吗?” 虽然 Windows 和 Linux 在机制上有差异,但这个类比很贴近。你可以把 libcrypto.so.10 理解成 Windows 里的某个 DLL,把安装 Erlang 理解成运行某个软件时提示缺少 DLL。只不过 Linux 的依赖检查更严格,在安装阶段就直接拦下来,不会等你运行时报错。
1.3 什么环境最容易踩到这个坑
结合我自己的经历和网上大量求助帖,最容易出这个报错的是下面几种场景:
- 在 CentOS Stream 8/9、RHEL 8/9 或其它新系统上,直接安装 el7 的 Erlang rpm 包。系统 OpenSSL 版本是 1.1.1 或更高,完全没有 libcrypto.so.10。
- CentOS 7 系统里的 OpenSSL 被第三方源升级到了 1.1.1。虽然有部分兼容库,但老版本 Erlang 仍然找不到 OPENSSL_1.0.2 符号版本。
- CentOS 7 minimal 安装后 yum 源失效。想装 epel 或者 rabbitmq 的依赖,结果源本身都起不来,更别提装兼容库了。
- 用 Docker 拉了 centos:7 镜像之后,又额外拷贝了别的系统里的库文件。这种环境 I 见得太多了,镜像里缺库,但主机上又“看起来有”,最后全乱套。
如果你符合其中任何一种,下面两章的内容应该能直接帮你解决问题。
2. 从根上想办法:恢复可用的 Yum 源比什么都重要
2.1 为什么 CentOS 7 的源会集体失效
CentOS 7 在 2024 年 6 月 30 日到达生命周期终点(EOL)之后,官方在 mirror.centos.org 上就不再提供 7 的更新内容。如果你机器上还保留着默认的 CentOS-Base.repo,里面用的是 mirrorlist=...centos.org,那么运行 yum 的时候就会收到:
Cannot find a valid baseurl for repo: base/7/x86_64这个报错的热度非常高,因为大量老机器还在跑 CentOS 7。解决思路很简单:把源地址从 mirrorlist 改成 vault.centos.org,也就是 CentOS 的版本存档仓库。vault 里的包会一直保留,不会因为 EOL 就消失。
2.2 一套可用的 vault 源配置方案
直接把 /etc/yum.repos.d/CentOS-Base.repo 改成下面这样,是最稳妥的做法。我建议先备份原文件:
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak然后用你熟悉的编辑器打开,改成:
[base] name=CentOS-$releasever - Base baseurl=https://vault.centos.org/7.9.2009/os/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 [updates] name=CentOS-$releasever - Updates baseurl=https://vault.centos.org/7.9.2009/updates/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 [extras] name=CentOS-$releasever - Extras baseurl=https://vault.centos.org/7.9.2009/extras/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7这里有个细节要提醒:不要用 CentOS Stream 9 的 baseos 地址来填。网络上一些教程会直接写 mirrors.tuna.tsinghua.edu.cn/centos-stream/9-stream/baseos/x86_64 这样的路径,如果你把这种地址塞给 CentOS 7,yum 虽然能连上服务器,但拿到的包版本、GPG key 都和 7 不匹配,最后会引发更多依赖问题。vault 目录下的 7.9.2009 才是 7 系的存档,路径不能混。
改完后,还要处理一下 SCL 源。很多 CentOS 7 机器上有 centos-sclo-rh 和 centos-sclo 这两个源文件,EOL 之后它们也跟着失效,报错就是:
Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64这个源和我们要装的 compat-openssl10 没关系,直接禁用最省心:
sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/CentOS-SCLo-scl.repo /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo最后清理缓存,让 yum 重新拉取元数据:
yum clean all yum makecachemakecache 成功输出“Loaded plugins... base/7/x86_64 ... 157 MB”之类的内容,就说明源已经活了。这一步虽然不直接解决 OpenSSL 报错,但它是所有后续操作的基础。没有可用源,后面全白搭。
2.3 顺带验证一下系统现状
在动手装任何东西之前,先花一分钟确认系统状态。这几条命令我每次都会敲一遍,属于基本操作:
cat /etc/os-release uname -m rpm -qa | grep openssl ldconfig -p | grep libcrypto如果是 x86_64 架构,输出里应该是 openssl-libs、openssl 等包。如果 ldconfig 的输出里只有 libcrypto.so.1.1 或 libcrypto.so.3,没有 libcrypto.so.10,那结论就很清晰:系统里缺少 OpenSSL 1.0.x 兼容库。
3. 安装 compat-openssl10:让你少折腾 90% 的首选方案
3.1 三行命令搞定 yum 安装流程
源修好之后,最省事的做法是直接用 yum 安装 compat-openssl10 这个包。它在 CentOS 7 官方源里一直存在,用途就是提供 OpenSSL 1.0.x 的兼容库,让老软件能继续跑。
yum -y install compat-openssl10这个包安装完成后,会往系统里放两个关键文件:
- /usr/lib64/libcrypto.so.10
- /usr/lib64/libssl.so.10
注意,不要自己去网上随便下载“openssl-1.0.2k”之类的源码包去编译。虽然编译也能得到 libcrypto.so.10,但你在 CentOS 7 上手动编译 OpenSSL 1.0.2 会有另一个坑:它默认安装到 /usr/local/ssl,而且一堆老补丁没有打上,编译参数也未必和 rpm 一致,后面很容易出现版本符号对不上的诡异问题。用官方 compat 包是最干净的。
如果你执行 yum install 之后,提示“No package compat-openssl10 available”,多数情况下就是源没有刷成功。先跑一遍 yum clean all && yum makecache,确认 makecache 没有报错,再装一次。如果还不行,用 yum search openssl10 看看源里有哪些包可用。
3.2 验证库文件是否真正到位
安装完不要急着装 Erlang,先验证库是否真的生效。这是很多人跳过的步骤,跳过之后就得来回折腾排查。
ls -l /usr/lib64/libcrypto.so.10这一步确认文件存在。接着用 rpm 确认它属于哪个包:
rpm -qf /usr/lib64/libcrypto.so.10输出应该是 compat-openssl10-1.0.2o-3.el7_9.x86_64 之类的包名。再深入一层,检查符号版本列表里有没有 OPENSSL_1.0.2:
strings /usr/lib64/libcrypto.so.10 | grep OPENSSL_1.0.2如果你看到 OPENSSL_1.0.2 这行输出,说明符号版本没问题。这个验证非常重要,因为我见过有人系统里同时存在多个 OpenSSL 库文件,结果 yum 装的是老库,Erlang 运行时加载的却是别的路径下的新库。这种混乱状态要用 ldconfig -p | grep libcrypto 来看全局搜索路径下到底有哪些库。
3.3 再把 Erlang 装上:完整复现过程
库就位后,回到最初的报错场景。假设你已经下载了 erlang-22.0.7-1.el7.x86_64.rpm 这个文件,建议用 yum 而不是 rpm 来安装,让 yum 自动解析剩余的依赖:
yum -y install ./erlang-22.0.7-1.el7.x86_64.rpm注意我写的是 ./erlang-22.0.7-1.el7.x86_64.rpm,这样 yum 会把它当成一个本地文件包来解析。如果还缺别的依赖,yum 会从前面修好的 vault 源里自动拉取。
安装成功后,验证 Erlang 能否正常加载 OpenSSL 相关模块:
erl -version如果想更严格一点,可以用一个简单的 Erlang 表达式测试加密模块:
erl -eval 'io:format("~s~n", [erlang:system_info(otp_release)]), halt().'如果输出 22,说明 Erlang 22 已经能正常跑起来。这里有个容易被忽略的点:Erlang 的加密模块 crypto 在启动时会动态加载 libcrypto.so.10,如果加载失败,erl 虽然能启动,但调用 crypto 模块时会报 undef。所以最好连 crypto 模块一起测:
erl -eval 'io:format("~p~n", [crypto:supports()]), halt().'能输出一个包含 ciphers、hashes 等信息的 map,才算真的万事大吉。
4. 源彻底不可用时:手工下载 rpm 的兜底路线
4.1 从哪里找对的 rpm 包
有时候场景比较极端:机器不能联网访问 vault,或者公司内网只有指定镜像可用。这种情况下,手工下载 rpm 包再本地安装就是必须掌握的一招。
compat-openssl10 对应 rpm 包的官方存档地址是:
https://vault.centos.org/7.9.2009/os/x86_64/Packages/compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm如果你在清华镜像或者阿里云镜像上找,路径类似,但要注意目录层级。以清华镜像为例:
https://mirrors.tuna.tsinghua.edu.cn/centos-vault/7.9.2009/os/x86_64/Packages/compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm下载命令:
wget https://vault.centos.org/7.9.2009/os/x86_64/Packages/compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm下载完以后,用 rpm -ivh 或者 yum localinstall 安装都行。我个人更推荐 yum localinstall,因为它会自动检查并尝试解析缺失的依赖:
yum localinstall ./compat-openssl10-1.0.2o-3.el7_9.x86_64.rpm如果你的系统上还缺其它基础依赖,yum 会一并告诉你,你只要继续用 vault 源补齐就行。
4.2 先看依赖再动手,别等到最后一步才发现缺包
这里分享一个我踩过几次坑之后养成的习惯:无论安装哪个 rpm 包,先查它的依赖再安。尤其是老包,依赖往往不止一个。
rpm -qpR erlang-22.0.7-1.el7.x86_64.rpm这条命令会列出这个包所依赖的所有文件、库和包名。输出里你会看到除了 libcrypto.so.10(OPENSSL_1.0.2)(64bit) 之外,还可能有一堆 libstdc++.so.6、libncurses.so.5 之类的依赖。提前知道就能一次性把该装的装齐,不用等 rpm 报一个错再装一次。
如果只想检查某一个依赖项是否被满足,可以用:
rpm -q --whatprovides 'libcrypto.so.10(OPENSSL_1.0.2)(64bit)'有输出说明系统里已经有包可以满足这个依赖,没输出就说明还缺。这个命令在排查“我明明装了 compat 包为什么还报错”的问题时特别好用。
4.3 为什么不能随便用软链接糊弄过去
网上有一种“野路子”,让人直接把新版库软链成老库名字:
ln -s /usr/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.10我必须说,这条路十有八九走不通,而且会让问题更隐蔽。
原因还是回到前面说的符号版本。OpenSSL 1.1.x 的库文件里,符号版本名称是 OPENSSL_1_1_0、OPENSSL_1_1_1 这些,没有 OPENSSL_1.0.2。你拿 libcrypto.so.1.1 去冒充 libcrypto.so.10,文件是有了,rpm 依赖检查这一关也可能蒙混过去,但 Erlang 一启动,动态加载器找 OPENSSL_1.0.2 符号版本时就会直接报:
version `OPENSSL_1.0.2' not found这是运行时错误,比安装时报错更难排查。我帮人处理过一个这样的案例,对方软链完以后 Erlang 能安装成功,但一跑 RabbitMQ 就崩溃,排查了两天才发现问题在软链上。
所以我的建议是:除非只是临时验证,否则绝对不要用软链接代替真正的兼容库包。你要的是 compat-openssl10 提供的那个带 OPENSSL_1.0.2 符号版本的真库,不是一个同名空壳。
5. 实测中经常翻车的几个细节
5.1 32 位和 64 位依赖混装
前面提到过 64bit 这个关键词,这里展开讲一下。
CentOS/RHEL 的库目录分两个:/usr/lib 放 32 位库,/usr/lib64 放 64 位库。如果你装了一个 i686 的 compat-openssl10,文件会落在 /usr/lib/libcrypto.so.10,而 Erlang 找的是 /usr/lib64/libcrypto.so.10,位置不对,一样报错。
排查命令很简单:
ls -l /usr/lib/libcrypto.so.10 /usr/lib64/libcrypto.so.10如果你看到 i686 的包装到了系统里,卸载掉重新装对架构:
rpm -qa | grep compat-openssl rpm -e compat-openssl10-1.0.2o-3.el7_9.i686然后重新安装 x86_64 版本。这个坑在 Docker 镜像里特别常见,因为有些基础镜像为了兼容性会默认带上 32 位库。
5.2 装完兼容库依然报错的排查清单
我自己调试这类问题的时候,会按一套固定的流程走,这里整理成一张速查表,方便你对照排查。
| 现象 | 可能原因 | 排查方法 | 解决方式 |
|---|---|---|---|
| yum install compat-openssl10 提示无此包 | yum 源没生效或缓存过期 | yum clean all && yum makecache | 重新配置 vault 源后重试 |
| 报 base/7/x86_64 找不到 baseurl | CentOS 7 源失效 | cat /etc/yum.repos.d/CentOS-Base.repo | 改用 vault.centos.org 地址 |
| 报 centos-sclo-rh/x86_64 找不到 | SCL 源失效 | ls /etc/yum.repos.d/ | 删除或禁用 sclo 相关 repo |
| 安装后仍提示需要 libcrypto.so.10 | 装了 i686 库或文件路径不对 | ls /usr/lib64/libcrypto.so.10 | 卸载 i686 包,装 x86_64 包 |
| Erlang 启动报 OPENSSL_1.0.2 not found | 用过软链接或库符号版本不符 | strings /path/to/libcrypto.so.10 | grep OPENSSL_1.0.2 | 卸载软链接,安装官方 compat 包 |
| erlang 报其它缺失依赖 | 老包依赖链长,缺 libstdc++ 等 | rpm -qpR erlang...rpm | 用 yum install ./erlang...rpm 自动补齐 |
| yum makecache 卡住或速度慢 | 网络限制访问 vault | 换国内镜像源 | 使用清华、阿里镜像的 centos-vault 路径 |
这张表基本覆盖了我见过的 90% 报错场景。如果你按表排查完还没解决,大概率是系统里有多套 OpenSSL 共存导致的混乱,建议用ldd直接看 Erlang 二进制实际加载的是哪个路径的库:
ldd /usr/lib64/erlang/bin/beam.smp | grep crypto输出里会明确显示加载的 libcrypto 路径,如果指向了错误路径,问题就很容易定位了。
5.3 不要一上来就 --nodeps 强装
还有一个非常常见的错误操作是看到依赖报错后,直接 rpm -ivh --nodeps erlang-22.0.7-1.el7.x86_64.rpm 强装。
我理解这种操作的冲动,但强烈建议别这么干。--nodeps 会绕过依赖检查,让包安装成功,但系统里的依赖问题并没有消失,只是被推迟到了运行期。Erlang 装上以后,crypto 模块加载失败,RabbitMQ 起不来,到时候报错信息更隐蔽,排查成本更高。
正确的操作顺序永远是:先满足依赖,再安装本体。依赖检查是保护机制,不是故意给你添堵的。
6. 另外几个我在生产环境里摸索出来的习惯
这次写下来,感觉最值得分享的不只是命令,而是排查这类问题的思路。
踩过几次坑之后,我现在遇到安装报错,第一反应永远是先看两样东西:系统源状态和依赖树。很多人在网上盲目搜索“erlang 装不上”,其实问题要么出在 yum 源失效,要么出在缺少兼容库。把源修好,再理清依赖关系,剩下的事情就非常机械了。
最后再分享一个小技巧。如果你是在容器环境里遇到同样的问题,直接用带 OpenSSL 1.0.x 兼容层的基础镜像,或者干脆在 Dockerfile 里加上RUN yum -y install compat-openssl10,比每次进容器手工处理要省心得多。如果是 Ubuntu/Debian 系统被迫运行 el7 的包,也可以找 libssl1.0.0 或 libssl1.0.2 这类老版本库来满足依赖,思路是一样的。但在 x86_64 的 CentOS 系系统上,compat-openssl10 依然是最省事、最干净的答案。