Error check_hostname de pip detrás de un proxy: ¿pip o el túnel?
Dos fallos imprimen el mismo mensaje de nombre de host de pip detrás de un proxy. Distinga un cliente obsoleto de un proxy que re-firma el tráfico y repare la capa correcta.
Dos fallos distintos imprimen el mismo rastreo de pip, y la reparación que sirve para uno empeora el otro. Un cliente demasiado antiguo para nombrar un host tunelizado necesita una actualización. Un proxy que re-firma el tráfico necesita un certificado raíz de confianza, no una degradación. Determine cuál de los dos tiene antes de editar una variable de proxy, porque los caminos van en direcciones opuestas.
Lea los últimos marcos antes de tocar la configuración
Donde termina el rastreo le dice qué capa se rindió. Si los marcos finales están dentro del código TLS de urllib3 incluido con pip y el texto se queja de un nombre de host, la biblioteca cliente no pudo terminar un paso de verificación, y eso es un problema de versión mucho más a menudo que un problema de certificado. Si el texto en cambio informa de una conexión rechazada, un nombre de proxy sin resolver o un HTTP 407, el punto final del túnel tiene la culpa y ninguna actualización lo cambiará.
Capture la versión de pip y las variables de proxy en la misma shell que falla. Una shell abierta antes de que el túnel subiera lleva valores distintos de una abierta después, y la diferencia entre ambas suele ser todo el diagnóstico.
python3 -m pip --version
env | grep -i -E 'proxy|no_proxy'
Cuando el cliente es más antiguo que el túnel
Las versiones antiguas de pip incluían una pila HTTPS que perdía el nombre del host de destino cuando el socket quedaba envuelto por un túnel. El mensaje check_hostname es lo que esa pila emite cuando llega a la verificación sin un nombre con el que comparar. Una actualización elimina el fallo porque el cliente más nuevo conserva el nombre durante el apretón de manos, y el cambio es lo bastante barato para probarlo primero siempre que los marcos finales apunten a código TLS incluido.
Si no se puede llegar al índice desde la máquina que falla, descargue una wheel actual en un host que sí pueda e instálela desde el archivo. Use el nombre de archivo que descargó de verdad, no una versión copiada de una entrada de blog.
python3 -m pip install --upgrade pip
python3 -m pip install ./pip-24.2-py3-none-any.whl
Cuando el proxy re-firma el tráfico
Un proxy que termina TLS y reemite certificados bajo una raíz corporativa produce un error distinto: certificate verify failed, no una queja de nombre de host. Esa diferencia es la pista, porque el cliente llegó a un servidor y luego rechazó la identidad que se le mostró. La reparación es confiar en esa raíz de forma explícita, ya sea para un comando o mediante la variable PIP_CERT, para que el cliente pueda construir una cadena hasta lo que el proxy presenta. Añadir la raíz al almacén de confianza del sistema también funciona, pero cambia la confianza de todos los programas de la máquina, y eso es una decisión mayor que arreglar una instalación de paquete.
Mantenga --trusted-host como diagnóstico, nunca como estado permanente. Desactiva la comprobación que intentaba conservar, así que un certificado realmente incorrecto parece sano después. Si lo usó para instalar un paquete, quítelo y repare la cadena antes de la siguiente versión.
Su propio código Python ignora por completo la configuración de pip. Una llamada de requests necesita el proxy y el paquete pasados donde esa sesión pueda verlos, y por eso el bloque de abajo pone ambos en el objeto de sesión.
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)
Cuando el punto final o el puerto son incorrectos
Un cliente de túnel a menudo reescribe el proxy del sistema mientras se conecta, lo que puede dejar pip apuntando a un host que nunca responde en ese puerto. Pruebe el punto final con un cliente que no sea pip antes de cambiar cualquier ajuste de pip. Si curl falla con el mismo argumento de proxy, el fallo está por encima de pip y ninguna configuración dentro de pip ayudará.
La bandera del comando y las variables de entorno dicen lo mismo a ámbitos distintos: la bandera se aplica a una invocación, las variables a cada proceso iniciado después. Añada NO_PROXY para un índice interno, de modo que el tráfico privado de paquetes se salte el rodeo por el túnel.
curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/
pip install --proxy http://proxy.corp.internal:8080 requests
Persista el ajuste y demuestre que el camino funciona
Guarde el proxy en la configuración propia de pip cuando deba sobrevivir a la shell actual, y luego lea lo que pip usará realmente. La salida de debug nombra el archivo y la variable detrás de cada valor, lo que zanja las discusiones sobre precedencia más rápido que leer la documentación.
La verificación usa dos clientes a propósito. La petición de la biblioteca estándar demuestra la ruta y la cadena de confianza, mientras que la descarga demuestra que la configuración propia de pip está de acuerdo con ellas. Cuando la primera tiene éxito y la segunda falla, la diferencia está dentro de pip y no en la red.
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 |