Помилка 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 |