SSD Nodes Learn メモリ 8GB — 年額 $66
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-01

SearXNGをセルフホストする方法 Docker Compose入門

SearXNGを自分のVPSで運用する手順です。Docker Compose、settings.yml、limiter、nginxのTLS設定と、スクリプトから呼べるJSON検索APIを解説します。

構築するもの

SearXNGをセルフホストすると、自分のサーバー上で動作するプライベートな検索エンジンを利用できます。SearXNGはメタ検索エンジンです。入力した検索クエリをGoogle、Bing、DuckDuckGo、Wikipediaなどの検索エンジンに送り、返された結果を1つの結果ページにまとめます。クエリを保存するマシンは自分のマシンだけなので、プロファイルは作成されず、トラッキングCookieも設定されません。

構成は小規模です。コンテナ2つ、設定ファイル1つ、リバースプロキシ1つで構成します。実際に決める必要があるのは、インスタンスをプライベートにするかどうかです。プライベートなら、自分と自分のスクリプトだけがアクセスできます。パブリックなら、インターネット上の誰でもクエリを送信できます。この選択によってセキュリティ設定が変わるため、何か入力する前に決めてください。デフォルトではプライベートにします。

もう1つ、実行する理由があります。SearXNGインスタンスはJSONを扱うため、作成したスクリプトやAIエージェントから、自分で管理する検索APIを利用できます。APIキー、クエリごとの課金、クォータ通知メールは必要ありません。

Docker ComposeでSearXNGをインストールする

このプロジェクトはコンテナイメージとComposeファイルを公開しています。Docker EngineとComposeプラグインがすでにインストールされている、初期状態のUbuntu 24.04サーバーに両方を取得します。Dockerを初めて使用する場合は、まずVPSでのDocker Composeの基本を確認してから戻ってきてください。

sudo install -d -o "$USER" -g "$USER" -m 750 /opt/searxng
cd /opt/searxng
mkdir -p core-config
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ファイルでは2つのサービスを定義しています。coreはSearXNG本体で、valkeyはレート制限と短時間だけ保持する状態情報に使用するインメモリデータストアです。コンテナ内の/etc/searxng/にホスト上の./core-config/をマウントするため、設定するすべての内容はホスト上のその1つのディレクトリに保存されます。

次に.envを編集します。配布されたサンプルではすべての行がコメントアウトされています。そのため、コンテナはすべてのアドレスのポート8080で起動します。次の3つをコメント解除して設定してください。

SEARXNG_VERSION=latest
SEARXNG_HOST=127.0.0.1
SEARXNG_PORT=8080

重要なのはSEARXNG_HOST=127.0.0.1です。これにより公開ポートが[::]:8080:8080ではなく127.0.0.1:8080:8080になります。その結果、コンテナはループバックアドレスでのみ応答し、インターネットから直接アクセスできなくなります。これを省略すると、公開されたDockerポートはファイアウォールルールより前に挿入されるため、コンテナの起動直後から外部に公開されます。この問題の詳細は、公開されたDockerポートはufwを回避するで確認してください。

学習中はSEARXNG_VERSION=latestで問題ありません。重要なサーバーでは、タグを固定してください。2026年7月現在、リリースタグは日付ベースで、2026.3.25-541c6c3cbのような形式です。これにより、レジストリの変更によって自動的に更新されず、必要なタイミングでアップグレードできます。

settings.yml: 重要な項目

最初に起動する前に core-config/settings.yml を作成します。use_default_settings: true により、SearXNG は提供されているデフォルト設定を読み込んだ後、ファイルに記述したキーだけを適用します。そのため、設定ファイルを短く保てます。また、新しいオプションが追加されるアップグレード後も設定を維持できます。

まずシークレットを生成します。この値をそのままファイルに記述するためです。

openssl rand -hex 32
use_default_settings: true

general:
  instance_name: "search.example.com"

server:
  base_url: "https://search.example.com/"
  secret_key: "paste-the-openssl-output-here"
  limiter: false
  public_instance: false
  image_proxy: true

valkey:
  url: valkey://valkey:6379/0

search:
  safe_search: 0
  autocomplete: "duckduckgo"
  formats:
    - html
    - json

secret_key は、セッションとトークンのデータに署名します。提供されているデフォルト値は文字列 ultrasecretkey です。このままにすると、そのデフォルト値を知っている人がトークンを偽造できます。値は一度だけ置き換え、その後は変更しないでください。後から変更すると、保存済みのすべての設定が失われます。

base_url には、末尾のスラッシュを含む公開 HTTPS アドレスを指定します。SearXNG はこのアドレスを生成するリンクに書き込みます。localhost のままにすると、リモートブラウザーの「次のページ」リンクが閲覧者自身のマシンを指し、失敗します。

