【硬核干货】uv 配置私有 PyPI 源:从自签名 SSL 证书到 Nginx 自动化部署全流程

1. 前言

在企业内网环境下,为了加速包管理并保护私有组件,搭建私有 PyPI 仓库是必经之路。uv 作为目前 Python 界最快的包管理器,对安全规范(尤其是 SSL 证书)有着极高的要求。

很多同学在配置时会遇到 CaUsedAsEndEntityUnknownIssuer 报错,本文将通过“证书链重构” + “系统级信任”彻底解决这些痛点。


2. 架构原理

在开始之前,我们先看下整体的请求链路。由于 pypi-server 默认不具备公网缓存功能,我们通过 Nginx 转发并配置 Fallback 机制。

Intranet Server

HTTPS

HTTP

302 Redirect

uv Client

Nginx Reverse Proxy

pypi-server

Public PyPI


3. 核心步骤详解

第一步:构建合法的证书体系

uv 报错 CaUsedAsEndEntity 是因为你直接把 CA 当成了服务器证书。正确的逻辑是:CA 签发证书,证书挂载服务。

Sign

Deploy

CA Private Key

CA Root Certificate

Server Certificate: pypi.service

Server Private Key

Nginx SSL Config

执行指令:

# 1. 创建 CA 根证书 (受信任的源头)
openssl genrsa -out MyCA.key 2048
openssl req -x509 -new -nodes -key MyCA.key -sha256 -days 3650 -out MyCA.crt -subj "/CN=MyPrivateCA"

# 2. 生成服务器私钥与签发请求 (CSR)
openssl genrsa -out pypi.key 2048
openssl req -new -key pypi.key -out pypi.csr -subj "/CN=pypi.service"

# 3. 定义扩展文件 (解决 SAN 域名校验问题,uv/Rust 库必查)
echo "subjectAltName=DNS:pypi.service" > ext.ini

# 4. 使用 CA 签发服务器证书
openssl x509 -req -in pypi.csr -CA MyCA.crt -CAkey MyCA.key -CAcreateserial \
-out pypi.crt -days 365 -sha256 -extfile ext.ini

# 5. 合并证书链 (解决浏览器及客户端的证书链补全问题)
cat pypi.crt MyCA.crt > pypi-fullchain.crt

第二步:Nginx 服务端配置

配置 Nginx 以支持 HTTPS 并允许大文件上传(防止 .whl 包上传失败)。

server {
    listen 443 ssl;
    server_name pypi.service;

    ssl_certificate /etc/nginx/ssl/pypi-fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/pypi.key;

    # 限制上传文件大小,避免上传大型包时报错
    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 延长超时时间
        proxy_read_timeout 90;
    }
}

第三步:Linux 客户端系统级信任

这是解决 UnknownIssuer 报错的最优解,直接让 Debian/Ubuntu 系统原生信任你的私有 CA。

# 1. 拷贝根证书到系统路径
sudo cp MyCA.crt /usr/local/share/ca-certificates/my_private_ca.crt

# 2. 更新系统证书库
sudo update-ca-certificates

第四步:uv 全局配置

修改 ~/.config/uv/uv.toml,设置多索引策略。

[[index]]
name = "pypi"
url = "https://pypi.org/simple/"
default = true # 默认去官方找公共包

[[index]]
name = "hb"
url = "https://pypi.service/simple/"

4. 自动化流水线指令

1. 极速构建 (Build)

由于构建后端(如 hatchling)通常在官方源,显式指定源可以避开私有源为空时的重定向开销:

uv build --index-url https://pypi.org/simple

2. 安全发布 (Publish)

# 建议通过环境变量配置认证,避免明文
export UV_PUBLISH_USERNAME="lipo"
export UV_PUBLISH_PASSWORD="your_password"

# 一键上传
uv publish --publish-url https://pypi.service/upload

5. 避坑指南总结

报错信息 根本原因 解决方案
CaUsedAsEndEntity 证书用途定义错误 使用上文的“CA 签发 Server”流程重做证书
UnknownIssuer 客户端不信任颁发者 update-ca-certificates 或设置 UV_CERT_BUNDLE
302 Found 循环 私有源没包且重定向失败 检查 pypi-server -f 参数及网络连通性
Connect Error uv 默认 TLS 库兼容性 export UV_NATIVE_TLS=true 切换至系统 OpenSSL

6. 结语

搭建私有源不仅仅是起一个 pypi-server 进程,更是一次对 TLS/SSL 握手协议自动化运维流程 的实践。希望本文能帮大家在配置 uv 环境时少走弯路!


如果你觉得文章对你有帮助,欢迎 关注、点赞、收藏!
版权声明:本文为博主 lipo8081原创文章,遵循 CC 4.0 BY-SA 版权协议。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