- 技術 💻
ERR_CONNECTION_RESETの原因と直し方|RSTの実物で切り分け
結論
ERR_CONNECTION_RESET(接続がリセットされました)は、つながった後の TCP 接続を、相手のサーバーか途中の機器が RST パケットで強制的に切ったときに Chrome が出すエラーです。つながる前に断られる ERR_CONNECTION_REFUSED とは別物で、見る人はプロキシ・VPN・セキュリティソフト、作る人は「誰が RST を送ったか」を tcpdump で確かめるのが近道です。
この記事でわかること
- RST を起こす7つの状況を手元で再現した、tcpdump の原文と Chromium の画面
- 見る人・作る人・途中の機器、それぞれの切り分け表と直し方
- curl (56)・Python・Node.js・Java でどんな文言になるかの対応表
TCP の接続は、普通は FIN というパケットで「もう送るものはありません」と伝え合って閉じます。RST(リセット)はその手順を飛ばして「この接続は無かったことにする」と告げるパケットで、受け取った側のソフトは errno 104 ECONNRESET(Connection reset by peer)を受け取ります。Chrome はこれを ERR_CONNECTION_RESET と表示します。
flowchart TD
C[ブラウザ] --> M{途中の機器<br>FW・プロキシ・LB}
M -->|通す| S[サーバー]
M -->|RST を注入| R2
S -->|つながった後に RST| R2[ERR_CONNECTION_RESET<br>接続がリセットされました]
R2 -.->|比べる| R1[SYN に RST なら REFUSED<br>何も返さず FIN なら EMPTY_RESPONSE]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| ERR_CONNECTION_RESET とは | つながった後の接続が RST で切られた(Chromium のコード -101) | ERR_CONNECTION_RESETとは |
| 接続がリセットされました(見る人) | 再読み込み→別の回線→VPN・プロキシ・拡張機能を切る→セキュリティソフト | 見ている人の直し方 |
| connection reset by peer(作る人) | tcpdump で RST の送信元と TTL を見て、サーバーか途中の機器かを決める | 誰がRSTを送ったか |
| ERR_CONNECTION_REFUSED との違い | REFUSED は SYN への RST(つながる前)、RESET はつながった後 | ERR_CONNECTION_RESETとは |
| アップロードだけ失敗する | サーバーが本文を読まずに閉じると RST になる | 大きなアップロード |
| たまに出る・2回目で直る | keep-alive の期限切れ、LB のアイドルタイムアウトとの競合 | keep-aliveとLB |
| HTTPS だけ出る | TLS の ClientHello に RST が返っている。curl は (35) | 途中の機器がRSTを返す |
| MTU が原因と言われた | 手元では RST ではなく応答待ちのまま止まった | MTUの問題 |
確認環境:Ubuntu 24.04.5 LTS(カーネル 6.18)の上に、ip netns(iproute2 6.1.0)でクライアント・ルーター・サーバーの3つのネットワーク名前空間を作り、veth でつなぎました(10.21.1.2 → 10.21.1.1/10.21.2.1 → 10.21.2.2)。サーバーは Python 3.13.18 の socket で書いた16ポートの実験サーバーで、SO_LINGER による RST、未読データを残した close()、keep-alive のタイムアウトなどを起こしています。RST の注入と大きなパケットの破棄は、ルーターの名前空間の中だけで nftables 1.0.9 の reject with tcp reset・drop を使い、ホストの設定は変えていません。パケットは tcpdump 4.99.4(libpcap 1.10.4)で、ブラウザの表示は Chromium 153.0.8010.12(Playwright 1.63.0・日本語の画面)で、コマンドは curl 8.5.0・Node.js 22.23.4・OpenJDK 21.0.12 で確かめました。エラーコードの定義は Chromium のソース(net_error_list.h)・curl の公式一覧・RFC 9293、ロードバランサーの挙動は AWS の公式ドキュメント、Windows のコマンドは Microsoft Learn で確かめています。図は mermaid 11 で描画を確かめました(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ERR_CONNECTION_RESETの原因と直し方|RSTの実物で切り分け」
ERR_CONNECTION_RESETとは(REFUSED・EMPTY_RESPONSE との違い)
この節では、ERR_CONNECTION_RESET の正確な意味と、似た名前のエラーとの見分け方が分かります。
ERR_CONNECTION_RESET は、Chromium のネットワーク層のエラー -101 で、ソースコードのコメントは「A connection was reset (corresponding to a TCP RST).」です。 つまり「TCP の RST を受け取った」という意味で、HTTP のステータスコードではありません。サーバーが 500 を返したのではなく、HTTP の応答が届く前(または途中)に接続そのものが壊れています。
| Chrome の表示 | 番号 | 意味(Chromium のコメント) | 手元で起こした状況 |
|---|---|---|---|
| ERR_CONNECTION_RESET | -101 | 接続がリセットされた(TCP RST) | サーバーが処理中に落ちた・途中の機器が RST・本文を読まずに閉じた |
| ERR_CONNECTION_REFUSED | -102 | 接続の試みが拒否された | SYN に RST が返った(待ち受けが無い・FW の reject) |
| ERR_CONNECTION_CLOSED | -100 | 接続が閉じられた(TCP FIN) | ― |
| ERR_EMPTY_RESPONSE | -324 | サーバーが何も送らずに接続を閉じた | リクエストを読んでから FIN で閉じた |
| ERR_CONNECTION_TIMED_OUT | -118 | 接続の試みがタイムアウトした | FW の drop(何も返さない) |
| ERR_CONTENT_LENGTH_MISMATCH | ― | Content-Length より短く終わった | 本文の途中で FIN |
ERR_CONNECTION_REFUSED(つながる前)
最初の SYN に RST が返る
ポートで誰も待っていない・FW が reject
tcpdump では SYN → RST の2行だけ
ERR_CONNECTION_RESET(つながった後)
3ウェイハンドシェイクは成功している
リクエストを送った後、応答の途中で RST
サーバーのアプリ・途中の機器・プロキシが候補
Firefox も同じ状態を「接続がリセットされました」という見出しで表示します(Firefox の画面は手元では確かめていません)。「localhost で接続が拒否されました」のほうは関連記事「localhostで接続が拒否されましたの原因と解決方法」で扱っています。
接続がリセットされました:Chromeの画面とtcpdumpの対応
この節では、同じ「接続がリセットされました」でもパケットの流れが違うことを、手元で起こした7つの状況で確かめられます。
Chromium(日本語)に出た画面は、いずれも「このサイトにアクセスできません/接続がリセットされました。/次をお試しください/接続を確認する/プロキシとファイアウォールを確認する/ERR_CONNECTION_RESET」でした。 画面だけでは原因は分かりません。パケットを見ると違いが出ます。
| サーバー側で起こしたこと | Chromium | curl | パケット |
|---|---|---|---|
| リクエストを読んだ後、応答を返さず RST(処理中に落ちた) | ERR_CONNECTION_RESET | (56) Recv failure: Connection reset by peer | サーバーから [R.](TTL 63) |
| リクエストを読んだ後、何も返さず FIN | ERR_EMPTY_RESPONSE | (52) Empty reply from server | サーバーから [F.] |
| 途中のルーターが、リクエストのパケットに RST を返す | ERR_CONNECTION_RESET | (56) Recv failure: Connection reset by peer | 送信元はサーバーのアドレスだが TTL 64 |
| HTTPS の ClientHello に途中の機器が RST | ERR_CONNECTION_RESET | (35) OpenSSL SSL_connect: Connection reset by peer | 517 バイトの ClientHello の直後に [R] |
| SYN に RST(ポートが閉じている) | ERR_CONNECTION_REFUSED | (7) Failed to connect … Connection refused | [S] → [R.] の2行 |
| 本文を 100,000 バイトと宣言し、10,000 バイト送って RST | 途中まで表示したまま、裏で ERR_CONNECTION_RESET | (56) 7,157 バイト受信後に Connection reset by peer | データの後に [R.] |
| 同じことを FIN で閉じる | 途中まで表示、ERR_CONTENT_LENGTH_MISMATCH | (18) transfer closed with 90000 bytes remaining | データの後に [F.] |
| 応答を全部返してから RST | 200 で表示された | 終了コード 0 | 応答の後に [R.](害は無かった) |
「処理中に落ちた」ときの tcpdump の原文です(クライアント側の veth で採取。オプション欄は省いています)。3ウェイハンドシェイク([S]・[S.]・[.])が成功し、GET(77 バイト)を送った 0.8 ミリ秒後に、サーバーから [R.] が返っています。
00:00:00.000000 IP 10.21.1.2.52688 > 10.21.2.2.8014: Flags [S], seq 3926158532, win 64240, length 0
00:00:00.000036 IP 10.21.2.2.8014 > 10.21.1.2.52688: Flags [S.], seq 3382808137, ack 3926158533, win 65160, length 0
00:00:00.000048 IP 10.21.1.2.52688 > 10.21.2.2.8014: Flags [.], ack 1, win 63, length 0
00:00:00.000120 IP 10.21.1.2.52688 > 10.21.2.2.8014: Flags [P.], seq 1:78, ack 1, win 63, length 77
00:00:00.000126 IP 10.21.2.2.8014 > 10.21.1.2.52688: Flags [.], ack 78, win 64, length 0
00:00:00.000968 IP 10.21.2.2.8014 > 10.21.1.2.52688: Flags [R.], seq 1, ack 78, win 64, length 0
同じ状況を curl で見ると、リクエストを送った直後に終わります。
$ curl -v http://10.21.2.2:8014/
> GET / HTTP/1.1
> Host: 10.21.2.2:8014
>
* Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer
REFUSED のほうは、SYN に対して RST が返り、2行で終わります。
00:00:00.000000 IP 10.21.1.2.54224 > 10.21.2.2.8010: Flags [S], seq 3731191252, win 64240, length 0
00:00:00.000018 IP 10.21.2.2.8010 > 10.21.1.2.54224: Flags [R.], seq 0, ack 3731191253, win 0, length 0
ERR_CONNECTION_RESETの原因一覧(見る人・作る人・途中の機器)
この節では、RST が起こる原因を「誰が送ったか」で3つに分けて確かめられます。
RST を送れるのは、サーバーの OS、サーバーのアプリ、途中の機器(ファイアウォール・プロキシ・ロードバランサー・VPN・セキュリティソフト)の3者です。 見る人の端末の設定が原因になるのは、端末の中にプロキシやセキュリティソフトがあって、それが途中の機器として働くときです。
| 誰が | 原因 | よく出る場面 | 手元で確かめた |
|---|---|---|---|
| サーバーのアプリ | 処理中にプロセスが落ちた・再起動した | デプロイ直後・メモリ不足(OOM) | 読んでから RST |
| サーバーの OS | 本文を読み切らずに close()(未読データがあると FIN ではなく RST になる) | 大きなアップロード・413 を返してすぐ閉じる | アップロードの実験 |
| サーバーの OS | 閉じた接続にデータが届いた | keep-alive の期限切れ直後の再利用 | keep-alive の実験 |
| サーバーのアプリ | SO_LINGER(0) など、わざと RST で閉じる設定 | アイドル接続の整理 | 8013 の実験 |
| 途中の機器 | ファイアウォール・IPS の reject with tcp reset |
社内ネットワーク・特定の URL だけ出る | ルーターの nft |
| 途中の機器 | プロキシ・VPN・セキュリティソフトの通信検査 | HTTPS だけ出る・会社の PC だけ出る | 壊れたプロキシ |
| 途中の機器 | ロードバランサーのアイドルタイムアウトとアプリの keep-alive の食い違い | たまに出る・2回目で直る | 公式ドキュメント+実験 |
| 途中の機器 | NAT のテーブルから接続が消えた | 長い間だまっていた WebSocket・DB 接続 | 公式ドキュメントのみ |
Chrome の画面に「プロキシとファイアウォールを確認する」と出るのは、この表の「途中の機器」の行が多いからです。TCP の仕様(RFC 9293)は、RST は「現在の接続に向けられたものではないと分かるセグメントが届いたときに送る」のが原則で、TCP のユーザー(アプリ)はいつでも接続にリセットを発行できる、としています。
見ている人の直し方(接続がリセットされましたが出たとき)
この節では、Web サイトを見ていて ERR_CONNECTION_RESET が出たときに、自分の端末でできることを順に確かめられます。
順番は「自分だけか」を先に決め、その後で端末の中の途中の機器(プロキシ・VPN・セキュリティソフト・拡張機能)を1つずつ外します。 上位の解説が挙げる手順(VPN・TCP/IP のリセット・セキュリティソフト・キャッシュ・プロキシ)はこの中に入っています。
再読み込みし、別のサイトを開く
Chrome は再利用した接続で RST を受けると自分で再試行します。それでも出るなら、別のサイトが開けるかで「回線全体」か「このサイトだけ」かを分ける。
別の回線・別の端末で同じ URL を開く
スマホのモバイル回線で開けるなら、サイトではなく自分の回線か端末が原因。開けないならサイト側で、見る人にできることは無い。
VPN・プロキシを切る
VPN や社内プロキシは通信を検査して切ることがある。Windows は「設定」→「ネットワークとインターネット」→「プロキシ」(Microsoft サポート)、macOS は「システム設定」→「ネットワーク」→接続先の「詳細」→「プロキシ」で確かめる(Apple サポート)。
拡張機能を止める・シークレットウィンドウで開く
広告ブロック・セキュリティ系の拡張機能が通信を止めることがある。Google の案内どおり、全部止めてから1つずつ戻すと原因が分かる。
セキュリティソフトの Web 保護を一時的に止める
HTTPS の検査機能が RST を返すことがある。止めて直るなら、そのサイトを除外に入れて戻す。止めたままにしない。
ルーターを再起動し、必要なら TCP/IP を戻す
Windows は管理者のコマンドプロンプトで netsh winsock reset(Microsoft Learn:Winsock のカタログを初期状態に戻し、壊れた Winsock の設定による問題を直す)を実行して再起動する。セキュリティソフトが入れた LSP も消えるので、最後に回す。
- キャッシュの削除は、このエラーに対しては効きにくい手順です。 RST はキャッシュを読む前の TCP の段階で起きています。ただし、Chrome の案内にある「閲覧データの削除」は、同じ URL で前の失敗を引きずる状況を切る意味で、最後に試す価値はあります。
- どこで切れたかを自分で見たいときは、Chrome の
chrome://net-exportでログを採り、Chromium の netlog viewer で該当の URL を開くと、net_error = -101の行が出ます。
誰がRSTを送ったか:作る人の切り分け手順(tcpdump・TTL・nstat)
この節では、サイトを作る人が「サーバーが送った RST」と「途中の機器が送った RST」を見分ける手順が分かります。
RST の送信元アドレスは当てになりません。 ルーターの名前空間で reject with tcp reset を入れて起こした RST は、送信元がサーバーのアドレス(10.21.2.2)になっていました。見分けたのは TTL です。
$ tcpdump -nn -v -r cap_8009.pcap | grep -oE "ttl [0-9]+|Flags \[[A-Z.]+\]" | paste - -
ttl 64 Flags [S] ← クライアントが送った
ttl 63 Flags [S.] ← サーバーが送った(ルーターを1つ通って 64→63)
ttl 64 Flags [.]
ttl 64 Flags [P.]
ttl 64 Flags [R] ← 「サーバーから」のはずなのに TTL が 64。ルーターが作った RST
サーバー自身が送った RST(8014 の実験)は、SYN/ACK と同じ TTL 63 でした。本物のサーバーのパケットと TTL が違う RST は、途中の機器が注入したものです。この見方は、Wireshark でも同じ欄(IP の Time to live)で確かめられます。
- 1サーバーの直前で tcpdump を採る
tcpdump -i eth0 -nn 'tcp port 443 and tcp[tcpflags] & tcp-rst != 0'。RST がサーバーの NIC から出ていなければ途中の機器 - 2クライアント側でも採り、RST の TTL を SYN/ACK と比べる違えば途中の機器。同じならサーバー
- 3サーバーなら、カーネルの統計で「なぜ」を絞る
nstat -az | grep -E 'TcpExtTCPAbortOn|TcpEstabResets' - 4アプリのログとプロセスの再起動時刻を突き合わせるOOM・デプロイ・ヘルスチェックの失敗で再起動していないか
- 5途中の機器なら、その機器のログを見るFW の reject の規則・IPS のシグネチャ・LB のアイドルタイムアウト
実験サーバーの名前空間で nstat を見ると、RST を送った理由ごとの回数が出ていました。
$ nstat -az | grep -E "TcpEstabResets|TcpExtTCPAbortOn"
TcpEstabResets 38 0.0 ← 確立した接続を RST で終えた回数
TcpExtTCPAbortOnData 26 0.0 ← 閉じた(閉じかけの)接続にデータが届いて RST
TcpExtTCPAbortOnClose 12 0.0 ← 未読のデータを残したまま close() して RST
TcpExtTCPAbortOnTimeout 0 0.0
TcpExtTCPAbortOnLinger 0 0.0
TCPAbortOnClose が増え続けるサーバーは、リクエストの本文を読み切らずに応答して閉じています。 TCPAbortOnData が増えるのは、keep-alive を閉じた直後にクライアントが送ってきているときです。どちらも次の節以降で起こしています。Wireshark での見方は、関連記事「Wiresharkの使い方|画面の見方・フィルター早見表を実例で解説」で扱っています。
サーバーが処理中に落ちたときのRSTと、FINとの違い
この節では、「アプリが落ちた」が RST になる理由と、同じ「何も返さない」でも FIN なら別のエラーになることが分かります。
プロセスが落ちると、OS はそのプロセスが持っていたソケットを閉じます。受信バッファに読んでいないデータが残っていれば、Linux は FIN ではなく RST を送ります。 リクエストを受け取った直後に落ちた場合はたいてい未読データがあるため、クライアントは「接続がリセットされました」になります。手元の実験サーバーでは SO_LINGER(0) で同じ状態を作りました。
LINGER0 = struct.pack("ii", 1, 0) # close() で FIN ではなく RST を送る
def h_read_then_rst(c): # 8014 リクエストを読んだあと、応答を返さずに RST
read_head(c)
c.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, LINGER0)
c.close()
def h_fin_now(c): # 8003 リクエストを読んでから、何も返さずに FIN
read_head(c)
c.close()
同じ「何も返さない」でも
RESET が出たら「落ちた」か「途中の機器」、EMPTY_RESPONSE なら「アプリが自分で閉じた」を先に疑う
FIN のときの tcpdump です。サーバーから [F.] が返り、クライアントも [F.] で応じて、4ウェイで閉じています。RST の行はありません。
00:00:00.000131 IP 10.21.1.2.39766 > 10.21.2.2.8003: Flags [P.], seq 1:78, ack 1, win 63, length 77
00:00:00.000139 IP 10.21.2.2.8003 > 10.21.1.2.39766: Flags [.], ack 78, win 64, length 0
00:00:00.000911 IP 10.21.2.2.8003 > 10.21.1.2.39766: Flags [F.], seq 1, ack 78, win 64, length 0
00:00:00.000990 IP 10.21.1.2.39766 > 10.21.2.2.8003: Flags [F.], seq 78, ack 2, win 63, length 0
応答の途中で落ちたときは、ブラウザの見え方が変わります。Content-Length を 100,000 と宣言して 10,000 バイトで RST したページは、Chromium では途中までの内容(「AAAA…」)が表示されたまま止まり、エラー画面は出ませんでした。裏では requestfailed イベントに net::ERR_CONNECTION_RESET が記録されています。「ページが途中で切れている」という問い合わせの正体は、このパターンのことがあります。
途中の機器(ファイアウォール・IPS)がRSTを返す:HTTPSだけ出る理由
この節では、サーバーは正常なのに途中の機器が RST を注入する状況と、HTTPS だけで出るときの見え方が分かります。
ルーターの名前空間に、SYN は通し、データを含むパケット(PSH)だけに RST を返す規則を入れました。 ハンドシェイクは成功するので REFUSED にはならず、最初のリクエストで RESET になります。URL の検査やシグネチャで止める機器は、この形で動きます。
table inet t21 {
chain forwarding {
type filter hook forward priority filter; policy accept;
iifname "vrc" tcp dport 8009 tcp flags psh / syn,psh reject with tcp reset
iifname "vrc" tcp dport 8443 tcp flags psh / syn,psh reject with tcp reset
iifname "vrc" tcp dport 8010 reject with tcp reset # SYN にも RST → REFUSED
iifname "vrc" tcp dport 8011 drop # 何も返さない → TIMED_OUT
}
}
00:00:00.000000 IP 10.21.1.2.51806 > 10.21.2.2.8009: Flags [S], seq 3212683004, win 64240, length 0
00:00:00.000032 IP 10.21.2.2.8009 > 10.21.1.2.51806: Flags [S.], seq 2251876782, ack 3212683005, win 65160, length 0
00:00:00.000048 IP 10.21.1.2.51806 > 10.21.2.2.8009: Flags [.], ack 1, win 63, length 0
00:00:00.000117 IP 10.21.1.2.51806 > 10.21.2.2.8009: Flags [P.], seq 1:78, ack 1, win 63, length 77
00:00:00.000126 IP 10.21.2.2.8009 > 10.21.1.2.51806: Flags [R], seq 2251876783, win 0, length 0
HTTPS(8443)では、TLS の ClientHello(517 バイト)を送った直後に RST が返りました。curl は (56) ではなく (35) になります。HTTP は開けるのに HTTPS だけ ERR_CONNECTION_RESET になるときは、TLS の中身を検査する機器(セキュリティソフト・社内プロキシ・国や組織の通信制限)を疑います。
$ curl -v -k https://10.21.2.2:8443/
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* Recv failure: Connection reset by peer
* OpenSSL SSL_connect: Connection reset by peer in connection to 10.21.2.2:8443
curl: (35) Recv failure: Connection reset by peer
1reject と drop は見え方が違う
reject with tcp reset は即座に RESET(SYN なら REFUSED)、drop は何も返らず curl (28) Connection timed out after 8002 milliseconds。
2サーバーのログには何も残らない
8009 のリクエストは実験サーバーに届いていない(RST の前に落とされた)。アクセスログに無いのに利用者がエラーを見るのが特徴。
3TTL と到着時刻で見抜く
注入された RST は TTL が本物と違い、往復時間より早く返ることがある。
大きなアップロードだけERR_CONNECTION_RESETになる(本文を読まずに閉じる)
この節では、フォームのアップロードだけが失敗する原因と、サーバー側の正しい閉じ方が分かります。
サーバーがリクエストの本文を読み切らずにソケットを閉じると、未読データのせいで OS が RST を送ります。 実験サーバーの 8015 は、ヘッダーだけ読んで何も返さずに close() しています。クライアントが 2MB の本文を送っている最中に、サーバーから [R.] が返りました(ack 126399 は、12万バイトほど受け取った時点)。
00:00:00.000000 IP 10.21.1.2.44172 > 10.21.2.2.8015: Flags [S], seq 362790253, win 64240, length 0
00:00:00.000030 IP 10.21.2.2.8015 > 10.21.1.2.44172: Flags [S.], seq 3418718287, ack 362790254, win 65160, length 0
00:00:00.000117 IP 10.21.1.2.44172 > 10.21.2.2.8015: Flags [P.], seq 1:159, ack 1, win 63, length 158
00:00:00.000176 IP 10.21.1.2.44172 > 10.21.2.2.8015: Flags [P.], seq 159:7399, ack 1, win 63, length 7240
...
00:00:00.200943 IP 10.21.2.2.8015 > 10.21.1.2.44172: Flags [R.], seq 1, ack 126399, win 96, length 0
Chromium でファイルを選んで送信すると、100KB でも 20MB でも「接続がリセットされました」の画面になり、POST … net::ERR_CONNECTION_RESET が記録されました。curl は (56) です。
直し方は「閉じる前に応答を返し、本文を読み切る(または読み捨てる)」です。実験サーバーの 8004 は、同じ状況で先に 413 Content Too Large を返してから閉じるようにしたところ、Chromium は「too large」の画面(413)を表示し、curl は HTTP error before end of send, stop sending と出して終了コード 0 で終わりました。パケットには RST が残っていますが、クライアントは応答を先に読んでいるので、利用者には 413 として見えます。
- 1上限を超えたら、閉じる前に 413 を返すnginx の client_max_body_size も 413 を返す。アプリで判定するときも同じ順番にする
- 2413 を返したあと、本文を読み捨ててから閉じる読み捨てないと未読データで RST になり、クライアントの実装によっては 413 を読む前に切れる
- 3クライアントには Expect: 100-continue を使わせるcurl は大きな本文(手元では 2MB のファイル)で自動的に付け、サーバーの 413 を本文を送る前に受け取れた
- 4nstat の TcpExtTCPAbortOnClose を監視に入れる増え続けていれば、どこかで読み残して閉じている
keep-aliveの期限切れとロードバランサーのアイドルタイムアウト(たまに出る)
この節では、「たまに出て再読み込みで直る」ERR_CONNECTION_RESET の仕組みと、サーバー・LB の設定の決め方が分かります。
keep-alive で使い回している接続を、サーバーがアイドルタイムアウトで閉じた直後に、クライアントが次のリクエストを送ると、閉じた接続にデータが届くのでサーバーの OS は RST を返します。 実験サーバーの 8007 は、2秒だれも送って来なければ FIN で閉じます。1 回目のリクエストの 3 秒後に 2 回目を送ったときのパケットです。
00:00:00.000093 IP 10.21.1.2.54536 > 10.21.2.2.8007: Flags [P.], seq 1:72, ack 1, win 63, length 71 ← 1回目の GET
00:00:00.000566 IP 10.21.2.2.8007 > 10.21.1.2.54536: Flags [P.], seq 1:138, ack 72, win 64, length 137 ← 200 OK
00:00:02.001646 IP 10.21.2.2.8007 > 10.21.1.2.54536: Flags [F.], seq 138, ack 72, win 64, length 0 ← 2秒後、サーバーが FIN
00:00:02.045603 IP 10.21.1.2.54536 > 10.21.2.2.8007: Flags [.], ack 139, win 63, length 0
00:00:03.001118 IP 10.21.1.2.54536 > 10.21.2.2.8007: Flags [P.], seq 72:143, ack 139, win 63, length 71 ← 閉じた接続に 2回目の GET
00:00:03.001156 IP 10.21.2.2.8007 > 10.21.1.2.54536: Flags [R], seq 2879432679, win 0, length 0 ← RST
クライアントの実装で、見え方が変わりました。
| クライアント | 2回目の結果 | 理由 |
|---|---|---|
| Python http.client(GET) | RemoteDisconnected: Remote end closed connection without response | FIN を先に読んでいた |
| Python http.client(1MB の POST) | BrokenPipeError: [Errno 32] Broken pipe | 送っている途中で RST が届いた |
| Python http.client(サーバーが RST でアイドルを閉じる 8013) | ConnectionResetError: [Errno 104] Connection reset by peer | RST を受けた接続に送った |
| Node.js http.Agent({ keepAlive: true }) | 200(新しい接続を開いた) | FIN・RST を受けた時点でプールから外す |
| Chromium(3秒後に再読み込み) | 200 | 同上。再利用した接続の失敗は自動で再試行する |
危ないのは、FIN がクライアントに届く前にリクエストが送られた瞬間(数ミリ秒の競合)です。 クライアントは「送った後に RST を受けた」ことになり、Node.js なら read ECONNRESET、ブラウザなら ERR_CONNECTION_RESET になります。手元の名前空間は往復が 0.1 ミリ秒未満のため、この競合そのものは起こせませんでしたが、パケットの流れは上のとおりです。
ロードバランサーが間にあるときは、同じ競合が LB とアプリの間で起こります。AWS の公式ドキュメント(Application Load Balancer)は、アイドルタイムアウトの既定を 60 秒(1〜4,000 秒)とし、アプリのアイドルタイムアウトを LB より長くすることを推奨しています。短いと、アプリが閉じた直後に LB がリクエストを送ってしまい、LB は利用者に 502 Bad Gateway を返す、と書かれています。
アプリ > LB
アプリの keep-alive タイムアウトは LB のアイドルタイムアウトより長く。閉じるのはいつも外側から。
AWS の推奨
Node.js は 5 秒が既定
server.keepAliveTimeout の既定は 5,000 ミリ秒。LB の 60 秒より短いので、ALB の後ろでは伸ばす。
Node.js 公式
クライアントは冪等なら1回だけ再送
GET など安全なリクエストは、ECONNRESET のとき新しい接続で1回だけやり直す。POST は二重登録に注意。
curl・Chrome がしている動き
RST で閉じない
アイドル接続の整理に SO_LINGER(0) を使うと、相手は必ず「リセットされました」を見る。FIN で閉じる。
8013 の実験
タイムアウトの値の決め方は関連記事「Connection refused・Read timed outの違いと直し方」と、TIME_WAIT や keep-alive の話は関連記事「TCPの落とし穴8選|TIME_WAIT・40ms遅延の正体」で扱っています。
プロキシがRSTを返すとき(会社のPCだけ出る)
この節では、ブラウザとサーバーの間のプロキシが原因のときに、何が見えるかが分かります。
プロキシ経由では、ブラウザが TCP でつないでいる相手はプロキシです。プロキシが RST を返せば、サーバーが正常でも ERR_CONNECTION_RESET になります。 ルーターの名前空間に、リクエストを受け取った直後に RST で切る「壊れたプロキシ」(10.21.1.1:3128)を置きました。
$ curl -v -x http://10.21.1.1:3128 http://10.21.2.2:8001/
> GET http://10.21.2.2:8001/ HTTP/1.1
> Host: 10.21.2.2:8001
> Proxy-Connection: Keep-Alive
>
* Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer
$ curl -v -x http://10.21.1.1:3128 https://10.21.2.2:8443/
* Establish HTTP proxy tunnel to 10.21.2.2:8443
> CONNECT 10.21.2.2:8443 HTTP/1.1
* Recv failure: Connection reset by peer
curl: (56) Recv failure: Connection reset by peer
Chromium を --proxy-server=http://10.21.1.1:3128 で起動して同じ URL を開くと、直接開けば 200 の 8001 が「接続がリセットされました」になりました。プロキシを外すと開けます。会社の PC だけ出る、自宅では出ない、というときはここです。
| 確かめること | やり方 |
|---|---|
| プロキシが設定されているか | Chrome の chrome://net-internals/#proxy、または OS のプロキシ設定。環境変数 http_proxy・HTTPS_PROXY も見る |
| プロキシを外すと直るか | curl なら --noproxy '*'。直れば原因はプロキシ側 |
| プロキシ自身は生きているか | curl -v -x プロキシ http://…。CONNECT に応答が返るか |
| PAC・透過プロキシ | 設定画面に無くても、ルーターやセキュリティソフトが透過プロキシになっていることがある |
プロキシの仕組みと設定の見方は、関連記事「プロキシとは?仕組みをわかりやすく|PCの設定確認・開発ツール・407対処」で扱っています。
MTUの問題はERR_CONNECTION_RESETになるのか(実測)
この節では、原因としてよく挙がる MTU(1回に送れるパケットの大きさ)が、手元ではどう見えたかが分かります。
手元では、MTU の問題は RST ではなく「小さいページは開けるのに大きいページは応答待ちのまま止まる」という形で現れました。 ルーターの名前空間で、サーバーからの 1,300 バイトを超えるパケットだけを黙って捨てる規則(経路の途中で MTU が小さく、ICMP も届かない「ブラックホール」の再現)を入れました。
$ curl -sS -m 10 -o /dev/null -w 'rc=%{http_code} size=%{size_download}\n' http://10.21.2.2:8001/
rc=200 size=11 ← 11 バイトの応答は届く
$ curl -v -m 15 -o /dev/null http://10.21.2.2:8012/ ← 200,000 バイトの応答
> GET / HTTP/1.1
* Operation timed out after 15002 milliseconds with 0 bytes received
curl: (28) Operation timed out after 15002 milliseconds with 0 bytes received
$ ss -tin (サーバー側。送ったのに ACK が返らず再送している)
mss:1448 pmtu:1500 bytes_retrans:47784 unacked:10 retrans:0/33
ブラウザならくるくる回ったあと ERR_CONNECTION_TIMED_OUT か、ヘッダーだけ届いて止まる見え方です。途中の機器が「待ちきれず」に接続を RST で片付けるときだけ、結果として RESET になります。MTU が疑わしいときは、VPN を使っているなら VPN 側の MTU を小さくして試し、サーバー側は ss -tin の pmtu・bytes_retrans と、特定の大きさから上だけ届かないかを見ます。サーバー側では sysctl net.ipv4.tcp_mtu_probing=1(手元の既定は 0)で、再送が続いたときに小さいパケットを試す動きにできます。切り分けの流れは関連記事「ネットワークの切り分け8選|pingは通るのに繋がらない」で扱っています。
言語・ツール別のconnection reset by peerの文言(curl 56・Python・Node・Java)
この節では、同じ RST を受けたときに、よく使うツールと言語がどんな文言を出すかが分かります。ログからの逆引きに使えます。
実験サーバーの4つの状況(読んでから RST・読んでから FIN・途中の機器が RST・SYN に RST)に、同じクライアントからつないだ結果です。
| クライアント | RST(サーバー・途中の機器) | FIN(空応答) | SYN に RST(拒否) |
|---|---|---|---|
| Chromium 153 | ERR_CONNECTION_RESET | ERR_EMPTY_RESPONSE | ERR_CONNECTION_REFUSED |
| curl 8.5 | (56) Recv failure: Connection reset by peer/HTTPS は (35) | (52) Empty reply from server | (7) Failed to connect … Connection refused |
| Python 3.13 urllib | ConnectionResetError: [Errno 104] Connection reset by peer | RemoteDisconnected: Remote end closed connection without response | URLError: [Errno 111] Connection refused |
| Node.js 22 http.get | ECONNRESET: read ECONNRESET | ECONNRESET: socket hang up | ECONNREFUSED: connect ECONNREFUSED |
| Node.js 22 fetch | fetch failed(cause: read ECONNRESET) | fetch failed(cause: UND_ERR_SOCKET other side closed) | fetch failed(cause: connect ECONNREFUSED) |
| Java 21 HttpURLConnection | java.net.SocketException: Connection reset | SocketException: Unexpected end of file from server | java.net.ConnectException: Connection refused |
- Node.js の「socket hang up」は FIN(応答なしで閉じた)で、「read ECONNRESET」が RST です。 どちらも
e.codeは ECONNRESET なので、message で見分けます。 - curl の (56) は公式の一覧で CURLE_RECV_ERROR「Failure with receiving network data.」、(55) CURLE_SEND_ERROR は送信側の失敗、(52) CURLE_GOT_NOTHING は「何も返って来なかった」、(35) は TLS の接続の失敗です。
- nginx を前に置いているときは、上流(アプリ)からの RST を受けるのは nginx です。公式ドキュメントでは、
proxy_next_upstreamの既定error timeoutの「error」が「接続の確立・リクエストの送信・応答ヘッダーの読み取り中のエラー」で、次のサーバーがあればそちらを試し、無ければ利用者には 502 として見えます(手元では nginx を起動していません)。
よくあるつまずきと判断表
この節では、問い合わせの文言から原因の候補を引ける表と、作る人が次に打つ手を決める判断表が分かります。
| つまずき(原文) | 手元で同じになった状況 | 見るところ |
|---|---|---|
| このサイトにアクセスできません/接続がリセットされました。/ERR_CONNECTION_RESET | 8014・8009・8443・8015・プロキシ | tcpdump の RST の TTL |
| curl: (56) Recv failure: Connection reset by peer | 同上(HTTP) | サーバーの nstat・プロセスの再起動 |
| curl: (35) OpenSSL SSL_connect: Connection reset by peer | 8443(ClientHello に RST) | TLS を検査する機器・プロキシ |
| curl: (52) Empty reply from server | 8003(FIN で閉じた) | アプリの例外処理・タイムアウト |
| curl: (18) transfer closed with 90000 bytes remaining to read | 8006(本文の途中で FIN) | Content-Length と実際の長さ |
| ページが途中で切れて表示される | 8005(本文の途中で RST) | requestfailed・アプリの途中の例外 |
| Error: read ECONNRESET(Node.js) | 8014・8009 | keep-alive のタイムアウトの大小 |
| Error: socket hang up(Node.js) | 8003 | FIN。アプリが応答せずに閉じた |
| java.net.SocketException: Connection reset | 8014・8009 | 同上 |
作る人の判断表
| 観察 | 判断 | 次の手 |
|---|---|---|
| サーバーの NIC で RST が出ていない | 途中の機器 | FW・IPS・LB・プロキシのログ。TTL を比べる |
| RST の直前にプロセスの再起動がある | アプリが落ちた | OOM・例外・ヘルスチェックを直す。graceful shutdown を入れる |
| TcpExtTCPAbortOnClose が増える | 本文を読み切らずに閉じている | 413 を返してから読み捨てる |
| TcpExtTCPAbortOnData が増える・たまに出る | keep-alive の競合 | アプリのタイムアウトを LB より長く。冪等な再送 |
| HTTPS だけ・特定の社内だけ | TLS 検査・プロキシ | 除外設定・証明書の配布 |
| 大きな応答だけ止まる(RST ではない) | MTU のブラックホール | 経路の MTU・VPN の MTU・tcp_mtu_probing |
よくある質問
Q. ERR_CONNECTION_RESET とは何ですか? A. Chrome が「TCP の接続が RST(リセット)で切られた」ときに出すエラーで、Chromium の番号は -101 です。サーバーか途中の機器が、つながった後の接続を強制的に終わらせています。HTTP のステータスコードではありません。
Q. 接続がリセットされました、と出たら何をすればよいですか? A. 再読み込み→別のサイト・別の回線で開けるか→VPN・プロキシを切る→拡張機能を止める→セキュリティソフトの Web 保護を止める、の順に試します。別の回線でも開けないならサイト側の問題で、見る人にできることはありません。
Q. ERR_CONNECTION_REFUSED との違いは何ですか? A. REFUSED は最初の SYN に RST が返り、つながる前に断られています(ポートで誰も待っていない・ファイアウォールの reject)。RESET はつながった後に切られています。tcpdump で見ると、REFUSED は [S] → [R.] の2行で終わります。
Q. connection reset by peer は誰が悪いのですか? A. 「peer(相手)が接続をリセットした」と OS が報告した、という意味です。相手のアプリが落ちた、相手の OS が未読データを残して閉じた、途中の機器が RST を注入した、のどれかで、手元では RST の TTL を SYN/ACK と比べて見分けました。
Q. HTTPS のサイトだけ出ます。 A. TLS の ClientHello に RST が返っている形です。curl では (35) になります。通信を検査するセキュリティソフト・社内プロキシ・ネットワークの制限が候補で、別の回線で開けるかを確かめます。
Q. ファイルをアップロードするときだけ出ます。 A. サーバーが本文を読み切らずに閉じると、OS が RST を送ります。作る側は、上限を超えたら 413 を返してから本文を読み捨てて閉じます。見る側は、ファイルを小さくして試すと切り分けられます。
Q. たまに出て、再読み込みすると直ります。 A. keep-alive の接続をサーバーや LB が閉じた直後に、次のリクエストを送ってしまう競合が典型です。アプリの keep-alive タイムアウトを LB のアイドルタイムアウトより長くし、クライアントは冪等なリクエストだけ新しい接続で1回やり直します。
Q. サーバーのログに何も残っていません。 A. 途中の機器が RST を返していると、リクエストはサーバーに届きません。手元でもルーターが RST を返した 8009 へのリクエストは、サーバーに記録が残りませんでした。サーバーの NIC で tcpdump を採り、RST がサーバーから出ているかを見ます。
Q. MTU が原因と言われましたが、本当ですか? A. 手元では、MTU のブラックホールは RST ではなく「小さいページは開けて大きいページは止まる」形になりました。RESET になるのは、途中の機器が止まった接続を RST で片付けたときです。VPN 利用時は VPN の MTU を小さくして試します。
Q. Windows の netsh winsock reset は効きますか? A. Microsoft Learn によると、Winsock のカタログを初期状態に戻し、壊れた Winsock の設定によるネットワークの問題を直すコマンドです。セキュリティソフトなどが入れた LSP も消えるため、ほかの手順を試したあとの最後の手段にし、実行後は再起動します。
Q. サーバー側で RST を返すのは、いつも悪いことですか? A. いいえ。ポートで待ち受けていないときの RST(REFUSED)は仕様どおりの正しい動きです。問題になるのは、つながった後にアプリの都合で RST になる場合で、本文を読み切る・FIN で閉じる・応答を返してから閉じる、で避けられます。
Q. Chrome はリセットされた接続を自動で再試行しますか? A. 手元では、サーバーが RST でアイドル接続を閉じた 3 秒後に再読み込みしても 200 で開けました。再利用した接続の失敗は新しい接続でやり直しています。最初のリクエストで RST を受けたときは、エラー画面になります。
まとめ
- ERR_CONNECTION_RESET は「つながった後の接続が RST で切られた」。REFUSED は「つながる前」、EMPTY_RESPONSE は「何も返さず FIN」で、tcpdump を見れば区別できる。
- RST を送るのはサーバーの OS・サーバーのアプリ・途中の機器の3者。送信元アドレスは当てにならず、手元ではルーターが注入した RST は TTL 64、サーバー自身の RST は TTL 63 だった。
- 見る人は、別の回線で開けるかを先に確かめ、VPN・プロキシ・拡張機能・セキュリティソフトの順に外す。キャッシュ削除は効きにくい。
- 作る人は、本文を読み切ってから閉じる(413 を返してから読み捨てる)、アイドル接続は FIN で閉じる、アプリの keep-alive タイムアウトを LB より長くする。nstat の TCPAbortOnClose・TCPAbortOnData で原因を絞れる。
- HTTPS だけ出るなら TLS 検査、たまに出るなら keep-alive の競合、アップロードだけなら未読データ、大きなページが止まるだけなら MTU(RST ではない)を疑う。
参考・出典
確認日はいずれも 2026年10月29日です。
- Chromium「net/base/net_error_list.h」(ERR_CONNECTION_RESET = -101 ほか):https://chromium.googlesource.com/chromium/src/+/main/net/base/net_error_list.h
- Google Chrome ヘルプ「ウェブページの接続エラーを解決する」:https://support.google.com/chrome/answer/6098869?hl=ja
- curl「libcurl error codes」(CURLE_RECV_ERROR 56 ほか):https://curl.se/libcurl/c/libcurl-errors.html
- IETF「RFC 9293 Transmission Control Protocol (TCP)」3.5.2 Reset Generation・3.5.3 Reset Processing:https://www.rfc-editor.org/rfc/rfc9293.html
- AWS「Application Load Balancer の属性を編集する」(Connection idle timeout):https://docs.aws.amazon.com/elasticloadbalancing/latest/application/edit-load-balancer-attributes.html
- Microsoft サポート「Windows でプロキシ サーバーを使用する」:https://support.microsoft.com/ja-jp/windows/windows-でプロキシ-サーバーを使用する-03096c53-0554-4ffe-b6ab-8b1deee8dae1
- Apple サポート「Mac でプロキシサーバの設定を変更する」:https://support.apple.com/ja-jp/guide/mac-help/mchlp2591/mac
- Microsoft Learn「netsh winsock」:https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/netsh-winsock
- netfilter「nft(8) manual page」(reject statement):https://www.netfilter.org/projects/nftables/manpage.html
- Node.js「HTTP」(server.keepAliveTimeout):https://nodejs.org/api/http.html
- nginx「Module ngx_http_proxy_module」:https://nginx.org/en/docs/http/ngx_http_proxy_module.html
- Mozilla サポート「Firefox でウェブサイトを読み込めない」:https://support.mozilla.org/ja/kb/firefox-cant-load-websites-other-browsers-can
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ERR_CONNECTION_RESETの原因と直し方|RSTの実物で切り分け」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。