SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor ・更新日 2026-09-05

SearXNGの429エラーとレート制限を解決する方法

SearXNGの429エラーは、自分のリミッターか検索エンジンによるサーバーIP拒否が原因です。ログで原因を約1分で切り分け、適切な設定を確認できます。

SearXNG が 429 エラーを返す理由

自己ホスト型の SearXNG インスタンスが 429 エラーを返す原因は、互いに関係のない2つです。通常、修正が必要なレート制限は想定しているものとは異なります。1つ目の原因はローカル側にあります。SearXNG 自身のリミッターがリクエストを bot からのものと判断し、Too Many Requests にステータス 429 を返します。2つ目は upstream 側の原因です。検索エンジンがサーバーの IP アドレスを拒否すると、ユーザーには429ではなく、結果が一部欠落した検索結果ページとして表示されます。

この2つのケースに共通する解決策はありません。リミッターは自分で管理しているため、変更できます。upstream によるブロックは Google 側で発生するため、settings.yml の設定を変更しても解除されません。どちらのケースかは、約1分でログから判断できます。まずログを確認してください。

このガイドでは、自分の VPS 上で自己ホスト型 SearXNG インスタンスを構築する方法で説明しているコンテナインストールを前提とします。以下の設定名はすべて、2026年8月に確認した最新の upstream ドキュメントとソースコードに基づいています。

設定を変更する前にログを読む

ログを開いた状態で問題を再現します。

cd ./searxng/
docker compose logs -f searxng-core

制限メッセージは searx.limiter という名前のロガーから出力され、IP アドレスが示されます。ブロックリストに該当した場合は BLOCK 203.0.113.10: matched BLOCKLIST、許可リストに該当した場合は PASS 203.0.113.10: matched PASSLIST と記録されます。制限機能がカウンターストアに接続できない場合は The limiter requires Valkey, please consult the documentation と記録されます。この場合、何もカウントされていません。

個々のボットチェックは debug レベルで記録されるため、デフォルトでは確認できません。settings.yml で 1 回のテストだけ debug を有効にします。

general:
  debug: true

その後のログには、クライアントネットワークの情報とともに NOT OK (http_accept_language) の形式の行が追加され、失敗したチェックが示されます。テスト後は debug を無効に戻してください。upstream も、デプロイ済みのインスタンスで debug を有効にしないよう求めています。

エンジンの障害は、この形式とはまったく異なります。IP アドレスではなくエンジン名が示されます。最も一般的なのはタイムアウトです。

HTTP requests timeout (search duration : 3.1 s, timeout: 3.0 s)

この確認用のページもあります。enable_metrics がデフォルト値の true のままであれば、インスタンスはエンジンエラーを /stats/errors に記録し、/preferences で現在応答しているエンジンを一覧表示します。/stats/errors が満杯で、ログに searx.limiter の行がない場合、原因は制限機能ではありません。

デバッグを始める前にバージョンを固定する

上流のコンテナ構成は2つのファイルで成り立ちます。

mkdir -p ./searxng/core-config/
cd ./searxng/

curl -fsSL \
    -O https://raw.githubusercontent.com/searxng/searxng/master/container/docker-compose.yml \
    -O https://raw.githubusercontent.com/searxng/searxng/master/container/.env.example

cp -i .env.example .env

compose ファイルは docker.io/searxng/searxng:${SEARXNG_VERSION:-latest} を取得します。変数が未設定だと latest になり、latest では次の docker compose pull でインスタンスの内容が変わります。そのため、先週動作した設定が、その設定を読み取るコードと一致しなくなる可能性があります。SearXNG のタグには日付とコミットが含まれます。2026年8月時点で、上流の .env.example にある例のタグは 2026.3.25-541c6c3cb です。.env に実際のバージョンを設定してください。

SEARXNG_VERSION=2026.3.25-541c6c3cb

公開されているタグを確認し、実際にテストしたリリースを固定してから、固定した対象に対してデバッグしてください。同じ .env ファイルには Secret key も保存されます。そのため、そのディレクトリをどこかにコミットする前に、Docker Compose で環境ファイルと Secret を扱う方法を確認してください。