formats は、Web エンドポイントが生成する出力形式を決定します。json はデフォルトのリストに含まれていないため、追加するまで JSON リクエストは 403 を返します。image_proxy: true は検索結果のサムネイルをサーバー経由で取得します。そのため、画像をホストするサイトには訪問者のアドレスが伝わりません。

valkey.url ではホスト名 valkey を使用します。これは Compose ファイル内のサービス名であり、Compose は両方のコンテナを、サービス名を解決できる同じネットワークに接続するためです。localhost を指定するとリミッターが失敗します。core コンテナ内では localhost がそのコンテナ自身を指すためです。

シークレットはプレーンテキストのファイルに保存されます。そのため、ファイル自体ではなく、そのファイルを含むディレクトリを保護してください。chmod 750 /opt/searxng により、ホスト上の他のユーザーを締め出せます。core-config/settings.yml をモード 600 に変更して、権限をさらに厳しくしないでください。コンテナは権限のない専用ユーザーとして実行されるため、そのユーザーがファイルを読み取れないと SearXNG は起動できません。

スタックを起動して確認します。

cd /opt/searxng
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080/

docker compose ps には、両方のコンテナが状態 running で表示されるはずです。curlHTTP/1.1 200 OK を返すはずです。何も返さない場合は docker compose logs core を確認してください。settings.yml の YAML の誤りは、行番号を示す解析エラーとしてそこに表示されます。

nginxの背後に配置してTLSを有効にする

コンテナはloopbackでのみ待ち受けるため、外部から到達できるようにするにはnginxが必要です。nginxはtransport layer security (TLS)も追加します。/etc/nginx/sites-available/searxngを記述します。

