Skip to content

[Bug/Feature request] Fix HTTPS proxy support by implementing https-proxy-agent (Axios regression since v8.2) #982

@mysther

Description

@mysther

Note: I used AI to help me write the issue for a clearer report. However, I tested, reviewed, and validated myself to ensure its accuracy. I hope that's okay.


Since the release of v8.2, the project has transitioned to using Axios for HTTP requests. It has introduced a regression for users operating behind corporate HTTP proxies (e.g., CNTLM, Squid).

Axios is known to have issues handling HTTPS requests through an HTTP proxy because it does not natively perform the required HTTP CONNECT tunneling correctly in many Node.js environments. This typically results in ECONNRESET or socket hang up errors.

This issue is well-documented in the Axios community: axios/axios#6330 - Unable to use HTTPS proxy with Axios

WUD logs

[...]
wud  | 09:59:26.061  WARN whats-up-docker/watcher.docker.penicilline: Error when processing (socket hang up) (container=penicilline_wud_cntlm)
wud  | 09:59:26.061 DEBUG whats-up-docker/watcher.docker.penicilline: socket hang up (container=penicilline_wud_cntlm, err.code=ECONNRESET)
wud  |     Error: socket hang up
wud  |         at AxiosError.from (/home/node/app/node_modules/axios/dist/node/axios.cjs:914:14)
wud  |         at RedirectableRequest.handleRequestError (/home/node/app/node_modules/axios/dist/node/axios.cjs:3515:25)
wud  |         at RedirectableRequest.emit (node:events:508:28)
wud  |         at RedirectableRequest.emit (node:domain:489:12)
wud  |         at eventHandlers.<computed> (/home/node/app/node_modules/follow-redirects/index.js:49:24)
wud  |         at ClientRequest.emit (node:events:508:28)
wud  |         at ClientRequest.emit (node:domain:489:12)
wud  |         at emitErrorEvent (node:_http_client:108:11)
wud  |         at Socket.socketOnEnd (node:_http_client:599:5)
wud  |         at Socket.emit (node:events:520:35)
wud  |         at Socket.emit (node:domain:489:12)
wud  |         at endReadableNT (node:internal/streams/readable:1729:12)
wud  |         at process.processTicksAndRejections (node:internal/process/task_queues:90:21)
wud  |         at Axios.request (/home/node/app/node_modules/axios/dist/node/axios.cjs:4731:41)
wud  |         at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
wud  |         at async Hub.authenticate (/home/node/app/dist/registries/providers/hub/Hub.js:89:26)
wud  |         at async Hub.callRegistry (/home/node/app/dist/registries/Registry.js:211:38)
wud  |         at async Hub.getTags (/home/node/app/dist/registries/Registry.js:63:20)
wud  |         at async Docker.findNewVersion (/home/node/app/dist/watchers/providers/docker/Docker.js:603:26)
wud  |         at async Docker.watchContainer (/home/node/app/dist/watchers/providers/docker/Docker.js:536:42)
wud  |         at async Promise.all (index 10)
wud  |         at async Docker.watch (/home/node/app/dist/watchers/providers/docker/Docker.js:508:38)
wud  |         at async Docker.watchFromCron (/home/node/app/dist/watchers/providers/docker/Docker.js:477:34)
wud  | 09:59:26.061 DEBUG whats-up-docker/watcher.docker.penicilline: Container watched for the first time (container=penicilline_wud_cntlm)
[...]

Proxy logs (CNTLM)

wud_cntlm  | cntlm[1]: 172.17.0.68 GET https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/traefik:pull&grant_type=password
wud_cntlm  | cntlm[1]: 172.17.0.68 GET https://auth.docker.io/token?service=registry.docker.io&scope=repository:robertdebock/docker-cntlm:pull&grant_type=password

Reproduction

Below is the script used to demonstrate the issue. It compares the default Axios behavior with the https-proxy-agent solution.

Script

I performed a comparative test using three different configurations. Only the https-proxy-agent approach successfully established a connection.

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const TARGET_URL = 'https://www.google.com';
const PROXY_CONFIG = {
    protocol: 'http',
    host: 'wud_cntlm',
    port: 3129
};
const PROXY_URL = `http://${PROXY_CONFIG.host}:${PROXY_CONFIG.port}`;

async function runTests() {
    console.log(`Target: ${TARGET_URL}\n`);

    // TEST 1: Default Axios Proxy Object
    try {
        console.log('--- Test 1: Axios Default Proxy Config ---');
        const res = await axios.get(TARGET_URL, { 
            proxy: PROXY_CONFIG,
            timeout: 5000 
        });
        console.log(`Success: Status ${res.status}`);
    } catch (err) {
        console.error(`Failed: ${err.message} (Code: ${err.code})`);
    }

    console.log('\n');

    // TEST 2: No Config (Testing Env Variables)
    try {
        console.log('--- Test 2: No Config (Testing Env Variables) ---');
        const res = await axios.get(TARGET_URL, { timeout: 5000 });
        console.log(`Success: Status ${res.status}`);
    } catch (err) {
        console.error(`Failed: ${err.message} (Code: ${err.code})`);
    }

    console.log('\n');

    // TEST 3: https-proxy-agent (Tunneling)
    try {
        console.log('--- Test 3: https-proxy-agent (Tunneling) ---');
        const agent = new HttpsProxyAgent(PROXY_URL);
        const res = await axios.get(TARGET_URL, { 
            httpsAgent: agent,
            proxy: false, 
            timeout: 5000 
        });
        console.log(`Success: Status ${res.status}`);
    } catch (err) {
        console.error(`Failed: ${err.message} (Code: ${err.code})`);
    }
}

runTests();

Script Output

Target: https://www.google.com

--- Test 1: Axios Default Proxy Config ---
Failed: socket hang up (Code: ECONNRESET)

--- Test 2: No Config (Testing Env Variables) ---
Failed: socket hang up (Code: ECONNRESET)

--- Test 3: https-proxy-agent (Tunneling) ---
Success: Status 200

Proxy Logs (CNTLM)

The logs from the proxy side confirm that Axios (Test 1 & 2) incorrectly tries to use GET for an HTTPS target, which causes the reset. Test 3 correctly uses the CONNECT method:

wud_cntlm  | cntlm[1]: 172.17.0.69 GET https://www.google.com/    <-- Fails (Axios default)
wud_cntlm  | cntlm[1]: 172.17.0.69 GET https://www.google.com/    <-- Fails (Env variables)
wud_cntlm  | cntlm[1]: 172.17.0.69 CONNECT www.google.com:443     <-- Success (Https-proxy-agent)

Problem and proposed Solution

In enterprise environments, a proxy is required to reach external registries or update checks. Using the standard Axios proxy configuration block fails when the target is an https:// URL because it lacks proper tunneling support.

Implement https-proxy-agent to handle the proxy handshake. This ensures that Axios works reliably with proxies in Node.js by establishing a secure tunnel via CONNECT.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions