Skip to content

Guides · Connect and debug

Python urllib proxy setup

Use Python’s standard library to send an HTTPS request through an authenticated HTTP proxy. Keep the password out of source code, check routing exceptions and distinguish gateway failures from destination responses.

Short answers

How do I configure an urllib proxy?

Pass an explicit ProxyHandler to build_opener, then call that opener’s open method. The mapping key describes the destination scheme; its value is the gateway URL.

Can urllib use a proxy username and password?

For the HTTP Basic authentication used here, encode the raw username and password separately into the proxy URL. Read the password through a hidden prompt and do not print that URL.

Does ProxyHandler configure Requests or HTTPX?

No. An urllib opener configures urllib requests made through that opener. Other clients have their own proxy settings.

Will a rejected HTTPS proxy password always raise HTTPError 407?

No. A rejected CONNECT tunnel can appear as URLError. Check the gateway connection separately before treating a destination status as a proxy-authentication error.

Use urllib when you need the standard library

urllib.request ships with Python. It is a different client from Requests, HTTPX and aiohttp: a Requests proxies argument does not configure an urllib opener. This guide uses one opener for one HTTPS check and installs no packages. If your application already uses Requests or HTTPX, configure that client instead.

Use a supported Python 3 installation with SSL support. The example below was run with CPython 3.12.14 against local HTTP CONNECT and HTTPS fixtures. It has not been run through the live Portproof gateway, on Windows, or against every Python release. The fixture checks and their limits are listed below.

Get the HTTP connection fields

  1. Open the connection builder and choose HTTP, a pool, a currently available country and the rotation setting you need.
  2. Keep the complete generated proxy username. Its pool, country and session tokens are part of the credential; your website login is not a substitute.
  3. Use the proxy password from the dashboard. Do not put it in the script, shell history, screenshots or shared logs.
  4. Save the following file as proxy_check.py. Run it from an interactive terminal with python3 proxy_check.py, then answer its prompts.

The connection reference explains the fields. The target is a small HTTPS echo endpoint; one successful request can consume traffic from an existing balance, but it does not buy traffic or change your account.

Make one HTTPS request through the HTTP proxy

proxy_check.py · Python standard librarypython
import getpass
import http.client
import ipaddress
import json
import ssl
import warnings
from urllib.error import HTTPError, URLError
from urllib.parse import quote, urlsplit
from urllib.request import (
    HTTPRedirectHandler, HTTPSHandler, ProxyHandler,
    build_opener, proxy_bypass,
)

TARGET = "https://api.portproof.org/v1/echo-ip"
GATEWAY = "gw.portproof.org:7000"

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

def main():
    try:
        # Stop if a terminal cannot hide the password.
        warnings.simplefilter("error", getpass.GetPassWarning)
        username = input("Full proxy username: ").strip()
        password = getpass.getpass("Proxy password: ")
        if not username or not password:
            raise ValueError("Empty credential")
        if proxy_bypass(urlsplit(TARGET).netloc):
            print("A direct-routing exception matches the target. Review NO_PROXY or system proxy exceptions.")
            return 1
        credential = quote(username, safe="") + ":" + quote(password, safe="")
        proxy = "http://" + credential + "@" + GATEWAY
        context = ssl.create_default_context()
        context.set_alpn_protocols(["http/1.1"])
        opener = build_opener(
            ProxyHandler({"https": proxy}),
            HTTPSHandler(context=context),
            NoRedirect(),
        )
        with opener.open(TARGET, timeout=10) as response:
            if response.status != 200:
                raise ValueError("Unexpected response")
            body = response.read(16_385)
        if len(body) > 16_384:
            raise ValueError("Response too large")
        payload = json.loads(body)
        if not isinstance(payload, dict) or not isinstance(payload.get("ip"), str):
            raise ValueError("Missing IP")
        print("HTTP 200; exit IP:", ipaddress.ip_address(payload["ip"]))
        return 0
    except HTTPError as error:
        print("HTTP status:", error.code)
        error.close()
    except getpass.GetPassWarning:
        print("Run from an interactive terminal that supports hidden password input.")
    except (URLError, OSError, ValueError, http.client.HTTPException):
        print("Check failed. Check proxy settings, credentials, TLS and the echo response.")
    except (EOFError, KeyboardInterrupt):
        print("Check cancelled.")
    return 1