server {
    listen 80;
    server_name search.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
sudo ln -s /etc/nginx/sites-available/searxng /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d search.example.com

nginx -tは、reloadする前にsyntax is oktest is successfulを出力します。Certbotは同じファイルを書き換え、証明書を使って443で待ち受けるようにし、port 80からのredirectを追加します。証明書認証局はHTTP経由でファイルを取得して所有権を証明するため、search.example.comのDNSレコードは事前にこのserverを指している必要があります。更新を含む詳しい手順は、Ubuntu 24.04向けCertbotとnginxのガイドにあります。

2つの転送ヘッダーは飾りではありません。X-Forwarded-ForX-Real-IPがないと、SearXNGに到達するすべてのリクエストがproxy addressを持つため、rate limiterは1つのclientがすべてのtrafficを発生させていると認識し、訪問者を区別できません。

スクリプトとエージェントが JSON 検索 API を必要とする理由

formatsjson があるため、ページを表示する同じエンドポイントが構造化データも返します。

curl -s 'http://127.0.0.1:8080/search?q=wireguard+mtu&format=json' \
  | jq -r '.results[0:5][] | .url'

urltitlecontent、およびそれを提供したエンジンを各エントリに含む results 配列を持つオブジェクトが返されます。さらに、answersinfoboxessuggestions も含まれます。これだけで、要約ツール、リンクチェッカー、または調査ループにデータを渡せます。

これは、エージェント型の処理全般で重要です。言語モデルには学習データの締切があるため、現在について回答するにはリアルタイム検索が必要です。一方、商用検索 API はクエリごとに課金され、厳しいレート制限も適用します。ローカルインスタンスなら、すでに料金を支払っているサーバー上で1つのコンテナを実行するだけで済み、クエリが外部に出ることもありません。モデルにツールを接続する場合も、同じ理由から VPS で MCP サーバーを実行する構成が有効です。検索ツールは通常、最初に追加されるツールです。

API の使用には2つのルールがあります。インスタンスは非公開にしてください。API 側を loopback アドレスまたはプライベートネットワークに bind し、自分のホストだけがアクセスできるようにします。次に、クエリを控えめな頻度で送信してください。SearXNG はリクエストを実際の検索エンジンに転送します。そのため、1秒あたり100件のクエリを実行するスクリプトは、Google にサーバーをブロックするよう求めているのと同じです。

リミッターとパブリックインスタンスで変わる点

リミッターはSearXNGのボット対策機能です。リクエストヘッダー、アドレス、リクエスト頻度を監視し、自動化された通信に見えるトラフィックを破棄します。この状態を保持するためにValkeyが必要です。そのため、Composeファイルに含まれています。

プライベートインスタンスではlimiter: falseを維持します。独自のスクリプトは定義上、自動化されたトラフィックです。そのため、リミッターは、このインスタンスを構築した目的であるJSON呼び出しをブロックします。アクセス制御は、代わりにリバースプロキシの役割です。nginxのlocationallowdenyのペアを設定する方法、HTTP Basic認証を使う方法、または他のサーバーからの通信だけを許可するファイアウォールを使う方法があります。

他のユーザー向けにインスタンスを公開する場合は、両方のスイッチを有効にします。

server:
  limiter: true
  public_instance: true

より細かい制御はcore-config/limiter.tomlで設定できます。コンテナはこれを/etc/searxng/limiter.tomlから読み取ります。変更するキーだけを記述します。プロキシの背後では、プロキシを宣言する必要があります。宣言しないと、リミッターはnginxのアドレスを不正なクライアントのアドレスとして扱います。

[botdetection]
trusted_proxies = [
  '127.0.0.0/8',
  '::1',
]

[botdetection.ip_limit]
link_token = true

link_token = trueを有効にすると、SearXNGは実際のブラウザーセッションだけが取得できるトークンを発行します。これにより、単純なスクレーパーの大半を阻止できます。パブリックインスタンスは数日以内にスクレーパーを引き寄せると考えてください。エンジンエラーも発生します。転送するトラフィックが増えるほど、上流のエンジンがサーバーのアドレスにCAPTCHAを返し始めるまでの時間が短くなるためです。パブリックSearXNGインスタンスは継続的な作業が必要です。プライベートインスタンスにはその必要がありません。そのため、2026年にセルフホスティングする価値があるものの短い一覧の多くに含まれています。

検索結果が返らない理由

インスタンスで /stats を開きます。ここには、すべてのエンジンのエラー率と応答時間が一覧表示されます。結果が少ないと感じたときは、まずここを確認します。

「Access denied」または「CAPTCHA」エラーが表示されるエンジンは、サーバーのアドレスをブロックしています。検索エンジンは、データセンターのアドレス範囲に属するアドレスをスクレイパーのものと判断するため、この問題はよく発生します。SearXNG は失敗したエンジンを再試行せず、一定期間停止します。そのため、ブロックされたエンジンは結果からひそかに除外されます。settings.yml で無効にするか、そのエンジンの結果が失われることを受け入れます。残りのエンジンは引き続き応答します。

すべてのエンジンが同時に失敗する場合、コンテナでは外部の名前解決が機能していないか、インターネットへのルートがありません。コンテナ内からテストします。

docker compose exec core wget -qO- https://duckduckgo.com > /dev/null && echo ok

FAQ

SearXNGで検索を匿名化できますか?

検索先のエンジンからは、利用者の身元が隠されます。エンジンにはブラウザーではなく、サーバーからリクエストが送信されたように見えるためです。ただし、検索内容がサーバーから隠されるわけではありません。また、サーバーが検索先のエンジンから隠されるわけでもありません。単一ユーザーのインスタンスでは、そのアドレスからのすべてのトラフィックが利用者のものになるため、アドレス自体が識別子になります。ブラウザーとインスタンス間のトラフィックは、TLS証明書によって保護されます。

JSONリクエストが403 Forbiddenを返すのはなぜですか?

原因は2つあり、どちらも設定に関係します。settings.ymlsearch: 配下にある formats リストに json がないことが原因の1つです。これはデフォルトの状態です。もう1つは、limiterが有効で、スクリプトをbotとして分類していることです。まず形式を追加し、docker compose restart core で再起動してから、もう一度試してください。それでも失敗する場合は limiter: false を設定し、reverse proxy側でアクセスを制御してください。

limiterを無効にしたままにする場合、Valkeyコンテナは必要ですか?

起動したままにしてください。SearXNGはValkeyなしでも動作しますが、Valkeyなしでは後からlimiterを有効にできません。また、その他の短期間だけ使用する状態も保持します。コンテナは小さく、キャッシュデータだけを保存します。そのため、削除しても節約できる容量はごくわずかで、将来の選択肢を失うことになります。

SearXNGを更新するにはどうすればよいですか?

/opt/searxngdocker compose pull を実行し、その後 docker compose up -d を実行してください。Composeはイメージが変更されたコンテナを再作成し、core-config/ ディレクトリはそのまま残すため、settings.yml も保持されます。use_default_settings: true は配布時のデフォルト設定に独自のキーをマージするため、upstreamで追加されたオプションも、ファイルを壊さず適切な値で反映されます。

複数のユーザーで1つのインスタンスを共有できますか?

はい。その場合はlimiterを有効にして public_instance: true を設定してください。設定は各訪問者自身のブラウザーに保存されるため、管理するアカウントはありません。公開後の1週間は /stats を監視してください。upstreamのエンジンは、検索結果の欠落に気付くよりもずっと早く、サーバーからのリクエストを拒否し始めることがあります。

#searxng#search#privacy#self-hosting#docker