在 CentOS 7 上从源码编译 Python 3.9 时,经常遇到 SSL 模块无法导入的问题,导致 pip 无法使用 HTTPS 源,甚至影响 Ansible 等工具的正常运行。本文汇总了常见错误信息,分析了根本原因,并提供了一套经过验证的完整解决方案,最终给出可直接使用的安装脚本。
1. 报错信息汇总
1.1 编译后无法导入 ssl 模块
>>> import ssl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.9/ssl.py", line 98, in <module>
import _ssl
ModuleNotFoundError: No module named '_ssl'
1.2 pip 操作提示 SSL 不可用
WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available."))
1.3 Ansible 执行时因 SSL 问题失败
fatal: [192.168.233.128]: FAILED! => {"changed": false, "msg": "SSL validation is not available in your version of python. You can use validate_certs=False, however this is unsafe and not recommended"}
1.4 其他常见依赖缺失
- •
zipimport.ZipImportError: can't decompress data; zlib not available - • 编译时提示找不到 OpenSSL 头文件或库
2. 问题原因分析
- • Python 3.9 要求 OpenSSL 1.1.1 或更高版本 ,而 CentOS 7 系统默认的 OpenSSL 版本为 1.0.2,且系统自带的
openssl-devel包仅提供 1.0.2 的头文件和库。 - • 即使通过 EPEL 安装了
openssl11-devel,由于系统默认的编译环境和链接器仍会优先查找/usr/include和/usr/lib64下的旧版本,导致 Python 的configure脚本找不到正确的 OpenSSL 1.1.1,或者找到的是不兼容的旧版本,最终无法编译出_ssl模块。 - • 简单指定
--with-openssl=/usr/include/openssl11并不足够,因为该目录下没有完整的库文件结构(缺少lib子目录),且运行时链接可能依然指向旧库。
3. 解决方案
核心思路 :安装 OpenSSL 1.1.1 开发包,并通过 pkg-config 获取正确的编译和链接标志,将其传递给 Python 的构建系统。
3.1 安装 OpenSSL 1.1.1 开发包
CentOS 7 可以通过 EPEL 仓库安装 openssl11-devel,该包会提供 OpenSSL 1.1.1 的头文件、库文件以及 pkg-config 配置文件(openssl11.pc)。
sudo yum install -y epel-release
sudo yum install -y openssl11 openssl11-devel
3.2 使用 pkg-config 设置编译环境变量
在运行 Python 的 ./configure 脚本之前,导出 CFLAGS 和 LDFLAGS 环境变量,让编译器和链接器知道去哪里找 OpenSSL 1.1.1 的头文件和库。
export CFLAGS="$CFLAGS $(pkg-config --cflags openssl11)"
export LDFLAGS="$LDFLAGS $(pkg-config --libs openssl11)"
pkg-config --cflags openssl11 会输出类似 -I/usr/include/openssl11 的选项,而 --libs 会输出 -L/usr/lib64/openssl11 -lssl -lcrypto 等。这样 Python 的构建系统就能正确找到 OpenSSL 1.1.1。
3.3 配置并编译 Python
执行配置时不需要 再使用 --with-openssl 参数,因为环境变量已经指定了路径。
./configure --enable-optimizations --prefix=/usr/local/python3.9
make -j$(nproc)
sudo make altinstall
3.4 验证 SSL 模块
安装完成后,验证 SSL 模块是否可用:
/usr/local/python3.9/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
如果输出 OpenSSL 1.1.1 的版本号,则成功。
4. 完整版安装脚本
以下脚本整合了所有步骤,可直接复制粘贴到 CentOS 7 系统中执行(以 root 用户或使用 sudo)。
#!/bin/bash
# CentOS 7 编译安装 Python 3.9 并启用 SSL 模块
set -e # 遇到错误立即退出
# 1. 安装系统依赖和 OpenSSL 1.1.1
yum install -y epel-release
yum groupinstall -y "Development Tools"
yum install -y openssl11 openssl11-devel \
zlib-devel bzip2-devel ncurses-devel sqlite-devel \
readline-devel tk-devel libffi-devel expat-devel gdbm-devel
# 2. 下载 Python 3.9 源码
cd /opt
wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tar.xz
tar -xf Python-3.9.0.tar.xz
cd Python-3.9.0
# 3. 设置环境变量,使编译器和链接器能找到 OpenSSL 1.1.1
export CFLAGS="$CFLAGS $(pkg-config --cflags openssl11)"
export LDFLAGS="$LDFLAGS $(pkg-config --libs openssl11)"
# 4. 配置、编译、安装
./configure --enable-optimizations --prefix=/usr/local/python3.9
make -j$(nproc)
make altinstall
# 5. 创建符号链接(可选)
ln -s /usr/local/python3.9/bin/python3.9 /usr/local/bin/python3.9
ln -s /usr/local/python3.9/bin/pip3.9 /usr/local/bin/pip3.9
# 6. 验证 SSL 模块
/usr/local/python3.9/bin/python3.9 -c "import ssl; print(ssl.OPENSSL_VERSION)"
echo "Python 3.9 installation completed successfully."
5. 验证与测试
5.1 测试 SSL 导入
python3.9 -c "import ssl; print('SSL module is available')"
5.2 测试 pip 使用 HTTPS 源
pip3.9 install --upgrade pip
应不再出现 SSL 相关警告。
5.3 测试 Ansible 远程执行
在 Ansible 控制节点上,确保 inventory 中指定了解释器路径:
[target]
192.168.233.128 ansible_python_interpreter=/usr/local/python3.9/bin/python3.9
然后执行涉及 HTTPS 下载的任务,应不再报 SSL 验证错误。
6. 常见问题及注意事项
6.1 为什么不用 --with-openssl?
在 Python 3.9 中,--with-openssl 只能指定一个根目录(如 /usr/local/openssl),要求该目录下有 include/ 和 lib/ 子目录。而通过 EPEL 安装的 openssl11-devel 将头文件放在了 /usr/include/openssl11,库文件在 /usr/lib64/openssl11,不符合标准结构。使用 pkg-config 传递标志是更灵活且通用的做法。
6.2 如果 pkg-config 找不到 openssl11
请确保 openssl11-devel 已正确安装,其生成的 .pc 文件通常位于 /usr/lib64/pkgconfig/openssl11.pc。如果 pkg-config 仍找不到,可以设置 PKG_CONFIG_PATH 环境变量:
export PKG_CONFIG_PATH=/usr/lib64/pkgconfig:$PKG_CONFIG_PATH
6.3 关于 zlib 模块缺失
如果同时遇到 zlib 模块缺失,请确保已安装 zlib-devel,并在编译前导出 CFLAGS 和 LDFLAGS 中包含 zlib 的相关路径(通常系统默认路径已包含,无需额外指定)。
6.4 使用 altinstall 避免冲突
始终使用 make altinstall 而不是 make install,以防止覆盖系统自带的 Python 2 或 Python 3 可执行文件,避免破坏系统工具(如 yum)。
6.5 虚拟环境建议
即使编译成功,也建议为项目创建虚拟环境,避免使用 root 权限安装包,并隔离依赖。
结语
通过上述方法,可以在 CentOS 7 上成功编译出带有完整 SSL 支持的 Python 3.9,彻底解决 _ssl 模块缺失的问题。本文提供的脚本已在 CentOS 7.9 上验证通过,可放心使用。如果在实践中遇到其他问题,欢迎反馈交流。

