Skip to content

Guides · Connect and debug

Wget proxy setup with authentication

Configure GNU Wget 1 to use an authenticated HTTP proxy, check an HTTPS destination and keep the password out of command history. Start with one bounded echo request before downloading a permitted dataset.

Short answers

How do I set a proxy in Wget?

GNU Wget 1 reads http_proxy and https_proxy settings from its environment or configuration file. The example below supplies both in a separate configuration file and removes conflicting inherited proxy settings.

Which password option authenticates the proxy?

Use proxy_user and proxy_password for the gateway. Website credentials and --ask-password serve a different purpose; they do not replace these proxy settings.

Can an HTTP proxy carry an HTTPS download?

Yes. Wget requests a CONNECT tunnel through the HTTP gateway, then verifies the destination certificate. The initial proxy authentication is not encrypted by that destination TLS connection.

Check that you are running GNU Wget 1

This guide uses GNU Wget 1.25.0 and a Python wrapper on macOS or Linux. Wget 2 is a separate implementation; BusyBox and shell aliases can also behave differently. Check the actual executable before adopting flags from a tutorial. The wrapper finds wget on PATH and checks its version output.

Check the installed executablesh
wget --no-config --version

Install GNU Wget through your operating system’s trusted package source if needed. The wrapper requires Python 3.10 or newer and uses only its standard library. We tested with Python 3.12.14 and an isolated Wget build using OpenSSL. Windows users need a suitable Unix environment for this pipe-monitoring example.

Separate the gateway URL from the destination

Copy the full username from the connection builder, choosing an available pool and country. Use the proxy password supplied for that connection. The website account password and developer API key are different credentials. The hostname and port in this page’s example come from the site’s gateway configuration.

For an HTTPS destination, https_proxy can still contain an http:// gateway URL: the setting selects traffic by destination scheme. Wget then uses CONNECT. An HTTP destination uses http_proxy without destination TLS. Both settings here point to the same authenticated HTTP gateway. For SOCKS configuration, follow the separate curl guide.

Run one bounded echo check

Save the following as wget_check.py, then run python3 wget_check.py in an interactive terminal. Paste the complete username at the first prompt and enter the password at the hidden prompt. An existing PROXY_USER environment variable supplies the username instead. Neither prompt writes the password into a shell command.

wget_check.pypython
import getpass
import ipaddress
import json
import os
from pathlib import Path
import selectors
import shutil
import subprocess
import tempfile
import time
import warnings
from urllib.parse import urlsplit


class CheckFailure(Exception):
    pass


