今まさに Stack Overflow のどこかで、誰かが Axios は HTTPS プロキシで「黙って壊れる」と思い込んでいるはずです。Node.js のプロキシ解説で何度も繰り返される話ですが、このガイドで検証した現行リリースには当てはまりません。私はローカルに、HTTP と HTTPS の実サーバーを 2 つのプロキシの背後に置いたテスト環境を立ち上げ、Axios 1.19.0 で HTTPS リクエストを送ったところ、プロキシを迂回することなく、正しい CONNECT リクエスト経由でトンネル接続されることを確認しました。
とはいえ、現場でよく聞く困りごとが全部ウソというわけではありません。古い Axios には実際にバグがありました(証拠は issue #3384 と issue #4531 を見てください)。さらに最近の Node には、別系統の環境変数プロキシ経路が追加されていて、きちんと設定する必要があります。このガイドでは、現時点の Axios 1.19.0 で実際に動く構成、リクエストにプロキシを組み込む全パターン、ほとんどの解説記事が触れない interceptor を使ったローテーション手法、そして「結局うまくいかない」ときのエラー別対処表までまとめて紹介します。
Axios プロキシとは何か? なぜ Node.js で重要なのか?
Axios の文脈でいうプロキシとは、Node プロセスとアクセス先サイトの間に入る中継サーバーのことです。リクエストはいったんプロキシへ送られ、プロキシが相手先へ転送します。すると、相手側にはあなたの IP ではなくプロキシの IP が見える。仕組みはそれだけです。
これを使う理由はだいたい決まっています。IP ごとのレート制限やブロックを避けたい、別地域からの見え方を確認したい、社内の出口経路を通したい、あるいは対象サイトのアクセスログに自分のサーバーの IP を残したくない、といったケースです。Axios の公式 request config には host、port、protocol、auth を持つ proxy オプションが最初から用意されています。昔からある機能で、どの解説記事でも最初に出てくる定番です。
ただし、ここで見落とされがちな点があります。proxy の挙動は、アクセス先が HTTP か HTTPS か、そしてどの Axios バージョンを使っているかで変わります。この違いこそが、この記事がある理由です。
Node.js と Axios の準備(最小構成)
すでにプロジェクトがあるなら読み飛ばして構いません。なければ 2 分ほどで済みます。
mkdir axios-proxy-demo && cd axios-proxy-demo
npm init -y
npm install axios
ESM の import を使いたいなら、package.json に "type": "module" を追加してください(私はそうしています。プロキシ検証で CommonJS の require() を使うのは少し古く感じます)。現在の Node LTS は v24.18.0 ですが、このテストでは最新ランタイム特有の癖に引っ張られないよう、あえて v22.22.3 で実施しました。
app.js に次を入れて、node app.js を実行します。
import axios from 'axios';
const res = await axios.get('https://httpbin.org/ip');
console.log(res.data);
レスポンスには、自分の実際の IP アドレスが表示されるはずです。これがベースラインです。プロキシが正しく動いたら、この同じリクエストが今度はプロキシの IP を返すようになります。
次のステップに進む前に、このレスポンスを記録しておきましょう。プロキシ経由の結果と比べるための、はっきりした基準になります。
Axios は HTTPS プロキシを本当にサポートしているのか?
短く答えると、現在の安定版では yes です。Axios 1.19.0 の説明では、HTTP プロキシの背後にある HTTPS ターゲットに対して CONNECT トンネリングを使うことが明記されています。npm のダウンロード API では、2026 年 7 月 31 日から 8 月 6 日までの 117,890,039 回の Axios ダウンロード が記録されており、ライブラリの利用規模を示す古い指標ではありますが、それだけ広く使われていることがわかります。HTTPS URL をプロキシ経由で叩くと、現在の Axios は CONNECT リクエストを送り、TLS ハンドシェイクは実際のオリジンと end-to-end で行われます。私も、ローカル HTTP プロキシ、自己署名証明書付きのローカル HTTPS オリジン、そしてプロキシ側の CONNECT カウンタが期待通り増えることを直接確認しました。
では、なぜフォーラムでは毎回のように「Axios の HTTPS プロキシが壊れている」と言われるのでしょうか。理由はいくつかありますが、どれも現実に起きています。
- 古い Axios バージョン。 GitHub の issue で参照される内容は何年も前のものが多く、当時のリリースや設定に固有の挙動です。現在の Axios にそのまま一般化してはいけません。
- CONNECT 非対応のプロキシ。 この構成だとトンネルが張れず、Axios はエラーを返すべきです。IP が迂回されたかどうかを疑う前に、実際の経路とエラーを確認しましょう。
proxy設定の誤解。proxyは forward proxy の指定であって、「何があってもこの agent を使って全部ここから通す」という万能スイッチではありません。
Chromium は 2023 年に、主要プラットフォーム全体の Chrome ナビゲーションの 90% 超が HTTPS だったと報告しました。これは Chrome の古い測定値であり、ウェブ全体の最新統計ではありませんが、HTTPS ターゲットの挙動を中心に扱うべき理由としては十分です。古い Axios を使っているなら、「昔はそうだった」ではなく、必ず今の系統で再現してから判断してください。アップグレードの影響は、本番投入前に自分のアプリで検証するべきです。
それでも明示的な Agent が欲しい場合
ネイティブの proxy 設定は、静的で 1 つだけの一般的なプロキシなら十分です。ただし、リクエストごとの制御、プロキシローテーション、SOCKS サポートが必要になった瞬間に限界が見えます。Axios の標準オプションは、その用途のために作られていません。そこで活躍するのが HttpsProxyAgent です。後ほど詳しく見ていきます。ネイティブ設定は「1 つのプロキシを 1 つの目的で使うなら十分」、agent ベースの方法は「本番で本当に欲しいもの」と考えるとわかりやすいでしょう。
Node v24 と v22.21+ の環境変数プロキシ経路
最近の Node には、NODE_USE_ENV_PROXY=1 または --use-env-proxy フラグで有効になる、組み込みの環境変数プロキシモードがあります。Node の CLI ドキュメント によれば、これは v24.0.0 で入り、v22.21.0 にもバックポートされています。つまり「Node 22+」という言い方は厳密には不正確で、正しくはその系統の v22.21.0 以降です。もっと古い Node 22 のパッチでは、このフラグ自体が存在しません。
現在の Axios は、依存している proxy-from-env を通じて HTTP_PROXY、HTTPS_PROXY、NO_PROXY をすでに解釈します。つまり、この現行 Axios の経路では global-agent は不要です。さらに Node の env-proxy モードも有効だと、経路選択には 2 層が関わる可能性があります。
Axios のドキュメントでは、proxyEnv プロパティを持つ agent を使う Node バージョンでは、Axios は自前で解決せず Node 側の処理に委ねると説明しています。実運用では、どちらか一方に決めて揃えるのが基本です。
- Node に任せる: フラグを有効にし、Axios の
proxy設定は使わず、環境変数で制御する。 - Axios に任せる: Node のフラグは使わず、Axios 側の環境変数解釈に任せる。
- 完全に手動で制御する:
proxy: falseを明示し、自前のhttpsAgentを渡す。これで自動解決を完全に外せます。ローテーションやリクエスト単位のロジックが必要になったら、私はこれをおすすめします。
Axios 側の解決は実際にテストしました。子プロセスの環境変数に HTTP_PROXY を設定すると、リクエストはローカルプロキシ経由で流れ、NO_PROXY を合わせて設定すると次のリクエストでは正しくスキップされました。つまり env-var 経路は今ちゃんと動きます。気をつけるべきなのは、2 つのモードが同時に有効なケースです。
Axios にプロキシを組み込む 5 つの方法
コードに入る前に、全体像を整理しておきましょう。ここでは、ドキュメントを読むだけではなく、実際にローカルのプロキシ環境で 1 つずつ検証しました。
| 方法 | HTTPS 対応 | 認証対応 | リクエスト単位の制御 | ローテーション向き | 複雑さ |
|---|---|---|---|---|---|
インラインの proxy オプション | ✅(現行 Axios) | ✅ | ✅ | ❌ | 低 |
axios.create() のデフォルト | ✅(現行 Axios) | ✅ | ❌(インスタンス全体) | ❌ | 低 |
環境変数(HTTP_PROXY/HTTPS_PROXY) | ✅ | ✅ | ❌ | ❌ | 低 |
httpsAgent + HttpsProxyAgent | ✅ | ✅ | ✅ | ⚠️(手動) | 中 |
| request interceptor + agent pool | ✅ | ✅ | ✅ | ✅ | 中〜高 |
1 回きりのスクリプトで 1 つのプロキシに流すなら、インラインの proxy を使えば十分です。モジュール内の全リクエストを同じプロキシに通したいなら、axios.create() でまとめると楽です。インフラ側ですでにプロキシ環境変数を管理していて、アプリはそれを引き継ぎたいだけなら、環境変数方式が向いています。ネイティブ設定では足りない制御が必要なら明示的な agent を使い、そして「制御」が「ローテーション」に変わった瞬間に interceptor パターンへ進みましょう。

手順でわかる:Axios の基本的なプロキシ設定
最もシンプルなのは、リクエストに直接組み込む方法です。
import axios from 'axios';
const res = await axios.get('https://httpbin.org/ip', {
proxy: {
host: '203.0.113.10',
port: 8080,
protocol: 'http',
},
});
console.log(res.data);
これを実行すると、レスポンスには自分の IP ではなくプロキシの IP が返るはずです。実際のプロキシを使ってローカルで試すなら、だいたい 1 秒もかからず確認できます。1 回の検証のためだけにシステム全体のプロキシ設定をいじる方法と比べれば、かなり手軽です。あれは 15 分くらい平気で消えます。
このレスポンスをベースラインと見比べてください。うまくいっていれば、先ほど記録したオリジンの IP ではなく、プロキシの公開 IP が表示されます。
axios.create() でインスタンス全体のデフォルトを設定する
あるモジュール内のすべてのリクエストを同じプロキシに通したいなら、毎回書かずにインスタンスへまとめてしまいましょう。
const client = axios.create({
proxy: {
host: '203.0.113.10',
port: 8080,
},
timeout: 15_000,
});
const res = await client.get('https://httpbin.org/ip');
個別リクエストで proxy: false を上書きすると、インスタンスのデフォルトをきれいに回避できることも確認済みです。たとえば 95% の呼び出しはプロキシが必要でも、ヘルスチェックの ping だけは直通にしたい、という場面で役立ちます。
環境変数でプロキシを設定する
Docker コンテナや CI 環境のように、運用側がすでにプロキシ環境変数を管理しているなら、Axios の設定を触る必要はありません。
export HTTP_PROXY=http://203.0.113.10:8080
export HTTPS_PROXY=http://203.0.113.10:8080
export NO_PROXY=localhost,127.0.0.1
現行 Axios は global-agent なしでこれらを読み取ります。ただし、先ほどの Node の境界条件は忘れないでください。NODE_USE_ENV_PROXY も有効なら、どの層がルーティングの責任を持つのかを明確にし、デプロイ先ランタイムで NO_PROXY の挙動を必ず確認しましょう。
手順でわかる:httpsAgent を使った HTTPS プロキシ設定(本格運用向け)
「ずっと同じ 1 個のプロキシ」以上のことが必要になったら、私ならこの構成を選びます。まずは current の agent パッケージを入れます。
npm install https-proxy-agent
https-proxy-agent 9.1.0 は Node 20 以上を要求し、ターゲット接続をトンネルする前に、プロキシへ正しい CONNECT を送ります。
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
const agent = new HttpsProxyAgent('http://203.0.113.10:8080');
const client = axios.create({
proxy: false, // Axios のネイティブ解決が横から入らないようにする
httpsAgent: agent,
timeout: 15_000,
});
const res = await client.get('https://httpbin.org/ip');
console.log(res.data);
明示的な agent を使うなら、proxy: false を設定してください。そうすることで設定の責任範囲が明確になり、Axios のネイティブ解決や環境変数解決が、渡した agent と競合するのを防げます。
プロキシ認証を追加する
認証情報はプロキシ URL に直接埋め込めます。
const agent = new HttpsProxyAgent('http://myuser:mypassword@203.0.113.10:8080');
パスワードに @、:, # などの特殊文字が入る場合は、URL を組み立てる前に percent-encode してください。あるいは各パーツを encodeURIComponent() でエンコードしてから結合しても構いません。パスワード中の生の @ は host 部分の開始と誤解釈されるため、見た目では原因がわかりにくい接続エラーにつながります。
Axios で SOCKS5 プロキシを使う
SOCKS プロキシは HttpsProxyAgent と互換ではありません。プロトコルに合った別の agent が必要です。
npm install socks-proxy-agent
import { SocksProxyAgent } from 'socks-proxy-agent';
const agent = new SocksProxyAgent('socks5://myuser:mypass@203.0.113.10:1080');
const client = axios.create({
proxy: false,
httpsAgent: agent,
});
socks-proxy-agent 10.1.0 も Node 20 以上が必要です。SOCKS5 は、社内ネットワークで SOCKS ゲートウェイしか開いていない場合や、単純な HTTP プロキシより柔軟なプロトコル対応を持つプロバイダを使う場合に有力です。
Axios の request interceptor でプロキシをローテーションする
呼び出し側でランダムにプロキシを選ぶだけなら、単発スクリプトでは十分です。しかし大量のリクエストを送るようになると、どのプロキシが死んでいるのかを一元管理する場所も、リトライの仕組みもなくなり、選択ロジックがあちこちにコピペされて破綻します。Axios の interceptor システム なら、そのロジックを 1 か所にまとめてテスト可能にできます。この記事の SERP で比較した 5 つの競合記事のうち、このパターンを使っていたものはありませんでした。

プロキシプールを作る
import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
class ProxyPool {
private agents: HttpsProxyAgent<string>[];
private index = 0;
constructor(proxyUrls: string[]) {
this.agents = proxyUrls.map((url) => new HttpsProxyAgent(url));
}
next(): HttpsProxyAgent<string> {
const agent = this.agents[this.index];
this.index = (this.index + 1) % this.agents.length;
return agent;
}
}
const pool = new ProxyPool([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
]);
const client = axios.create({ timeout: 15_000 });
client.interceptors.request.use((config: InternalAxiosRequestConfig) => {
config.proxy = false;
config.httpsAgent = pool.next();
return config;
});
これを 2 つのローカルプロキシで試し、リクエストが proxy A、proxy B、再び A と正しく交互になることを確認しました。なお、Axios の request interceptor は後入れ先出しで実行されるため、認証ヘッダーやログ出力など他の interceptor がある場合は、順序が想像以上に重要です。
Response interceptor を追加して、リトライを制御する
ここで多くの自作ローテーションスクリプトは雑になります。失敗のたびに無条件で、しかも無制限のプールに対して再試行すると、1 件の不具合が連鎖的な混乱を生みます。特に POST のような冪等でないメソッドでは、意図しない副作用を二重に発生させる危険があります。
type RetryableConfig = InternalAxiosRequestConfig & {
__proxyRetryCount?: number;
};
client.interceptors.response.use(
undefined,
async (error: AxiosError) => {
const config = error.config as RetryableConfig | undefined;
if (!config) throw error;
const method = String(config.method ?? 'get').toUpperCase();
config.__proxyRetryCount ??= 0;
if (method !== 'GET' || config.__proxyRetryCount >= 1) throw error;
config.__proxyRetryCount += 1;
config.proxy = false;
config.httpsAgent = pool.next();
return client.request(config);
}
);
壊れたプロキシを使ってこれをテストし、代替 agent へ 1 回だけリトライされることを確認しました。無限ループもなく、POST にはリトライも入りません。これくらいの制御がちょうどよいのです。「動くまで何度でもやり直す」のではなく、どのリクエストが安全に再送できるかを明示するリトライポリシーにしてください。

エラー診断表:失敗を原因と修正に対応づける
これはブックマーク推奨です。Axios の GitHub issue や Stack Overflow で実際に出てくるエラーをまとめています。想像上のものではありません。
| エラー / 症状 | 考えられる原因 | 対処法 |
|---|---|---|
ECONNREFUSED | host/port が間違っている、またはプロキシサーバーが落ちている | Axios を触る前に、curl -x http://host:port target-url で確認する |
407 Proxy Authentication Required | 認証情報がない、または間違っている | proxy 設定に auth: { username, password } を追加するか、HttpsProxyAgent の URL に認証情報を埋め込む |
403 Forbidden | オリジンまたは WAF がリクエストやプロキシ IP を拒否した | サイトのアクセス方針、認証、リクエスト頻度を確認する。ヘッダーや IP が変わったからといって制限を回避できるとは考えない |
| レスポンスに実際の IP が出る | NO_PROXY、proxy:false、明示的な direct agent、または過去バージョン固有の設定でプロキシが回避されている | どの層がルーティングを担当しているか確認し、必要なら制御可能な IP エンドポイントと明示的 agent で経路を検証する |
ETIMEDOUT | 接続または応答が設定したタイムアウトを超えた | どこで時間を使っているか測る。ワークロードに見合う場合だけ timeout を延ばし、それ以外は不健康な経路を切り替えるか冷却する |
途中で ECONNRESET | プロキシ、ネットワーク、またはオリジンが接続を閉じた | 失敗したホップを記録する。再送可能なリクエストだけを、回数上限付きで再試行する |
Nginx 配下で 502 Bad Gateway | Nginx の proxy_pass 設定ミス、または Axios の timeout と Nginx 設定の不一致 | proxy_connect_timeout と proxy_read_timeout を確認する(どちらも既定は 60 秒)。Axios の timeout と揃える |
ERR_TLS_CERT_ALTNAME_INVALID | ターゲットに対して agent の種類が違う、または自己署名証明書を使っている | プロトコルに合った agent を使っているか確認する。rejectUnauthorized: false はローカル検証専用で、本番では絶対に使わない |
すぐ使えるデバッグ・チェックリスト
原因がわからない不具合が起きたら、次の順で確認してください。
- まず
curl -x http://host:port https://your-target.comでプロキシ単体をテストする。失敗するなら、Axios ではなくプロキシ接続、認証、ターゲット側を疑う。通るなら、Axios 側の経路を別途確認する必要があります。 - 実際に使っている Axios と Node のバージョンを確認し、過去の報告を同じリリース・同じ設定で比べてから修正を当てる。
- どの仕組みがプロキシを解決しているのかを見極める。ネイティブ Axios 設定か、Axios の env-var 解決か、Node の組み込み env-proxy モードか、あるいは明示的 agent か。1 つのリクエストを複数の仕組みに担当させないこと。
NO_PROXYに、意図しないホスト名一致がないか確認する。- 明示的 agent を使うなら、Axios が二重処理しないよう
proxy: falseが設定されているか確認する。
DIY のプロキシ配線をやめたほうがいい場合
上で紹介した内容は、本当に交通経路を制御したい場合には有用です。たとえば社内ネットワークの検証、アプリの地域別テスト、制御された外向き通信などです。ただ、多くの開発者は「Axios のプロキシをどう設定するか」で検索しながら、本当に欲しいのはウェブサイトのデータで、プロキシはそのための手段にすぎません。
もしそうなら、そもそもプロキシが必要なのか、それともインフラを丸ごと任せられる scraping API が必要なのか、考えてみる価値があります。Thunderbit の Open API は URL とスキーマを渡すだけで構造化された JSON を返します。生 HTML の解析も、agent ライブラリも、プロキシプールの保守も不要です。/extract エンドポイント は JavaScript レンダリングページ、ボット対策、CAPTCHA をサーバー側で処理し、ページをきれいな Markdown に変換するだけでよければ、軽量な /distill エンドポイント も使えます。さらに MCP server では thunderbit_extract や thunderbit_suggest_fields のようなツールを公開しているため、Claude や Cursor のような coding assistant が、プロキシ設定に触れずにタスクの途中で構造化データを取得できます。CLI もあるので、ターミナルや CI でのワークフローにも対応します。
| 関心事 | DIY の Axios + プロキシ | Thunderbit API/MCP/CLI |
|---|---|---|
| プロキシの調達とローテーション | 自分で管理 | サーバー側で処理 |
| ブラウザやアクセス制限への対応 | 自分でブラウザ/ネットワーク層を運用 | サービスが文書化された範囲で管理 |
| JS レンダリングページ | ヘッドレスブラウザが必要 | renderMode: full |
| 出力形式 | 生 HTML を自分で解析 | スキーマ付きの構造化 JSON |
| サイト変更時の保守 | 解析ロジックやセレクタを保守 | 管理された抽出層がアプリ側の保守負担を一部軽減 |
正直に言うと、テストや社内ネットワークのためにトラフィックをルーティングする必要があるなら、Axios とプロキシ設定の代替にはなりません。ですが、求めている成果物が構造化されたウェブデータなら、API ファーストの方法のほうが、アプリが持つべきプロキシ・ブラウザ・解析コードを減らせるかもしれません。2026 年 8 月 7 日の取得時点で、Thunderbit の API レート制限ドキュメント には Free tier が 1 分あたり 10 リクエスト、同時 2 リクエストと記載されていました。本番で頼るなら、こうした数値は時間依存の情報として扱い、必ずページを再確認してください。
まとめ
ここでの本質的な教訓は、昔のチュートリアルが言うことと少し違います。現在の Axios は、記録したローカルテストでは、HTTPS ターゲットに対して CONNECT トンネリングを正しく使っていました。過去の失敗は確かに重要ですが、バージョンと設定の文脈込みで見る必要があります。ネイティブ設定は低複雑度の出発点として有効ですし、リクエスト単位の制御、SOCKS 対応、ローテーションが必要なら、proxy: false と組み合わせた明示的な HttpsProxyAgent(または SocksProxyAgent)のほうが、責任の所在が明確です。本番でプールを回すなら、request / response interceptor を使えば中央集約されたテスト可能な形で実装できます。ただし、リトライにはループ防止を入れ、安全に再送できるリクエストだけに限定してください。
深夜 2 時にプロキシ設定が意味不明なエラーを返してきたら、上の 診断表 をブックマークしておくと役に立ちます。そして、プロキシ配線のデバッグにデータ活用よりも時間を取られていると気づいたら、API ファーストの抽出ツール のほうが、インフラを整えるより早く本当の問題を解決してくれるかもしれません。
FAQ
Axios はネイティブで HTTPS プロキシをサポートしていますか? 現在の Axios なら、一般的な HTTP プロキシ経由で yes です。公式ドキュメントには HTTPS ターゲット向けの CONNECT トンネリングが記載されており、Axios 1.19.0 でも記録したローカルテストではその経路が通りました。とはいえ、古いリリースや特定のプロキシ構成では実際に失敗が起きていたため、万能に成功すると決めつけず、必ずバージョンとプロキシ構成を個別に確認してください。
Axios でプロキシをローテーションするにはどうすればいいですか?
request interceptor を使って、リクエスト送信前にプロキシプールから異なる httpsAgent を割り当てます。さらに response interceptor で、失敗したリクエストを別のプロキシで再試行するようにします。リトライは必ず制限してください。1 回だけ、しかも GET のような冪等なメソッドに限定することで、本来再送すべきでないリクエストを誤って繰り返さずに済みます。
Axios のプロキシが実際の IP を返すのはなぜですか?
NO_PROXY、proxy:false、明示的な direct agent、あるいはデプロイ先固有のルーティングでプロキシを迂回していないか確認してください。Axios と Node のバージョンを記録し、cURL でプロキシ単体を別途テストしましょう。リクエストごとの経路を曖昧なく制御したいなら、proxy:false と HttpsProxyAgent を使い、制御可能なエンドポイントで実際の IP を確認してください。
Axios で SOCKS5 プロキシは使えますか?
はい、socks-proxy-agent パッケージ経由で使えます。SOCKS の URL で SocksProxyAgent を作成し、それを Axios の httpsAgent に渡してください。ただし HttpsProxyAgent を同時に渡さないように注意してください。両者は別プロトコルなので、使う agent の種類も違います。
Axios の proxy オプションと httpsAgent の違いは何ですか?
proxy は Axios 標準の設定で、単一の静的プロキシを使う用途に向いており、現行バージョンなら素直なケースでは十分機能します。一方 httpsAgent は HttpsProxyAgent や SocksProxyAgent のようなカスタム Node.js agent を受け取れるため、ルーティング、認証、ローテーションをリクエスト単位で細かく制御できます。これはネイティブの proxy オプションが最初から想定していた用途ではありません。