リミッターには Valkey が必要です。Valkey がなければ動作しません

制限機能はクライアントごとにリクエスト数を数えるため、そのカウントをワーカープロセス間で共有する必要があります。この保存先が Valkey です。Valkey は Redis の保守継続フォークです。古い SearXNG ガイドでは、この設定を redis: と記載しています。現在のリリースでは valkey: を読み込むため、古い投稿ではなく、現行ドキュメントからキー名をコピーしてください。さらに古いページには、SearXNG ではなく Searx について説明しているものもあります。Searx は異なるコードベースで、制限機能も異なります。そのため、設定ブロックをコピーする前に、そのページがどちらのプロジェクト向けに書かれたものかを確認してください

use_default_settings: true
server:
  secret_key: "change-this-value"
  limiter: true
  public_instance: false
valkey:
  url: valkey://searxng-valkey:6379/0

上流の compose ファイルでは、docker.io/valkey/valkey:9-alpine イメージを使用する searxng-valkey サービスがすでに起動します。そのため、このホスト名は compose ネットワーク内で解決されます。同じ値は SEARXNG_VALKEY_URL 環境変数でも設定できます。SearXNG と Valkey が同じホストを共有する場合は、Unix ソケット URL(unix:///path/to/socket.sock?db=0)も使用できます。

ストアがない場合の動作は、もう 1 つのキーによって異なります。public_instance: false の場合、リミッターは Valkey のエラーをログに記録して処理を諦めるため、レート制限なしでインスタンスのサービス提供を続けます。public_instance: true の場合、プロセスは代わりに sys.exit(1) を呼び出します。ボット対策が壊れた公開インスタンスは、1 日以内にすべての検索エンジンから CAPTCHA(completely automated public turing test to tell computers and humans apart)を収集するためです。public_instance: true を設定した直後にコンテナがループして再起動する場合は、この状態です。各終了前の最後の行に Valkey が記録されます。

リミッターが実際に数えるもの

ChartSearXNG limiter: requests allowed per client IP, defaults in ip_limit.py
The data behind this chart
[
  {
    "label": "Burst, normal client",
    "max_requests": 15,
    "window": "20 seconds"
  },
  {
    "label": "Burst, flagged client",
    "max_requests": 2,
    "window": "20 seconds"
  },
  {
    "label": "Sustained, normal client",
    "max_requests": 150,
    "window": "10 minutes"
  },
  {
    "label": "Sustained, flagged client",
    "max_requests": 10,
    "window": "10 minutes"
  },
  {
    "label": "Any non-HTML format",
    "max_requests": 4,
    "window": "1 hour"
  },
  {
    "label": "Flagged requests before block",
    "max_requests": 3,
    "window": "30 days"
  }
]

通常のクライアントは、20 秒のバーストウィンドウ内で 15 件、10 分間のウィンドウ内で 150 件のリクエストを送信できます。リクエストが不審と判定されると、同じクライアントはバーストウィンドウあたり 2 件までに制限されます。最後の行が最も厳しい制限です。30 日間のウィンドウ内で不審なリクエストが 3 件に達すると、そのアドレスは検索結果ではなく開始ページへリダイレクトされ、ログには BLOCK: too many request from ... in SUSPICIOUS_IP_WINDOW (redirect to /) と記録されます。

これらの数値は searx/botdetection/ip_limit.py 内の定数です。設定値ではなく、limiter.toml からも変更できないため、変更するにはソースを編集する必要があります。/etc/searxng/limiter.toml で制御できるのは、クライアントのグループ化に使用するアドレスプレフィックス、信頼するプロキシの一覧、オプションのリンクトークン検査、許可リストとブロックリストです。

リクエストはヘッダー検査によって不審と判定されます。各検査には名前があり、デバッグログで確認できます。

  • http_accept: Accept ヘッダーに text/html が含まれていません。
  • http_accept_encoding: Accept-Encoding ヘッダーに gzipdeflate も指定されていません。
  • http_accept_language: Accept-Language ヘッダーがありません。
  • http_connection: Connection ヘッダーが close に設定されています。
  • http_user_agent: User-Agent がないか、既知の bot パターンと一致します。
  • http_sec_fetch: Sec-Fetch-Mode または Sec-Fetch-Dest ヘッダーが、ブラウザーが送信する値になっていません。

ブラウザーはこれらをすべて送信します。一方、単純な curl 呼び出しでは、そのほとんどが送信されません。そのため、手作業で作成したテストリクエストは初回から不審と判定されますが、同じ検索をブラウザーのタブで実行すると成功します。したがって、「ブラウザーでは動作するのに、スクリプトでは 429 になる」という結果は、謎ではなく通常の動作です。

リバースプロキシの背後でリミッターが全員を一度にブロックする

これは、正常に動作しているインスタンスを壊す最も一般的な原因です。SearXNG は X-Forwarded-For にある最初の信頼されていない IP からクライアントアドレスを取得し、見つからない場合は X-Real-IP にフォールバックし、それでも見つからなければ接続元のアドレスを使用します。これらのヘッダーを信頼するかどうかは、limiter.tomltrusted_proxies で決まります。

プロキシのアドレスがその一覧に含まれていない場合、ヘッダーは無視され、すべての訪問者がプロキシのアドレスからアクセスしたものとして扱われます。その結果、全員が 1 つのカウンターを共有し、10 分間のリクエスト総数が 150 を超えるとサイト全体がまとめてブロックされます。1 人のユーザーが結果ページを数回再読み込みするだけで、全員が影響を受けます。

信頼しすぎる設定は、さらに危険です。パブリックな範囲を登録すると、訪問者は誰でも独自の X-Forwarded-For ヘッダーを送信し、リクエストごとに新しい識別情報を選べます。これにより、その方法を知っているユーザーはリミッターを無効化できます。自分のプロキシが接続元として使用するアドレスだけを登録してください。Docker では通常、172.16.0.0/12 内の bridge network であり、その行はコメントアウトされた状態で出荷されています。

[botdetection]
ipv4_prefix = 32
ipv6_prefix = 48

trusted_proxies = [
  '127.0.0.0/8',
  '::1',
  '172.16.0.0/12',
]

プロキシ側でもヘッダーを送信する必要があります。Nginx はこれらを自動では追加しません。

location / {
    proxy_pass http://127.0.0.1:8080;

    proxy_set_header Host              $host;
    proxy_set_header Connection        $http_connection;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
}

Caddy と Traefik は転送用ヘッダーを自動的に設定するため、これらを使用する場合は trusted_proxies 側の設定だけが必要です。トレードオフについては、セルフホストサービス用のリバースプロキシを選ぶで説明しています。どちらの構成でも、確認するには debug を有効にし、モバイルデータ通信中のスマートフォンから 1 回検索します。ログ行に表示されたネットワークがプロキシのアドレスではなく、スマートフォンのアドレスになっていることを確認してください。

エージェントは 1 時間あたり 4 件の API リクエストを実行します

JSON 出力はデフォルトで無効になっているため、エージェントで有効にする必要があります。

search:
  formats:
    - html
    - json

ここで、チャートの行をもう一度確認します。HTML 以外の形式を要求するリクエストは、それぞれ独自のウィンドウでカウントされます。アドレスごとに、4 件のリクエストを 1 hour ごとに処理できます。調査エージェントは 1 件のタスクでこの上限を使い切り、それ以降の呼び出しはすべて 429 を返します。上限を引き上げることはできません。この数値はソースに記述されているためです。

確実な修正方法は、このクライアントが未知のアクセス元ではないことを limiter に伝えることです。limiter.toml の pass list にアドレスを追加します。

[botdetection.ip_lists]
block_ip = []

pass_ip = [
  '10.8.0.0/24',
]

pass_searxng_org = true

pass_ip は他のすべての方式より優先されるため、許可リストに登録したクライアントではヘッダーチェックも省略され、単純な curl 呼び出しが機能します。範囲は可能な限り小さくしてください。ルーティング可能なネットワークよりも、VPN サブネットまたはコンテナネットワークを優先します。もう 1 つの確実な方法は、エージェントをパブリック経路から完全に切り離すことです。内部ネットワーク上のコンテナアドレスをエージェントに指定すれば、プロキシとその limiter にトラフィックが到達しません。この設定方法については、AI エージェントに SearXNG の検索機能を追加するで説明しています。

避けるべき方法は、他人が運用するパブリックインスタンスをエージェントに指定することです。これが、上流の検索エンジンによってボランティアの IP アドレスがブロックされる最も早い原因になります。そもそも JSON 形式がデフォルトで無効になっている理由もこれです。

エンジンにブロックされた場合

ChartHow long SearXNG suspends an engine, search.suspended_times defaults
The data behind this chart
[
  {
    "label": "SearxEngineTooManyRequests",
    "suspended_seconds": 3600,
    "roughly": "1 hour"
  },
  {
    "label": "SearxEngineAccessDenied",
    "suspended_seconds": 86400,
    "roughly": "1 day"
  },
  {
    "label": "SearxEngineCaptcha",
    "suspended_seconds": 86400,
    "roughly": "1 day"
  },
  {
    "label": "recaptcha_SearxEngineCaptcha",
    "suspended_seconds": 604800,
    "roughly": "7 days"
  },
  {
    "label": "cf_SearxEngineCaptcha",
    "suspended_seconds": 1296000,
    "roughly": "15 days"
  }
]

エンジンが独自の 429 または CAPTCHA ページを返すと、SearXNG は名前付き例外を発生させ、しばらくそのエンジンへのリクエストを停止します。Too Many Requests の応答では、3600 秒間停止します。通常の CAPTCHA またはアクセス拒否の応答では、1 day の間停止します。Cloudflare 経由で提供された CAPTCHA では、15 days の間停止します。これは一覧内で最も長いデフォルト値です。この応答はブロックがエッジにあることを示し、再試行しても改善しないためです。該当した CAPTCHA の3つの行のどれかによって、次に試す価値のある対処が変わります。インスタンスが記録した例外が分かれば、CAPTCHA エラーには固有の対処方法があります

通常の失敗には別の設定が使われます。タイムアウトまたは解析エラーが発生すると、エンジンは search.ban_time_on_fail から算出された短い時間だけ停止します。search.ban_time_on_fail のデフォルトは 5 秒で、search.max_ban_time_on_fail により 120 秒が上限になります。そのため、遅いエンジンは数分以内に自動復旧しますが、ブロックされたエンジンは数時間利用できません。この違いにより、「ランダムに発生する」と報告される現象が起きます。検索結果は正常でも、その後、1 つのエンジンの結果だけが午後いっぱい表示されなくなります。

誰かを責める前に、タイムアウトを調整してください。デフォルトの request_timeout は 2.0 秒です。エンジンの最寄りのエッジサーバーから遠い小規模 VPS では、短すぎる場合があります。

outgoing:
  request_timeout: 3.0
  max_request_timeout: 10.0
engines:
  - name: bing
    timeout: 5.0

request_timeout はすべてのエンジンに対するデフォルト値です。max_request_timeout は上限で、個別のエンジンには独自の timeout を設定できます。これらの値を上げると、ページの待ち時間と引き換えに失敗を減らせます。いきなり 10 にせず、0.5 秒ずつ増やしながら /stats/errors を監視してください。

アドレスを実際にブロックしているエンジンは削除してください。すべての検索は最も遅いエンジンを待つため、恒久的に停止されたエンジンを残すと遅延が増え、結果も返りません。

use_default_settings:
  engines:
    remove:
      - google

docker compose restart searxng-core で変更を適用し、いくつか検索を実行してから /stats/errors を再読み込みします。実際に 5 分間使用した後もページが空であれば、変更は適用されています。

データセンターの IP はボットとして扱われます

VPS のアドレスはホスティング事業者のアドレス範囲に属しているため、大手検索エンジンでは自動化されたアクセスとして評価されます。そのようなアドレスからのすべてのリクエストに対して、ヘッダーが適切でリクエスト間隔が長くても CAPTCHA を表示する検索エンジンがあります。settings.yml の設定で、この判定を変更することはできません。検索クエリを入力した人ではなくサーバーが検索エンジンから見えることは、自己ホスティングによって受け入れたプライバシー上のトレードオフそのものです。また、SearXNG が実際にどの程度隠すのかを読んでから、さらに多くの情報を隠せると判断してください。

変更できるのは、問い合わせる検索エンジンと、インスタンスを公開一覧に掲載するかどうかです。1 つの家庭だけで使用する非公開インスタンスであれば、問題が発生することはほとんどありません。ホスティング事業者の IP で公開インスタンスを運用すると、制限の厳しい検索エンジンでは停止を繰り返し受けます。これは設定の不具合ではなく、通常の動作です。SearXNG では、outgoing.proxies または outgoing.using_tor_proxy を使用して、プロキシ経由で検索エンジンへのリクエストを送信できます。これにより、通信元のアドレスが変わります。ただし、出口ノードや安価なプロキシプールはホスティング事業者のアドレス範囲より低く評価されるため、この変更によって検索結果が悪化する可能性があります。

インスタンスを監視し、最初に異常を把握する

すべてのエンジンが停止中でも、SearXNG はポートへの応答を返します。そのため、ステータスコードだけを監視する稼働確認では、インスタンスが何も返していなくても正常な状態が続きます。応答内容を確認してください。実際の検索を実行し、応答本文に含まれる想定した単語を照合します。Uptime Kuma のキーワード監視なら、追加のツールなしでこれを実行できます。バージョンを更新するたびに /stats/errors も監視してください。エンジンの HTML が変更されると、レート制限が関係していなくてもパーサーが壊れるためです。

FAQ

SearXNG をリバースプロキシの背後に置いた後、すべての訪問者に 429 が返るのはなぜですか?

リミッターがプロキシをクライアントとして数えているためです。SearXNG は、接続元アドレスが /etc/searxng/limiter.tomltrusted_proxies に登録されている場合にだけ X-Forwarded-For を読み取ります。登録されていない場合、すべての訪問者が 1 つのカウンターを共有し、10 分あたり 150 リクエストの上限を同時に超えます。プロキシの接続元アドレスを追加してください。Docker では通常、ブリッジ範囲の 172.16.0.0/12 です。また、プロキシが X-Real-IPX-Forwarded-For を送信することを確認してください。管理していない範囲は決して登録しないでください。信頼したネットワーク上では、任意の訪問者がそのヘッダーを設定し、リクエストごとに新しい識別情報を選べるためです。

SearXNG のリミッターは、1 時間あたり何件の API リクエストを許可しますか?

IP アドレスごとに 1 時間あたり 4 件です。HTML 以外の形式を要求するリクエストは、別の 1 時間ウィンドウで数えられます。この上限は limiter.toml ではなく searx/botdetection/ip_limit.py で設定されるため、設定ファイルから引き上げることはできません。エージェントやスクリプトは、1 つのタスクでこの上限に達します。クライアントのアドレスを limiter.tomlpass_ip に追加するか、リミッターがリクエストを認識しない内部ネットワーク経由でインスタンスにアクセスしてください。

429 エラーがないのに検索結果が空になるのはなぜですか?

拒否しているのはユーザーではなく、サーバーです。自分のインスタンスで /stats/errors を開いてください。ここには、失敗した各エンジンとその理由が表示されます。CAPTCHA またはアクセス拒否の項目がある場合、そのエンジンがサーバーの IP アドレスをブロックしています。SearXNG はその後、エンジンを一時停止します。too-many-requests 応答の後は 1 時間、CAPTCHA の後は 1 日停止します。上流側のブロックを解除するローカル設定はありません。そのため、アドレスをブロックするエンジンを削除し、応答するエンジンを残してください。

プライベートなインスタンスでもリミッターを有効にすべきですか?

自分以外からインスタンスにアクセスされない場合は、limiter: false のままにしてください。リミッターを有効にすると Valkey への依存関係が追加され、自分のスクリプトもブロックされます。また、存在しないトラフィックから保護することになります。インスタンスに公開アドレスを割り当てた時点で、public_instance: true と併せて有効にしてください。この組み合わせには意図があります。public_instance: true を設定していて Valkey が利用できない場合、プロセスは保護なしで動作を続けず、status 1 で終了します。