笔者在一台 CentOS 7.9 服务器上升级 Python 3.10 后,运行 pip3.10 安装依赖库总是报错:
There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443):
WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.
这个错误表明在编译Python 3.10时,SSL模块并未正确构建,或者可能是 openSSL 版本太低导致。尝试运行 openssl version
,服务器返回 openSSL 的版本号:
OpenSSL 1.0.2k-fips 26 Jan 2017
都2024年了,该服务器还用着老旧的 openSSL, 难怪新版本的软件不兼容。为了使SSL模块能正确构建,并且Python编译配置能找到这些库,需要手动更新OpenSSL。
1、下载并编译 OpenSSL:
首先,尝试把 openSSL 从1.0.2k 升级到 1.1.1l,下载并解压 OpenSSL 的源代码,然后编译并安装它。
sudo yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel
cd /usr/src
wget https://www.openssl.org/source/openssl-1.1.1l.tar.gz
tar xzf openssl-1.1.1l.tar.gz
cd openssl-1.1.1l
./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl
make
sudo make install
2、配置环境变量:
上面的命令如果顺利完成安装 OpenSSL ,第二步需要更新系统的环境变量,以便系统能够找到新的 OpenSSL 库和可执行文件。
export LD_LIBRARY_PATH=/usr/local/openssl/lib
export PATH=/usr/local/openssl/bin:$PATH
这样做会将 /usr/local/openssl/bin
添加到 PATH
环境变量,/usr/local/openssl/lib
添加到 LD_LIBRARY_PATH
环境变量中,以确保系统能够找到新的 OpenSSL 可执行文件。
3、验证新版本的 OpenSSL:
运行 openssl version
命令来验证系统是否正在使用新版本的 OpenSSL。
如果一切顺利,这应该显示新安装的 OpenSSL 的版本信息,例如:
OpenSSL 1.1.1l 24 Aug 2021
4、下载 Python 源代码进行编译
cd /usr/src
wget https://www.python.org/ftp/python/3.10.0/Python-3.10.0.tgz
tar xzf Python-3.10.0.tgz
cd Python-3.10.0
export LDFLAGS="-L/usr/lib64"
export CPPFLAGS="-I/usr/include/openssl"
./configure --enable-optimizations --with-openssl=/usr/include/openssl --with-openssl-rpath=/usr/lib64
make altinstall
注:最后一条命令是 make altinstall
,而不是 make install
,目的是为了保留服务器原来的 Python 版本不被覆盖。
5、验证
无论使用哪种方法,都应在编译并安装 Python 3.10 后,验证 SSL 模块是否正确构建:
/usr/local/bin/python3.10 -c "import ssl; print(ssl.OPENSSL_VERSION)"
如果输出了 OpenSSL 版本信息,例如:
OpenSSL 1.1.1l 24 Aug 2021
则说明 SSL 模块已经正确安装。
这样就能愉快地继续使用 pip3.10 install
安装依赖库了。
6、One more thing:下次进入服务器的shell,为什么查看 OpenSSL 的版本号仍然是旧版?上次升级的 OpenSSL 怎么了?
这是因为 Python 和系统使用的 OpenSSL 版本是独立的。你编译安装的 Python 3.10 使用了你手动安装的OpenSSL 1.1.1l,而系统默认的 OpenSSL 版本仍然是1.0.2k。这种情况很常见,尤其是在你手动编译和安装软件时。
以下是导致这种现象的几个原因以及相关解释:
系统OpenSSL vs 自定义OpenSSL
-
系统OpenSSL:系统默认的OpenSSL版本由系统包管理器(如
yum
)管理,通常不会被你手动编译的OpenSSL覆盖。这确保了系统的稳定性,因为很多系统级别的工具和服务依赖于默认的OpenSSL版本。 -
自定义OpenSSL:当你手动编译并安装一个新版本的OpenSSL(如1.1.1l),你可以指定安装目录(例如
/usr/local/openssl
),并且这个版本的OpenSSL可以被特定的软件(如你编译的Python 3.10)使用。
如何让系统使用新的OpenSSL版本
如果你确实需要让系统使用新的OpenSSL版本,这通常不推荐,因为可能会破坏系统依赖项,以下是可能的步骤:
-
备份现有的OpenSSL
在做任何系统级别的更改前,备份现有的OpenSSL库文件:
sudo cp /usr/bin/openssl /usr/bin/openssl.bak sudo cp -r /usr/lib64/openssl /usr/lib64/openssl.bak
-
替换系统的OpenSSL
用新的OpenSSL替换系统的OpenSSL。这一步要非常小心,因为可能会导致系统不稳定或不可用。
sudo mv /usr/bin/openssl /usr/bin/openssl.old sudo cp /usr/local/openssl/bin/openssl /usr/bin/ sudo cp -r /usr/local/openssl/lib/* /usr/lib64/ sudo ldconfig
推荐方法:使用环境变量
为了避免破坏系统,建议在需要的地方使用环境变量指定OpenSSL版本。
-
设置环境变量
在需要的地方设置环境变量:
export LD_LIBRARY_PATH=/usr/local/openssl/lib:$LD_LIBRARY_PATH export PATH=/usr/local/openssl/bin:$PATH
-
验证
重新打开一个终端或shell,确保环境变量生效,然后运行:
openssl version
这种方法不会影响系统默认的OpenSSL版本,但会确保在你指定的环境中使用新的OpenSSL版本。
总结
系统默认的OpenSSL版本和你手动编译安装的OpenSSL版本是独立的。你已经成功让Python 3.10使用新的OpenSSL版本,而系统的OpenSSL版本保持不变。建议在需要的环境中使用环境变量指定新的OpenSSL版本,而不是全局替换系统的OpenSSL版本,以保持系统的稳定性和兼容性。