Erreur check_hostname de pip derrière un proxy : pip ou le tunnel ?
Deux pannes impriment le même message de nom d’hôte de pip derrière un proxy. Distinguez un client obsolète d’un proxy qui re-signe le trafic, puis réparez la bonne couche.
Deux pannes différentes impriment la même trace de pip, et la réparation qui convient à l’une aggrave l’autre. Un client trop ancien pour nommer un hôte tunnélisé a besoin d’une mise à niveau. Un proxy qui re-signe le trafic a besoin d’un certificat racine de confiance, pas d’un rétrogradage. Déterminez lequel des deux vous avez avant de modifier une variable de proxy, car les chemins mènent dans des directions opposées.
Lisez les dernières trames avant de toucher aux réglages
L’endroit où la trace se termine vous dit quelle couche a abandonné. Si les trames finales se trouvent dans le code TLS d’urllib3 embarqué avec pip et que le texte se plaint d’un nom d’hôte, la bibliothèque cliente n’a pas pu terminer une étape de vérification, et c’est un problème de version bien plus souvent qu’un problème de certificat. Si le texte signale plutôt une connexion refusée, un nom de proxy non résolu ou un HTTP 407, le point de sortie du tunnel est en cause et aucune mise à niveau n’y changera rien.
Relevez la version de pip et les variables de proxy dans le même shell qui échoue. Un shell ouvert avant que le tunnel ne monte porte des valeurs différentes d’un shell ouvert après, et la différence entre les deux est souvent tout le diagnostic.
python3 -m pip --version
env | grep -i -E 'proxy|no_proxy'
Quand le client est plus ancien que le tunnel
Les anciennes versions de pip embarquaient une pile HTTPS qui perdait le nom d’hôte de destination une fois la socket enveloppée par un tunnel. Le message check_hostname est ce que cette pile émet lorsqu’elle atteint la vérification sans nom auquel se comparer. Une mise à niveau supprime la panne parce que le client plus récent conserve le nom pendant la poignée de main, et le changement est assez bon marché pour être tenté en premier chaque fois que les trames finales pointent vers du code TLS embarqué.
Si l’index n’est pas joignable depuis la machine qui échoue, récupérez une wheel à jour sur un hôte qui le peut et installez depuis le fichier. Utilisez le nom de fichier que vous avez réellement téléchargé, pas une version copiée d’un billet de blog.
python3 -m pip install --upgrade pip
python3 -m pip install ./pip-24.2-py3-none-any.whl
Quand le proxy re-signe le trafic
Un proxy qui termine TLS et réémet des certificats sous une racine d’entreprise produit une autre erreur : certificate verify failed, et non une plainte sur le nom d’hôte. Cette différence est l’indice, car le client a atteint un serveur puis a rejeté l’identité qu’on lui montrait. La réparation consiste à faire confiance explicitement à cette racine, que ce soit pour une commande ou via la variable PIP_CERT, afin que le client puisse construire une chaîne vers ce que le proxy présente. Ajouter la racine au magasin de confiance du système fonctionne aussi, mais cela change la confiance pour chaque programme de la machine, ce qui est une décision plus lourde que de réparer une installation de paquet.
Gardez --trusted-host comme outil de diagnostic, jamais comme état permanent. Il désactive la vérification que vous cherchiez à conserver, si bien qu’un certificat réellement erroné paraît sain ensuite. Si vous l’avez utilisé pour installer un paquet, retirez-le et réparez la chaîne avant la prochaine version.
Votre propre code Python ignore entièrement la configuration de pip. Un appel requests a besoin du proxy et du bundle passés là où cette session peut les voir, c’est pourquoi le bloc ci-dessous place les deux sur l’objet de session.
pip install --cert /usr/local/share/ca-certificates/corp-root.crt requests
export PIP_CERT=/usr/local/share/ca-certificates/corp-root.crt
s = requests.Session()
s.proxies = {"https": "http://10.20.30.40:8080"}
s.verify = "/usr/local/share/ca-certificates/corp-root.crt"
s.get("https://pypi.org/simple/", timeout=15)
Quand le point de sortie ou le port est faux
Un client tunnel réécrit souvent le proxy système pendant qu’il se connecte, ce qui peut laisser pip pointé vers un hôte qui ne répond jamais sur ce port. Testez le point de sortie avec un client qui n’est pas pip avant de changer un réglage de pip. Si curl échoue avec le même argument de proxy, la panne se situe au-dessus de pip et aucune configuration interne à pip n’aidera.
L’option de commande et les variables d’environnement disent la même chose à des portées différentes : l’option vaut pour une invocation, les variables pour chaque processus lancé ensuite. Ajoutez NO_PROXY pour un index interne afin que le trafic privé de paquets évite le détour par le tunnel.
curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/
pip install --proxy http://proxy.corp.internal:8080 requests
Persistez le réglage et prouvez que le chemin fonctionne
Stockez le proxy dans la configuration propre à pip quand il doit survivre au shell courant, puis relisez ce que pip utilisera vraiment. La sortie de debug nomme le fichier et la variable derrière chaque valeur, ce qui tranche les débats sur la priorité plus vite que la lecture de la documentation.
La vérification utilise délibérément deux clients. La requête de la bibliothèque standard prouve la route et la chaîne de confiance, tandis que le téléchargement prouve que la configuration propre à pip s’accorde avec elles. Quand la première réussit et que le second échoue, la différence est à l’intérieur de pip et non dans le réseau.
pip config set global.proxy http://proxy.corp.internal:8080
pip config debug
python3 -c "import urllib.request as r; print(r.urlopen('https://pypi.org/simple/').status)"
pip download --no-deps -d /tmp/wheelcheck requests
| What you see | First command | Repair |
|---|---|---|
| hostname message inside vendored TLS frames | python3 -m pip --version | upgrade the client |
| certificate verify failed after the tunnel | curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/ | trust the corporate root |
| connection refused or HTTP 407 | env | grep -i -E 'proxy|no_proxy' | correct host, port or credentials |