def check():
    wget = shutil.which("wget")
    if not wget:
        raise CheckFailure("Install GNU Wget 1 and check your PATH")
    version = subprocess.run([wget, "--no-config", "--version"],
                             capture_output=True, text=True, timeout=5)
    if not version.stdout.startswith("GNU Wget 1."):
        raise CheckFailure("This example requires GNU Wget 1")
    server = os.environ.get("PROXY_SERVER", "http://gw.portproof.org:7000")
    parsed = urlsplit(server)
    if (parsed.scheme != "http" or not parsed.hostname or not parsed.port
            or parsed.username is not None or parsed.password is not None
            or parsed.path not in ("", "/") or parsed.query or parsed.fragment
            or any(ord(c) <= 32 or ord(c) == 127 for c in server)):
        raise CheckFailure("Use an HTTP gateway URL without credentials")
    user = os.environ.get("PROXY_USER") or input("Full proxy username: ")
    warnings.simplefilter("error", getpass.GetPassWarning)
    password = getpass.getpass("Proxy password: ")
    for value in (user, password):
        if (not value or value != value.strip()
                or any(ord(c) < 32 or ord(c) == 127 for c in value)):
            raise CheckFailure("This config method requires nonempty credentials without edge whitespace or controls")
    if ":" in user:
        raise CheckFailure("A Basic-auth username cannot contain a colon")
    env = {k: v for k, v in os.environ.items()
           if k.lower() not in {"http_proxy", "https_proxy", "ftp_proxy",
                                "all_proxy", "no_proxy", "wgetrc"}}
    with tempfile.TemporaryDirectory(prefix="wget-check-") as folder:
        config = Path(folder) / "wgetrc"
        fd = os.open(config, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
        with os.fdopen(fd, "w", encoding="utf-8") as stream:
            stream.write(f"use_proxy = on\nhttp_proxy = {server}\nhttps_proxy = {server}\n"
                         f"no_proxy =\nproxy_user = {user}\nproxy_password = {password}\n")
        command = [wget, f"--config={config}", "--quiet", "--no-netrc",
                   "--no-hsts", "--no-cookies", "--tries=1", "--timeout=5",
                   "--max-redirect=0", "--output-document=-"]
        if os.environ.get("PROXY_CA_BUNDLE"):
            command.append("--ca-certificate=" + os.environ["PROXY_CA_BUNDLE"])
        command.append("https://api.portproof.org/v1/echo-ip")
        with subprocess.Popen(command, stdout=subprocess.PIPE,
                              stderr=subprocess.DEVNULL, env=env) as process:
            deadline = time.monotonic() + 20
            data = bytearray()
            try:
                with selectors.DefaultSelector() as ready:
                    ready.register(process.stdout, selectors.EVENT_READ)
                    while True:
                        left = deadline - time.monotonic()
                        if left <= 0 or not ready.select(left):
                            raise CheckFailure("Overall download deadline reached")
                        chunk = os.read(process.stdout.fileno(), 4096)
                        if not chunk:
                            break
                        data.extend(chunk)
                        if len(data) > 65536:
                            raise CheckFailure("Echo body exceeds 64 KiB")
                process.wait(timeout=max(0.001, deadline - time.monotonic()))
                if process.returncode:
                    raise CheckFailure(f"Wget exited with status {process.returncode}")
            finally:
                if process.poll() is None:
                    process.kill()
                process.wait()
        payload = json.loads(data)
        if not isinstance(payload, dict) or not isinstance(payload.get("ip"), str):
            raise ValueError("Echo response has no IP string")
        address = ipaddress.ip_address(payload["ip"])
        print("Exit address:", address)


if __name__ == "__main__":
    try:
        check()
    except CheckFailure as error:
        print(error)
        raise SystemExit(1)
    except (OSError, ValueError, subprocess.SubprocessError, getpass.GetPassWarning) as error:
        print("Check failed:", type(error).__name__)
        raise SystemExit(1)

The wrapper prints a validated exit address only after Wget succeeds and the response contains an IP string. That address describes this request; it does not establish country accuracy, future availability or access to another site. Next, test one permitted operation from the application that will perform the real work.

Use a temporary file for proxy credentials

The password goes into a mode-0600 file inside a private temporary directory, rather than the gateway URL or process arguments. It remains plaintext in that protected file while Wget runs. Handled failures and timeouts remove the directory; forced termination can leave it behind, so use a trusted account and temporary storage.

This method passes raw punctuation directly to Wget’s configuration parser. Do not URL-encode the password or add quotation marks around it. The parser trims surrounding whitespace, so the wrapper rejects leading or trailing whitespace and control characters instead of silently changing credentials. If those characters are required, use a client with a separate authentication object, such as HTTPX.

The script rejects a colon in a Basic-auth username. It also stops if hidden password entry is unavailable. For unattended work, replace the prompts with your established secret-manager lookup and retain the same validation and file protections. Keep generated configuration files out of repositories, archives and diagnostic attachments.

Control inherited proxy and configuration settings

GNU’s proxy documentation describes the lower-case environment variables and configuration settings. A job scheduler or service may inherit different values from your terminal. The wrapper clears inherited proxy variables for its child process, uses a dedicated configuration file and disables netrc credentials, cookies and HSTS persistence for this check.

An empty no_proxy setting prevents an exclusion from changing this diagnostic’s route. The local fixture also supplied conflicting environment proxies and WGETRC settings; the chosen gateway still received the request. Apply explicit routing only where it fits your network policy. The application troubleshooting guide explains how to compare processes.

Bound attempts, elapsed time and response data

Wget receives one URL, one permitted attempt and no redirects. Its five-second timeout limits network waiting; it is not an overall runtime limit. The wrapper separately stops the download after twenty seconds, including a response that keeps delivering small chunks. Password entry and the preliminary version check happen before that download deadline.

The wrapper also stops when the echo body exceeds 64 KiB. That bounds the diagnostic’s buffered response, not billable traffic: headers, buffering and protocol overhead remain separate. For larger files, choose deliberate download limits and measure account usage. Wget’s quota option is not a reliable single-file cutoff; see its download options.

Read failures by connection stage

Wget status 4
In our HTTPS fixture, rejected CONNECT requests with 407 or 503 and stalled downloads returned this network-error status. It does not identify authentication failure by itself. Check the gateway, generated username and proxy password, then use the 407 diagnostic. If the gateway is not reached at all, the connection-refused guide isolates that stage with curl.
Wget status 5
Untrusted and mismatched destination certificates returned this status locally. Correct the hostname or trust chain. An approved PROXY_CA_BUNDLE supplies a CA file to this example; certificate verification stays enabled.
Wget status 8
Destination 403, 407 and 429 responses inside an established HTTPS tunnel returned this status, as did a refused redirect. Respect access restrictions and retry guidance. A destination 407 is distinct from a gateway rejecting CONNECT.

What the local tests established

On 1 October 2026, the example ran against local HTTP and HTTPS origins through an authenticated fixture proxy. Checks covered punctuation, routing overrides, rejected tunnels, certificate rejection, destination errors, redirects, malformed echo responses, oversized bodies and timeouts. The HTTPS origin received no proxy credentials, and handled exits removed the private configuration and closed the connection.

These checks establish the named client behaviour, without measuring live pool performance. Wget does not rotate addresses itself: choose gateway rotation or a sticky session in the username, as explained in the session guide. Before scaling, define permitted destinations, finite retries and a measured traffic budget.

What is not allowed

Use Wget for authorised research, monitoring and QA that follows destination rules and the acceptable-use policy.

Wget proxy setup and authentication · Portproof