Грешка check_hostname в pip зад прокси: pip или тунелът?
Две повреди отпечатват една и съща грешка за име на хост в pip зад прокси. Разграничете остарял клиент от прокси, което преподписва трафика, и поправете правилния слой.
Две различни повреди отпечатват една и съща следа от pip и поправката, която подхожда на едната, влошава другата. Клиент, твърде стар, за да назове тунелиран хост, се нуждае от надграждане. Прокси, което преподписва трафика, се нуждае от доверен коренов сертификат, а не от понижаване. Установете коя от двете имате, преди да редактирате променлива за прокси, защото пътищата водят в противоположни посоки.
Прочетете последните кадри, преди да пипате настройки
Мястото, където следата свършва, показва кой слой се е отказал. Ако затварящите кадри са в TLS кода на urllib3, вграден в pip, и текстът се оплаква от име на хост, клиентската библиотека не е успяла да завърши стъпка на проверка и това е проблем с версията много по-често, отколкото проблем със сертификат. Ако текстът вместо това съобщава за отказана връзка, неразрешено име на прокси или грешка HTTP 407, крайната точка на тунела е виновна и никакво надграждане няма да го промени.
Запишете версията на pip и променливите за прокси в същата обвивка, която се проваля. Обвивка, отворена преди тунелът да се вдигне, носи различни стойности от отворена след това, и разликата между тях често е цялата диагноза.
python3 -m pip --version
env | grep -i -E 'proxy|no_proxy'
Когато клиентът е по-стар от тунела
По-старите издания на pip включваха HTTPS стек, който губеше името на дестинацията, след като сокетът беше обвит от тунел. Съобщението check_hostname е това, което този стек издава, когато стигне до проверка без име за сравнение. Надграждането премахва повредата, защото по-новият клиент запазва името през ръкостискането, и промяната е достатъчно евтина, за да се опита първа, когато затварящите кадри сочат към вграден TLS код.
Ако индексът не е достъпен от машината, която се проваля, изтеглете актуален wheel на хост, който може, и инсталирайте от файла. Използвайте името на файла, което действително сте изтеглили, а не версия, копирана от публикация в блог.
python3 -m pip install --upgrade pip
python3 -m pip install ./pip-24.2-py3-none-any.whl
Когато проксито преподписва трафика
Прокси, което прекратява TLS и преиздава сертификати под корпоративен корен, дава друга грешка: certificate verify failed, а не оплакване за име на хост. Тази разлика е уликата, защото клиентът е стигнал до сървър и после е отхвърлил показаната му идентичност. Поправката е да се доверите на този корен изрично, било то за една команда или чрез променливата PIP_CERT, за да може клиентът да изгради верига до това, което проксито представя. Добавянето на корена към системното хранилище за доверие също работи, но променя доверието за всяка програма на машината и това е по-голямо решение от поправянето на една инсталация на пакет.
Дръжте --trusted-host като диагностичен инструмент, никога като постоянно състояние. Той изключва проверката, която сте се опитвали да запазите, така че наистина грешен сертификат изглежда здрав след това. Ако сте го използвали, за да инсталирате един пакет, премахнете го и поправете веригата преди следващото издание.
Вашият собствен Python код напълно игнорира конфигурацията на pip. Извикването на requests се нуждае от проксито и пакета, подадени там, където тази сесия ги вижда, и затова блокът по-долу задава и двете на обекта на сесията.
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)
Когато крайната точка или портът са грешни
Клиентът на тунела често пренаписва системното прокси, докато се свързва, което може да остави pip насочен към хост, който никога не отговаря на този порт. Тествайте крайната точка с клиент, който не е pip, преди да промените каквато и да е настройка на pip. Ако curl се провали със същия аргумент за прокси, повредата е над pip и никаква конфигурация в pip няма да помогне.
Флагът на командата и променливите на средата казват едно и също за различни обхвати: флагът важи за едно извикване, променливите за всеки процес, стартиран след това. Добавете NO_PROXY за вътрешен индекс, за да пропуска частният трафик на пакети обиколката през тунела.
curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/
pip install --proxy http://proxy.corp.internal:8080 requests
Запазете настройката и докажете, че пътят работи
Съхранявайте проксито в собствената конфигурация на pip, когато трябва да надживее текущата обвивка, после прочетете какво наистина ще използва pip. Изходът на debug назовава файла и променливата зад всяка стойност и това решава споровете за приоритет по-бързо от четенето на документацията.
Проверката умишлено използва два клиента. Заявката от стандартната библиотека доказва маршрута и веригата за доверие, докато изтеглянето доказва, че собствената конфигурация на pip е съгласна с тях. Когато първата успее, а втората се провали, разликата е вътре в pip, а не в мрежата.
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 |