if __name__ == "__main__":
    raise SystemExit(main())

Success prints HTTP 200 and the IP address the echo destination saw. It does not verify the country, guarantee the next connection will use the same address, or show that another destination accepts your traffic. Keep the result local if you do not want to share your current exit address.

The script stops rather than accepting visible password input when getpass cannot hide it. The password remains in process memory while the check runs; the prompt does not protect a compromised machine. The example does not print the proxy URL, raw response body or complete exception, because those can expose configuration or data.

Why https maps to an http proxy URL

The https dictionary key selects HTTPS destinations. The http:// value selects the connection to the HTTP gateway at gw.portproof.org:7000. urllib opens an HTTP CONNECT tunnel and checks the destination certificate inside it. Changing that value to https:// would ask for a different proxy transport; an HTTPS destination alone is not a reason to do that.

Gateway authentication and website authentication are separate. Credentials in the proxy URL are used for proxy authentication; this example sends no destination login. Encoding each raw username and password with quote(value, safe="") preserves characters such as @, :, / and %. Do not encode the entire URL or encode values that are already encoded.

Destination HTTPS does not encrypt the initial credential exchange with an HTTP gateway. Use a network you trust and keep destination certificate verification enabled. A certificate failure is not fixed by accepting any certificate.

Check exceptions and redirects before a bigger job

A ProxyHandler with an explicit mapping avoids choosing the gateway from inherited proxy settings. Direct-routing exceptions can still apply. The example checks the target against urllib’s exception handling and stops if it matches; review NO_PROXY, no_proxy and your operating system’s proxy exception settings in that case. Do not silently remove a corporate routing policy from a shared application.

This opener belongs to the check. It is not installed with install_opener, so it does not replace the global opener used by unrelated code. Redirects are also stopped: a 301, 302 or other redirect is reported as an HTTP status rather than following a different destination. Decide which targets a real job may visit before adding redirect handling.

The ten-second timeout applies to blocking socket operations; it is not a ten-second deadline for the whole program. The response read is capped at 16 KiB plus one byte used to detect overflow. A scheduled job still needs an overall deadline, a work limit and an intentional retry policy.

Separate gateway errors from destination errors

First checks for this urllib example
ResultNext check
HTTP status 401 or 403The HTTPS destination returned an authentication or access response after the tunnel. Check the destination’s documented requirements; do not replace its credential with the proxy password.
Check failed before an HTTP statusA refused CONNECT, including proxy authentication rejection, can surface as URLError rather than HTTPError. Compare the gateway host, port and complete credential with a small curl check. The same general message also covers network, certificate and invalid echo-body failures.
HTTP status 301, 302, 307 or 308The example intentionally does not follow redirects. Check the intended endpoint instead of turning on unrestricted forwarding.
Direct-routing exception messageA target exception would avoid the configured gateway. Review the process environment and system policy before retrying.
No hidden password inputRun in an interactive terminal. Do not replace the password prompt with a literal secret in source code.

Use the 407 guide for gateway credential checks and the curl test to compare one client with another. The app-routing guide helps when the same connection works in a shell but fails inside a job.

Know the limits before reusing the example

The standard urllib handler used here is an HTTP proxy client. It does not add SOCKS5 support. For that requirement, use a client with documented SOCKS support, such as the optional integration covered in the Requests guide, and follow its setup instructions.

A Python opener is not a gateway sticky session. Select rotation and session settings in the generated username. A sticky session keeps the same device while it is available; the network can still change its IP. Reuse the intended username for a related workflow and read the session guide before testing rotation.

Portproof’s Mobile 4G/5G and Residential traffic pools are shared. If you need traffic for the connection, view proxy options and check current availability and pricing there.

What was checked

Local fixtures exercise authenticated CONNECT, reserved characters in credentials, rejection of bad gateway credentials, destination errors and redirects, certificate validation, invalid or oversized echo bodies, routing exceptions and timeout handling. The origin fixture also checks that proxy authentication is not forwarded into the HTTPS request. These are client-behaviour checks, not a measurement of the live pool, speed or availability.

The fixtures replace only gateway and echo coordinates, provide a test certificate authority and supply synthetic terminal input. A separate terminal check verifies hidden password entry. The published timeout is retained in the timeout case. Test output records the interpreter version and the SHA-256 of the exact published snippet.

Python references

Python urllib proxy setup and authentication · Portproof