RustXNG vs SearXNG:乗り換えるべきか、VPSで安全に動かす方法
RustXNGはSearXNG互換をうたうRust製のメタ検索エンジンです。v0.27.1を基準に、互換性の差、SHA-256検証つきの導入、ループバック運用、MCP連携、検索先の利用規約まで、乗り換える前に確かめる点を整理します。
RustXNG と SearXNG、乗り換えるべきか
RustXNG と SearXNG のどちらを使うかは、何に使うかで決まります。自分用の検索やコーディングエージェントの検索窓口として、小さな VPS のループバックで動かすなら、RustXNG は試す価値があります。テーマやプラグインを作り込んだ公開インスタンスや、上流の botdetection に頼った運用なら、今は SearXNG のままにしておくのが安全です。
この記事は v0.27.1 タグ(2026年11月3日公開)だけを基準にしています。2026年11月3日の確認時点では、GitHub のタグ一覧には v0.1.0 から v0.27.1 まで 40 個のタグがありました。CHANGELOG.md では v0.1.0 の公開日が 2026年10月18日です。つまり約2週間で 40 回タグが切られています。既定のポート番号も途中で変わりました。ほかのバージョンを入れる場合は、そのタグの README と settings.toml を読み直してください。
SearXNG 自体の構築手順は SearXNG を VPS でセルフホストする手順 にまとめています。この記事はそれを読んだ人、または SearXNG をすでに動かしている人向けです。
RustXNG とは何か
RustXNG は SearXNG をもとに Rust で書き直したメタ検索エンジンです。メタ検索エンジンとは、自分では索引を持たず、複数の検索サービスに問い合わせて結果をまとめるソフトウェアのことです。ライセンスは AGPL-3.0-or-later(GNU Affero General Public License)で、SearXNG 由来であることは NOTICE ファイルに書かれています。
v0.27.1 の修正点は1つだけです。リリースノートには「security: harden proxied SVG responses」(#82)とあります。
RustXNG と SearXNG の互換性:何が同じで、何が違うか
互換性の範囲は、タグ内の docs/COMPATIBILITY.md(日本語、題は「SearXNG 互換性の範囲」)にまとまっています。リポジトリ直下に COMPATIBILITY.md はないので、docs 以下のファイル を開いてください。要点は次のとおりです。
- 設定ファイル:
--config settings.ymlまたは環境変数SEARXNG_SETTINGS_PATHに、上流の YAML をそのまま指定できます。TOML でも動きます。 - JSON API:
/search?format=jsonは、既定では上流のget_json_responseと同じ 7 フィールドだけを返します。より詳しい出力が欲しいときはformat=json&full=1を付けます。 - テーマ:simple 相当のテーマが1つだけです。上流のテンプレート、テーマ資産、マークアップとは互換性がありません。
- プラグイン:RustXNG は 11 個です。COMPATIBILITY.md は上流を 12 個としていますが、上流の
searx/settings.ymlに並ぶプラグインは 11 個です。favicon の取得も上流の resolver 方式とは違います。
ここから分かることがあります。JSON API だけを使う連携、たとえば Open WebUI から SearXNG の JSON API を呼ぶ構成 は、既定の出力が上流と同じ形なので、そのまま試せる可能性が高いです。一方、HTML テンプレートを書き換えている人は、その作業を RustXNG に持ち込めません。使っているプラグインが RustXNG にもあるかは、自分で画面を見て確かめてください。
もう1つ、大きな違いがあります。README によると、Google 関連の連携は削除されました。CHANGELOG の未リリース欄には、Google の検索エンジン、Google を裏で使うフロントエンド、YouTube、Google 翻訳の連携が並んでいます。今の SearXNG で Google の結果に頼っているなら、RustXNG ではその結果は出ません。
起動の速さとメモリ量は、プロジェクト自身の計測です
RustXNG が話題になった理由は軽さです。ただし、ここで見せる数字はすべて docs/BENCHMARK.md にあるプロジェクト自身の計測です。この記事で測り直したものではありません。
このグラフのデータ
[
{
"tool": "SearXNG (granian/WSGI)",
"startup_s": 0.72
},
{
"tool": "RustXNG (cargo run --release)",
"startup_s": 0.03
}
]このグラフのデータ
[
{
"tool": "SearXNG (granian/WSGI)",
"rss_mib": 118
},
{
"tool": "RustXNG (cargo run --release)",
"rss_mib": 13
}
]ページの記述では、SearXNG は起動から 0.72 秒、RustXNG は 0.03 秒で /healthz が 200 を返しました。常駐メモリは SearXNG が 118 MiB、RustXNG が 13 MiB です。
この数字を読むときの注意点は2つあります。1つ目は条件が揃っていないことです。RustXNG は cargo run --release、SearXNG は granian による WSGI で動かしており、本番と同じ起動方法ではありません。ハードウェア、OS、試行回数、メモリの測り方も書かれていません。2つ目は記録が古いことです。ページ自身が「過去の条件での測定記録」と書いており、今の設定での値は保証していません。
古さはファイルサイズを見るとはっきりします。
このグラフのデータ
[
{
"tool": "SearXNG venv\uff08\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u8a18\u8f09\uff09",
"size_mb": 151
},
{
"tool": "RustXNG \u30d0\u30a4\u30ca\u30ea\uff08\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u8a18\u8f09\uff09",
"size_mb": 17
},
{
"tool": "RustXNG DB \u30a8\u30f3\u30b8\u30f3\u8fbc\u307f\uff08\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u8a18\u8f09\uff09",
"size_mb": 27
},
{
"tool": "v0.27.1 \u914d\u5e03 x86_64 gnu",
"size_mb": 41.0
},
{
"tool": "v0.27.1 \u914d\u5e03 x86_64 musl",
"size_mb": 39.5
}
]ベンチマークでは RustXNG のバイナリは 17 MB でした。一方、v0.27.1 の x86_64 gnu 版の配布ファイルは 41.0 MB あります。バイナリが大きくなっているので、メモリ量も当時と同じとは限りません。自分の VPS で使う前に、systemctl status の Memory 行などで実際の値を見てください。
RustXNG の配布バイナリを入れて SHA-256 を確かめる
v0.27.1 のリリースには Linux 用のバイナリが3種類あります。
x86_64-unknown-linux-gnux86_64-unknown-linux-muslaarch64-unknown-linux-gnu
aarch64 の musl 版はありません。ほかに macOS(aarch64 と x86_64)、Windows の x86_64 版、LICENSE、NOTICE、release-manifest.json、そして各バイナリの .sha256 ファイルが付いています。SHA256SUMS と SBOM は付いていません。ただし、リリースのワークフローが GitHub の署名付きの証明(attestation、SLSA provenance)を作っており、これはリリースのファイルとは別に GitHub に保存されています。
自分の VPS のアーキテクチャは uname -m で確かめます。x86_64 なら README と同じく musl 版、aarch64 なら gnu 版を選びます。エージェント向け導入ガイドによると、Linux の gnu 版には x86_64 で glibc 2.35 以降、aarch64 で glibc 2.39 以降が必要です。
README の手順は GitHub CLI(gh release download)を使います。ここでは同じ流れを curl で書きます。ダウンロード先は空のディレクトリにしてください。
uname -m
tag=v0.27.1
asset="rustxng-${tag}-x86_64-unknown-linux-musl"
base="https://github.com/sahenjp/RustXNG/releases/download/${tag}"
mkdir -p ~/rustxng-dl && cd ~/rustxng-dl
curl -fLO "${base}/${asset}"
curl -fLO "${base}/${asset}.sha256"
curl -fLO "${base}/LICENSE"
curl -fLO "${base}/NOTICE"
sha256sum --check "${asset}.sha256"sha256sum --check が rustxng-v0.27.1-x86_64-unknown-linux-musl: OK と表示すれば成功です。FAILED と出たらファイルが壊れているので、消してからダウンロードし直します。musl 版の期待値は GitHub のリリース資産一覧にも d701cb636f7ba57b428228203152827e5a879fef5562b54e88cbcc80fb1b5919 として載っています。
この検証でできることには限界があります。.sha256 ファイルもマニフェストも、同じリリースから配られています。そのため、ダウンロード中の破損は見つけられますが、リリースそのものが差し替えられた場合は見抜けません。そこで、GitHub に保存された証明と照合します。GitHub CLI が入っていれば、同じリリースのチェックサムではなく GitHub の証明ストアを相手に、ファイルが .github/workflows/release.yml から作られたものかを確かめられます。
gh attestation verify --repo sahenjp/RustXNG rustxng-v0.27.1-x86_64-unknown-linux-musl検証が通ったら、README と同じ場所に置きます。
install -Dm755 "$asset" "$HOME/.local/bin/rustxng"
install -Dm644 LICENSE NOTICE -t "$HOME/.local/share/rustxng/"
"$HOME/.local/bin/rustxng" --version--version がバージョン番号を表示すれば、バイナリは動いています。ここで cannot execute binary file: Exec format error が出る原因には、アーキテクチャの不一致のほか、認識できない実行形式やその他の形式エラーがあります。このメッセージだけでは原因を特定できません。uname -m の結果と、ファイル名に含まれる x86_64 か aarch64 を見比べてください。
cargo install と Docker イメージで入れる場合
ソースからビルドするなら、README がタグ固定の方法を書いています。
cargo install --git https://github.com/sahenjp/RustXNG.git --tag v0.27.1 --locked--tag v0.27.1 でコードを、--locked で依存関係を Cargo.lock の状態に固定します。README によると、最低限必要なバージョンは Rust 1.88 で、CI で確かめられています。ソースからのビルドについては、1.88 以降、できれば最新の stable を使うよう勧めています。小さな VPS ではビルドに時間とメモリを使うので、検証済みのバイナリを使うほうが手軽です。
Docker の場合、README の例は :latest タグを使っています。:latest は新しいリリースが出るたびに中身が変わるので、固定にはなりません。2026年11月3日時点の GHCR のパッケージページには 0.27.1、0.27、0.27.0 のタグも並んでおり、latest と 0.27.1 は同じダイジェストでした。固定したいなら 0.27.1 を指定します。
docker run --rm -p 127.0.0.1:29483:29483 -e SEARXNG_PORT=29483 ghcr.io/sahenjp/rustxng:0.27.1 --bind 0.0.0.0 --port 29483--bind 0.0.0.0 はコンテナの内側の話です。Dockerfile は 29483 を EXPOSE し、コンテナ内ではすべてのインターフェースで待ち受けます。外のネットワークから見えないようにしているのは、ホスト側の -p 127.0.0.1:29483:29483 です。ここを -p 29483:29483 にすると、ホストのすべてのアドレスで公開されます。
README は、公開イメージは今のところ Linux amd64 向けだと書いています。パッケージページには arm64 のダイジェストも見えますが、記述が食い違っています。arm64 の VPS ではバイナリを使うほうが確実です。
RustXNG の既定のバインドアドレスとポートを確かめる
ポート番号は記憶で書かないでください。v0.27.1 の settings.toml は bind_address = "127.0.0.1" と port = 29483 です。README にも「This checkout defaults to 127.0.0.1:29483.」とあります。ただし README は、公開済みの v0.26.0 のバイナリは 8888 を使うとも書いています。8888 は SearXNG でもよく使われる番号なので、古いバイナリと SearXNG を同じ VPS で動かすとぶつかります。
src/main.rs のヘルプは、--bind と --port の既定値を設定ファイルの server.bind_address と server.port から取ると書いています。つまり、読み込ませた設定ファイルの値がそのまま待ち受け先になります。上流の settings.yml を流用すると、その中の bind_address が使われます。Docker 用に 0.0.0.0 にしていた設定を持ち込むと、VPS の全アドレスで待ち受けます。だからこの記事では、毎回 --bind 127.0.0.1 --port 29483 を明示します。
VPS で常駐させる:systemd とループバック
自分のホームに置いたバイナリは試用向けです。VPS で常駐させるなら、専用ユーザーを作り、/usr/local/bin と /etc/rustxng に置きます。設定ファイルはタグの settings.toml をそのまま使います。
sudo useradd --system --home-dir /nonexistent --shell /usr/sbin/nologin rustxng
sudo install -m755 ~/rustxng-dl/rustxng-v0.27.1-x86_64-unknown-linux-musl /usr/local/bin/rustxng
sudo install -d -m755 /etc/rustxng
sudo curl -fL -o /etc/rustxng/settings.toml https://raw.githubusercontent.com/sahenjp/RustXNG/v0.27.1/settings.toml/etc/systemd/system/rustxng.service を作ります。
[Unit]
Description=RustXNG metasearch (v0.27.1)
After=network-online.target
Wants=network-online.target
[Service]
User=rustxng
Environment=SEARXNG_SETTINGS_PATH=/etc/rustxng/settings.toml
ExecStart=/usr/local/bin/rustxng --bind 127.0.0.1 --port 29483
Restart=on-failure
NoNewPrivileges=true
[Install]
WantedBy=multi-user.targetSEARXNG_SETTINGS_PATH は Dockerfile と同じ環境変数です。ProtectSystem= などのサンドボックス設定は、ここでは足していません。v0.27.1 がどこに書き込むかを、この記事では確かめていないためです。動作を確認してから、1つずつ足してください。
sudo systemctl daemon-reload
sudo systemctl enable --now rustxng
systemctl status rustxng --no-pager
ss -ltn 'sport = :29483'
curl --fail --max-time 3 http://127.0.0.1:29483/healthzss の出力の Local Address 欄が 127.0.0.1:29483 なら、外からは届きません。0.0.0.0:29483 や *:29483 が出たら、設定ファイルかフラグが意図と違います。サービスを止めて ExecStart を見直してください。
/healthz はプロセスが生きているかを見るだけです。README も、成功しても検索先のエンジンが動いている保証にはならないと書いています。実際に検索できるかは、プロジェクトのエージェント向けガイドにある JSON 検索で確かめます。
curl --fail --max-time 20 --get 'http://127.0.0.1:29483/search' --data-urlencode 'q=tokio runtime documentation' --data 'format=json' --data 'max_results=5' | python3 -m json.tool | head -n 40results の配列に title、url、content を持つ項目が並べば成功です。配列が空なら、プロセスは動いていても検索先から結果が返っていません。journalctl -u rustxng -n 50 で、どのエンジンが失敗したかを見てください。
外からは SSH トンネルか tailnet で使う
v0.27.1 の settings.toml は limiter = false で出荷されています。limiter(リクエスト数の制限)を有効にしても、ファイルのコメントによると「simplified per-client rate limit」で、上流の botdetection ではありません。image_proxy も false です。上流で limiter.toml と Valkey で組んだボット対策 は、RustXNG には持ち込めません。ですから、インターネットに公開するインスタンスとしては考えないでください。
自分だけで使うなら、SSH のポート転送がいちばん簡単です。手元の PC で次を実行し、ブラウザで http://127.0.0.1:29483 を開きます。
ssh -N -L 29483:127.0.0.1:29483 you@203.0.113.10VPS 側のファイアウォールは何も開けなくて済みます。家族や複数の端末から使うなら、Tailscale などの tailnet(自分の端末だけでつくる仮想ネットワーク)越しにアクセスする方法もあります。どうしてもリバースプロキシで公開するなら、認証を前に置いてください。README も、ループバック以外で公開するのは意図した選択であり、アクセス制御が必要だと書いています。SearXNG で同じことをするときの考え方は 公開 SearXNG インスタンスを固める方法 を参考にしてください。
既存の settings.yml を RustXNG で試す
COMPATIBILITY.md によれば、上流の settings.yml はそのまま読めます。とはいえ、本番の SearXNG を止めて差し替えるのは避けてください。別のポートで並べて動かし、結果を見比べるのが安全です。
SEARXNG_SETTINGS_PATH=/etc/searxng/settings.yml "$HOME/.local/bin/rustxng" --bind 127.0.0.1 --port 29484--bind と --port を付けているのは、前の章で説明した理由からです。付けないと、YAML の中の server.bind_address と server.port が使われます。上流の設定ではポートが 8888 のことが多く、動いている SearXNG と同じ番号を取り合います。
見比べるときは、YAML の engines 欄も読み直してください。上流の設定で有効にしていた Google 系のエンジンは、RustXNG では削除されています。Yahoo! JAPAN と Mojeek は次の章で説明する理由で既定では無効です。ただし設定で disabled = false を明示していれば、その指定が優先されます。
コーディングエージェントに rustxng mcp をつなぐ
RustXNG のいちばん新しい使い道は、エージェントの検索窓口です。rustxng mcp は MCP(Model Context Protocol、エージェントと外部ツールをつなぐ規約)のサーバーとして動きます。読み取り専用の search と read_page の2つのツールを、標準入出力(stdio)で提供します。ヘルプには rustxng mcp [--config FILE] とあります。
stdio で動くので、ネットワークのポートは開きません。エージェントが子プロセスとして起動し、パイプでやり取りします。README に書かれている既定の動きは次のとおりです。
searchは 5 件の結果を返し、各スニペットは 500 文字までです。- シリアライズされた構造化 JSON 本体は、既定で 12,000 Unicode 文字かつ 24,000 UTF-8 バイトまでに収まり、切り詰めを示すフラグと
next_offsetが付きます。この上限に JSON-RPC のエンベロープ、SDK のテキスト表示、呼び出し側のプロンプトは含まれません。呼び出し側は、公開された範囲内で上限を増減できます。 read_pageは、同じセッションのsearchが返した URL だけを取得します。エージェントが任意の URL を読みに行くことはできません。- 外向きのプロキシを設定していると、
read_pageは失敗します。ページの取得には直接接続が必要だからです。
README と docs/AGENT-SETUP.md には、特定のエージェント用の設定例はありません。次は Claude Code の claude mcp add の構文に合わせて、この記事で書いた例です。プロジェクトが公式に示したものではなく、この記事では動作を確かめていません。
claude mcp add --transport stdio --scope user rustxng -- "$HOME/.local/bin/rustxng" mcp --config /etc/rustxng/settings.toml
claude mcp list-- より後ろは、そのまま RustXNG に渡されます。claude mcp list で rustxng が ✔ Connected と表示されれば、起動できています。✘ Failed to connect は接続できなかったことを示し、原因はパスや設定ファイル以外にもあります。同じコマンドを手で実行して、エラーを見てください。MCP サーバーを VPS 上でどう置くかの全体像は VPS で MCP サーバーを動かす方法 に、MCP を使わずに SearXNG をエージェントへつなぐ方法は SearXNG をエージェントの検索スキルにする方法 にあります。
エージェントが HTTP の /search を直接呼ぶ使い方もあります。その場合、エージェントがバックグラウンドで起こしたプロセスが残り続けないように、ガイドは RUSTXNG_IDLE_TIMEOUT=300 を勧めています。一定時間使われないと、プロセスが自分で終了します。settings.toml の既定は idle_timeout = 0 で、無効です。
注意点が1つあります。エージェントが投げる検索語には、プロジェクト名や関数名、エラーメッセージが入ります。それらはすべて、有効にした外部の検索先に送られます。
検索先の利用規約:ライセンスとは別の問題です
RustXNG の README には、作者のおわびが載っています。英語版では「That was an oversight, and I apologize.」、日本語版では「検索先の利用条件を十分に確認しないまま、性能面を強調して紹介してしまいました。」と書かれています。そのうえで README は、次の点を明記しています。
- 検索サービスの中には、自動検索、スクレイピング、大量リクエスト、結果の保存や再配布を制限しているものがあります。
- 個人で、あるいは自宅の LAN で動かしても、それだけで制限の対象外になるとは限りません。
- API キーなしで結果が取れることは、自動での利用が許されていることを意味しません。
- 設定に検索先が入っていることは、どの使い方も許されていることの保証ではありません。
Google 関連の連携はすでに削除されました。v0.27.1 では、Yahoo! JAPAN と Mojeek の HTML アダプターが既定で無効になっています。docs/PROVIDERS.md は、その理由を「許諾を確認できていないHTML経路を標準利用から外す保守上の判断」と説明しています。同じページによると、Yahoo! JAPAN の該当ヘルプはスクレイピングなどの機械的な収集を禁じており、Mojeek の規約は認められた API 利用者以外の自動アクセスを禁じています。2026年11月4日に両社の一次資料も確認しました。Yahoo! JAPAN のヘルプは検索エンジン運営者によるインデックス作成目的のクロールを例外とし、Mojeek の規約は事前同意のないスクレイピングも禁じています。日本の読者にとって Yahoo! JAPAN は身近な検索先です。使う前に、自分で規約を読んでください。
ここで混同しやすい点があります。AGPL が定めているのは、RustXNG のコードを使い、改変し、配るときの条件です。AGPL の文面は、検索サービスを使う許可や、その検索結果を再利用する許可には触れていません。これはライセンス文を読んだうえでの筆者の理解です。コードが自由でも、問い合わせ先との関係は、その会社の規約で決まります。
同じ問いは SearXNG にも当てはまる、と筆者は考えています。SearXNG も外部の検索サービスに問い合わせて結果をまとめる仕組みだからです。SearXNG のプロジェクトがこの点について何と言っているかは、この記事では確かめていません。それでも、RustXNG の作者が書いたことは SearXNG を使う人にとっても読む価値があります。
この記事では、プロキシの切り替え、User-Agent の偽装、CAPTCHA の回避は扱いません。検索先が CAPTCHA やアクセス拒否を返すのは、その使い方を受け付けていないという合図です。SearXNG の現行の既定設定では、通常のアクセス拒否は 180 秒(3分)、CAPTCHA は 3600 秒(1時間)エンジンを止めます。Cloudflare と reCAPTCHA の専用例外には別の停止時間が設定されています。止まったエンジンは、規約を読み直したうえで無効にするのが正しい対応です。
RustXNG に乗り換えるかどうかの判断基準
RustXNG が向いているのは、次のような場合です。
- 自分やエージェントだけが使う検索を、メモリの少ない VPS のループバックで動かしたい。
- JSON API か MCP だけを使い、Web 画面の見た目にはこだわらない。
- 約2週間で 40 タグという変化の速さに付き合い、更新のたびに README と設定を読み直せる。
- 有効にする検索先の規約を、自分で確認する手間をかけられる。
SearXNG のままでいるべきなのは、次のような場合です。
- 公開インスタンスを運営していて、botdetection と limiter.toml に頼っている。
- テーマ、テンプレート、特定のプラグインを使い込んでいる。
- Google 系エンジンの結果が欲しい。
- 1つのバージョンを長く据え置いて運用したい。
迷うなら、今の SearXNG を残したまま、RustXNG を別ポートで1週間ほど並べて動かしてください。検索結果の質と、journalctl に出るエラーを比べれば、自分の用途に合うかが分かります。
FAQ
RustXNG は SearXNG の settings.yml をそのまま使えますか?
v0.27.1 の docs/COMPATIBILITY.md には、--config settings.yml か SEARXNG_SETTINGS_PATH で上流の YAML をそのまま指定できると書かれています。ただし、YAML の server.bind_address と server.port がそのまま待ち受け先になります。起動時に --bind 127.0.0.1 --port 29484 のように明示してください。Google 系のエンジンは RustXNG から削除されているので、その結果は出ません。
RustXNG の既定のポートは 8888 ですか、29483 ですか?
v0.27.1 の settings.toml と README では 127.0.0.1:29483 です。README によると、公開済みの v0.26.0 のバイナリは 8888 を使います。8888 は SearXNG でもよく使う番号です。起動時に --port を明示し、ss -ltn 'sport = :29483' で実際の待ち受け先を確かめるのが確実です。
RustXNG は本当に SearXNG より軽いのですか?
プロジェクトの docs/BENCHMARK.md では、起動から /healthz までが SearXNG 0.72 秒、RustXNG 0.03 秒です。常駐メモリは 118 MiB 対 13 MiB です。ただし RustXNG は cargo run --release、SearXNG は granian で動かした、条件の揃わない計測です。ページ自身も過去の条件の記録だと書いています。v0.27.1 のバイナリは記録当時より大きいので、自分の VPS で測り直してください。
AGPL のソフトウェアなら、検索結果を自由に使ってよいのですか?
いいえ。AGPL はソフトウェアのコードを使い、改変し、配る条件を決めるライセンスです。検索サービスに自動で問い合わせる許可や、その結果を保存・再配布する許可は、各サービスの規約で決まります。RustXNG の README も、設定に検索先が入っていることは利用が許されている保証ではないと書いています。
rustxng mcp はネットワークにポートを開きますか?
開きません。rustxng mcp は標準入出力で MCP の search と read_page を提供し、エージェントが子プロセスとして起動します。ただし検索語は、有効にした外部の検索先に送られます。read_page は、同じセッションの search が返した URL だけを読みます。