521
IETF ではなく Cloudflare 独自のコードで、5xx の中でいちばん狭い失敗を表します。オリジンが Cloudflare の TCP 接続を能動的に拒否した——遅かったのでも、経路を間違えたのでもなく、何かが「駄目だ」と言ったのです。
同じ 3 桁でも、リクエストのどちら側にいるかで別々の問題になります。自分に当てはまるブロックを読んでください。
これが出ている理由
ここにあなたの仕事はありません。それを素早く確定させることが貢献です。そのゾーンへのすべてのリクエストが同じように、しかも即座に失敗します——HTML の文書も、API も、ハッシュ付きのアセットバンドルも全部。失敗はあなたのアプリケーションのコードが登場する前に起きているからです。目の前にあるのは Cloudflare 自身の HTML ページで、`server: cloudflare` ヘッダーと `cf-ray` を持っていて、クライアントの `res.json()` は `<` でパースエラーになります。
やること
まずサイト全体で起きていることを確定させてください。この 1 つの事実が調査全体の行き先を変えます。1 つのパスだけの 521 は本当の 521 ではなく、オリジン自身の応答が中継されているだけです。本物の 521 は静的アセットも巻き添えにします。次に、意味のある文字列を 2 つ集めて渡してください——応答ヘッダーの `cf-ray` の値と、正確な時刻。運用側が Cloudflare 側でそのリクエストを見つけるのに使うのがこれです。クライアントが事態を悪化させないようにすること。拒否しているオリジンへの自動再試行ループは何も達成せず、回復を遅らせるだけなので、再試行には固い上限を付けてください。そして CORS に時間を使わないこと。コンソールには CORS エラーが出ますが、エラーページは `access-control-allow-origin` を持たないので、ブラウザが本当の失敗の上に CORS の苦情を積んでいるだけで、その CORS のメッセージは症状です。
これが出ている理由
オリジン上の何かが、ハンドシェイクではなく拒否を Cloudflare に返しました。候補は 3 つしかありません。プロセスが動いていないかクラッシュしていて、ソケットを誰も握っていない。プロセスは動いているが違うインターフェイスに bind されている——`127.0.0.1:8080` のアプリケーションは、停止したプロセスと同じくらい完全に外からの接続を拒みます。あるいはファイアウォールが Cloudflare を名指しで拒否している。これはデプロイ無しで起きる場合で、fail2ban、新しいセキュリティグループのルール、あるいは全トラフィックが一握りのプロキシアドレスから来るのを見てアドレス帯を BAN したホストベースのブロッカーが犯人です。
やること
この順で確認してください。どれも安上がりで、それぞれが次を除外します。何かが listen しているか——オリジンで `ss -ltnp`——そしてループバックではなく `0.0.0.0` に bind されているか。SSL/TLS モードが要求するポートか——Cloudflare は Flexible に 80 番、Full と Full (Strict) に 443 番と明記していますし、そもそも Cloudflare は公開済みのポート一覧しかプロキシしないので、3000 番のサービスは見えません。Cloudflare は通してもらえているか——Cloudflare が示す対処は、オリジンのファイアウォールやセキュリティソフトウェアで全 IP レンジを許可し、そのアドレスがブロックもレート制限もされていないことを確認することです。レート制限はブロックと同じくらい重要です。プロキシされたトラフィックはサイト全体のリクエストを少数の送信元アドレスに集中させ、素朴なルールにはまさに攻撃のように見えます。そのうえで、Cloudflare も挙げているクラッシュについてオリジン自身のエラーログを読んでください。そしてこれを診断可能にしている非対称性を覚えておくこと。REJECT に設定したファイアウォールは 521 を生み、同じファイアウォールを DROP に設定すると 522 を生みます。つまりコードが、探すべきルールの種類を教えてくれます。
これが出ている理由
いま読んでいるページを書いたのは Cloudflare で、そこはウェブサイトの手前に立っていて正常に動いています。その後ろにあるサイト自身のサーバーが接続を受け付けていません。ブラウザにも端末にもネットワークにも関係ありません。同じページが世界中の全員に出ますし、待たされたあとではなく即座に出ます。たいていはサイトのサーバーが止まったか設定を誤ったという意味で、誰かが気づくまで続きます。
やること
手元で試せることは本当にありません。リロード、Cookie の削除、ブラウザの変更、DNS の変更、ルーターの再起動——どれも遠くのサーバーに接続を受け付けさせることはできません。数分待って 1 回だけリロードしてください。報告するなら、Cloudflare のページの下部に印字されている Ray ID と正確な時刻の 2 つが送る価値のあるものです。サイト運営者の記録の中で、そのリクエストを一意に特定できます。有料のサービスなら、運営者がすでに把握しているかを知るいちばん速い手段はステータスページか公式アカウントです。521 は全訪問者に同時に影響するので、気づかれるのも早い種類の障害です。
失敗した URL に対してそのまま実行してください。エラーページを表示せずにステータスだけを出すので、ブラウザが描画したものではなくサーバーが言ったことが見えます。
curl -sS -o /dev/null --connect-timeout 5 -w '\n%{http_code} connect=%{time_connect}s\n' --resolve example.com:443:203.0.113.10 https://example.com/`--resolve` は、元のホスト名と SNI を送りつつ指定したアドレスへ curl を接続させるので、エッジを経路から外したうえで、Cloudflare がオリジンにダイヤルするときの動作を再現できます。例のアドレスは自分の本物のオリジンアドレスに置き換えてください。`--connect-timeout 5` は拒否を素早く済ませ、同じくらい有用なことに、無言のドロップと区別してくれます。結果は 3 通りあり、それぞれ別のバグです。`curl: (7) Failed to connect to example.com port 443: Connection refused` が再現です。オリジンは Cloudflare を拒んだのとまったく同じようにあなたを拒んでいて、答えはオリジン側にあります——listener が無い、bind するアドレスが違う、ポートが違う、あるいはファイアウォールが reject に設定されている。5 秒の接続タイムアウトで終わる無反応はそもそも 521 ではありません。落とされた SYN を Cloudflare は 522 として報告するので、同じファイアウォールの DROP ルールと REJECT ルールは 2 つの違うエラー番号を生みます。そして普通に応答が返るなら、オリジンはあなたからの接続は受け付けて Cloudflare からのそれは受け付けていないということで、サービスではなく送信元アドレスのフィルタリングをまっすぐ指しています。Cloudflare の公開 IP レンジと、オリジンのファイアウォールを突き合わせてください。そのあと `--resolve` 無しで同じリクエストを実行してエッジの答えを見て、`cf-ray` ヘッダーを読みます。運用側が引ける ID です。
521 は RFC 9110 にありません。IETF に登録された 5xx は 511 で止まっていて、520 から 526 の帯は Cloudflare 独自の拡張です。文書化しているのは Cloudflare だけですし、生成されるのは Cloudflare を経由してプロキシされたトラフィックだけなので、グレークラウドの DNS レコードがこれを返すことはありません。Cloudflare の定義は正確です。エラー 521 は、オリジンのウェブサーバーが Cloudflare からの接続を拒否したときに発生する。この「拒否」という語が、この番号の価値のすべてです。拒否は一つの答えです——TCP の RST か ICMP の unreachable か。つまりパケットはオリジンのネットワークまで到達していて、そこにある何かがそれを断ったということで、これだけで隣接する 3 つのコードが一度に除外されます。522 ではありません。Cloudflare はそちらをタイムアウトと定義していて、SYN から 19 秒以内に SYN+ACK が無い、あるいは接続確立後 90 秒以内にリクエストへの応答が無い場合です。523 でもありません。そちらは Cloudflare がオリジンにまったく到達できない場合で、たいていは間のネットワーク機器がオリジンのアドレスへの経路を持っていないからです。520 でもありません。そちらはオリジンが空・不明・予期しない何かで答えた場合です。Cloudflare は 521 の原因として 2 つ——オフラインになったオリジンのウェブサーバーアプリケーションと、ブロックされた Cloudflare のリクエスト——を挙げていて、対処はそこから素直に導かれます。オリジンが応答することを確認する。アプリケーションのクラッシュや障害についてオリジンのエラーログを確認する。Cloudflare の IP アドレスがブロックもレート制限もされていないことを確認する。オリジンのファイアウォールやその他のセキュリティソフトウェアで Cloudflare の全 IP レンジを許可する。そしてオリジンが、SSL/TLS モードの要求するポート——Flexible なら 80 番、Full と Full (Strict) なら 443 番——で実際に bind して listen していることを確認する。最後の項目がいちばん時間を吸う場合を拾います。Cloudflare がプロキシするポートは決まっているからです。HTTP は 80・8080・8880・2052・2082・2086・2095、HTTPS は 443・2053・2083・2087・2096・8443。それ以外で listen しているオリジンは、どれほど健全でもプロキシからは到達できません。
| 紛らわしいコード | 見分け方 |
|---|---|
522 | どちらも Cloudflare がオリジンへの使える接続を得られなかったという意味で、違いはオリジンが答えたかどうかです。521 は拒否——答えの一種なので即座に返ります。522 はタイムアウトで、Cloudflare の定義は正確です。自分の SYN から 19 秒以内に SYN+ACK が無い、または接続確立後 90 秒以内にリクエストへの応答が無い。同じファイアウォールのルールが、REJECT か DROP かによってどちらかを生みます。 |
523 | 523 は Cloudflare がオリジンにまったく到達できない場合で、ドキュメントはその原因を、間のネットワーク機器がオリジンのアドレスへの経路を持っていないことに帰しています。実例として挙げられているのは AWS のルートテーブルで、広すぎる `172.0.0.0/8` のエントリが Cloudflare 自身の `172.64.0.0/13` レンジを飲み込み、戻りのトラフィックをどこか私設の場所へ送ってしまうというものです。つまり 521 はパケットが届いたうえで拒まれた、523 はそもそも届かなかった、です。 |
520 | 520 はオリジンが、Cloudflare には使えない何か——空・不明・予期しないもの、そして Cloudflare の 128 KB の上限を超える応答ヘッダーも含みます。これは過剰な Cookie が思ったより頻繁に到達する境界です——で答えた場合です。接続としては 521 の反対側の端で、520 ではハンドシェイクもリクエストも応答も起きていて、間違っていたのは応答の中身だけです。 |
| 502 | 502 は、内側のサーバーからの不正な応答に対してどのプロキシも返せる IETF のコードで、拒否もリセットも解釈不能な返答もまとめて覆います。521 は同じ分類を原因 1 つまで絞り込んだ Cloudflare 版で、520 から 526 の帯が存在する理由もそこにあります。汎用の 502 では 4 つのことを調べる羽目になりますが、521 は「オリジンが接続を拒否した」と告げて、listener とファイアウォールへまっすぐ送ってくれます。 |
| 524 | 比べれば 524 のほうが安心できるコードです。接続が成功したことを証明しているからです。Cloudflare はオリジンに接続し、そのあと 125 秒間、来ない HTTP 応答を待ちました。つまり 524 は 521 が投げかける問い——listener は上がっているか、ポートは合っているか、ファイアウォールは Cloudflare を通しているか——を全部否定して、調査をまるごとアプリケーションの中へ移します。 |
どれもブラウザ内で完結します。アップロードは発生しません。
521 を調べているとき、ついでに読むことになりがちなコードです。
ページではなく応答ヘッダーを読んでください。curl -sS -o /dev/null -D - https://example.com/path が本文なしでヘッダーだけを出し、server・via・cf-ray の 3 つで、答えたのがどの層かが分かります。cf-ray の値があれば応答を扱ったのは Cloudflare で、その値はサポートが聞いてくる ID です。エッジを完全に外して確かめたいなら、--resolve example.com:443:203.0.113.10 を付けて同じリクエストを投げ直します。元のホスト名と SNI を送りつつ、指定したオリジンのアドレスへ接続するので、答えが変われば、エッジとオリジンの言い分が食い違っているということです。
ありません。分岐条件にしてはいけません。RFC 9112 はクライアントに理由句を無視するよう求めていますし、サーバーは自由に変えられますし、HTTP/2 と HTTP/3 にはそもそも理由句が存在しません。HTTP/1.1 では 404 Not Found として届くものが、HTTP/2 では素の 404 として届きます。このサイトが登録済みの理由句を載せているのは、それが検索される語であり HTTP/1.1 のログに出る文字列だからで、何かのソフトウェアがそれに依存しているからではありません。
5xx と 429 は再試行してよく、4xx はしないでください。次に投げても中身は同じだからです。応答に Retry-After が付いていればそれに従ってください。RFC 9110 がまさにこのために定義していて、値は秒数でも日時でも構いません。付いていなければ、ジッター付きの指数バックオフと明確な上限を使い、しかも冪等なメソッドに限ってください。再試行された POST はカードに二重で課金しかねません。すでに失敗しているサーバーへの再試行の嵐は、短い障害を長い障害に変える典型的な経路です。
変えられます。守るべき規則は 1 つだけ、そのコードが本当であること。応答を自動で読むもの——検索エンジン、監視、キャッシュ、クライアント側の再試行ロジック——はすべて数字だけで判断し、ページの中身は一切見ません。エラーページを 200 で返せば自分の監視から障害が隠れますし、無いページを 200 で返せばエラーが本文として索引されますし、単に不正なリクエストに 500 を返せば、当番の人をスタックの間違った半分へ送り込むことになります。
521 でまだ詰まっているなら、ステータスコード一覧をすべて見る。あるいは上に戻って、自分の立ち位置に向けて書かれたブロックを読んでください。