모든 Node.js HTTP 클라이언트는 프록시를 제각기 다르게 처리하며, 그중 절반은 헬퍼 패키지 없이는 프록시 인증을 아예 처리하지 못합니다. axios는 일부 버전에서 HTTPS 대상에 대해 자체 proxy 옵션을 조용히 무시하고, 네이티브 fetch에는 프록시 옵션이 전혀 없으며, 오류 메시지 — ECONNRESET, 407, 또는 그냥 멈춤 — 는 아무것도 알려주지 않습니다.
이 글은 axios, got, node-fetch, 네이티브 fetch(undici), superagent를 인증된 주거용 프록시로 라우팅하는 완전하고 실제로 작동하는 레퍼런스입니다. 우리의 Python 가이드(requests/httpx/aiohttp, Scrapy)에 대응하는 Node 편입니다. 모든 예제는 표준 플레이스홀더 형식을 사용합니다 — 실제 자격 증명으로 바꿔 넣으세요:
socks5h://USERNAME:[email protected]:913
내장된 proxy 옵션을 쓰지 마세요. 프록시 에이전트를 사용하세요. Node의 HTTP 클라이언트는 연결 처리를 "에이전트" 객체에 위임하며, 에이전트 패키지(https-proxy-agent, socks-proxy-agent)는 CONNECT 터널링과 인증을 올바르게 구현합니다. 내장 옵션은 그렇지 못한 경우가 많습니다 — axios의 proxy 설정이 가장 악명 높은 예입니다.
npm install socks-proxy-agent https-proxy-agent
const axios = require("axios");
const { SocksProxyAgent } = require("socks-proxy-agent");
const agent = new SocksProxyAgent(
"socks5h://USERNAME:[email protected]:913"
);
const res = await axios.get("https://api.ipify.org?format=json", {
httpAgent: agent, // for http:// targets
httpsAgent: agent, // for https:// targets
proxy: false, // IMPORTANT: disable axios's own proxy handling
});
console.log(res.data); // -> the proxy's exit IP
사람들이 놓치는 두 가지: httpAgent와 httpsAgent를 둘 다 설정해야 하며(axios는 대상 스킴에 따라 선택함), proxy: false를 설정해 axios가 에이전트 위에 HTTP_PROXY 환경 변수까지 적용하려 하지 않도록 해야 합니다.
const got = require("got");
const { SocksProxyAgent } = require("socks-proxy-agent");
const agent = new SocksProxyAgent(
"socks5h://USERNAME:[email protected]:913"
);
const body = await got("https://api.ipify.org?format=json", {
agent: { http: agent, https: agent },
}).json();
got으로 보호된 대상을 스크래핑한다면 대신 got-scraping을 보세요 — 동일한 API에 더해 브라우저 같은 헤더 생성과 HTTP/2 핑거프린트 모방을 제공합니다(왜 중요한지: JA3/JA4 설명).
Node의 내장 fetch는 undici에서 오며, 프록시 환경 변수를 무시하고 agent 옵션이 없습니다. undici 방식은 dispatcher입니다:
const { ProxyAgent } = require("undici");
// undici's ProxyAgent speaks HTTP CONNECT (use your HTTP proxy port)
const dispatcher = new ProxyAgent({
uri: "http://us.jibaoproxy.com:1000",
token: "Basic " + Buffer.from("USERNAME:PASSWORD").toString("base64"),
});
const res = await fetch("https://api.ipify.org?format=json", { dispatcher });
console.log(await res.json());
참고: undici의 ProxyAgent는 HTTP 프록시 전용입니다. 네이티브 fetch로 SOCKS5를 쓰려면 로컬 포워더를 앞에 두거나 socks 에이전트를 받아들이는 클라이언트(위의 axios/got)를 사용하세요.
const fetch = require("node-fetch");
const { SocksProxyAgent } = require("socks-proxy-agent");
const agent = new SocksProxyAgent(
"socks5h://USERNAME:[email protected]:913"
);
const res = await fetch("https://api.ipify.org?format=json", { agent });
로테이팅 주거용 게이트웨이를 쓰면 IP 목록을 직접 관리하지 않습니다 — 게이트웨이가 연결마다 새로운 출구를 주거나, 세션 ID마다 하나의 출구를 유지합니다. Node에서는 이것이 신원당 하나의 에이전트로 깔끔하게 매핑됩니다:
// Sticky: same session id -> same exit IP across requests
function identityAgent(sessionId) {
return new SocksProxyAgent(
`socks5h://USERNAME-session-${sessionId}:[email protected]:913`
);
}
// Account A keeps IP A, account B keeps IP B - cookies and IP move together
const agentA = identityAgent("acct_a");
const agentB = identityAgent("acct_b");
하나의 신원 내에서는 연결 풀링을 위해 에이전트를 재사용하되, 절대 여러 신원에 걸쳐 하나의 에이전트를 공유하지 마세요. 언제 로테이션하고 언제 고정할지는 별도의 주제입니다 — 스티키 vs 로테이팅 세션을 보세요.
| 증상 | 원인 | 해결 |
|---|---|---|
407 Proxy Authentication Required | 자격 증명이 프록시에 도달하지 않음 | user:pass를 클라이언트 설정이 아니라 에이전트 URL에 넣으세요 |
| axios가 http://에서는 되는데 https://에서는 실패 | httpAgent만 설정됨 | httpsAgent도 설정하고 proxy: false로 하세요 |
즉시 ECONNRESET | 잘못된 포트 / 잘못된 프로토콜(SOCKS 에이전트에 HTTP 포트) | 에이전트 유형을 포트에 맞추세요 |
| DNS 누출 / 내부 호스트명 실패 | socks5://가 DNS를 로컬에서 해석함 | socks5h://를 쓰세요 — h가 호스트명을 프록시를 통해 전송합니다 |
| 네이티브 fetch가 HTTP_PROXY를 무시함 | undici가 환경 변수를 읽지 않음 | dispatcher를 명시적으로 전달하세요 |
| 로컬에서는 되는데 대상 사이트에서 403 | 프록시 버그가 아님 — TLS 핑거프린트 | got-scraping이나 실제 브라우저; TLS 가이드 참조 |
socks-proxy-agent / https-proxy-agent)를 사용하고, 내장 프록시 옵션을 절대 믿지 마세요.proxy: false. got: agent: {http, https}. 네이티브 fetch: undici ProxyAgent dispatcher.socks5h://를 써서 DNS가 프록시를 통해 해석되도록 하세요 — 누출 없음.신규 사용자는 가입 시 500MB를 받고, 첫 충전 시 추가 보너스를 받습니다. 기간 한정 혜택입니다.