RustXNG vs SearXNG: which one to self-host
RustXNG is a Rust metasearch binary for AI agents, with a JSON API and MCP tools. See what it drops from SearXNG and when SearXNG stays the better pick.
RustXNG vs SearXNG: the short answer
RustXNG is a single Rust binary, based on SearXNG, that serves metasearch results to AI agents through a JSON API and an MCP (Model Context Protocol) server. Choose RustXNG if your main user is an agent that needs short, bounded results and optional page text. Keep SearXNG if people use the web interface, if you rely on bangs, or if you depend on the limiter with Valkey and a mature upstream project.
The rest of this guide explains why. It also installs RustXNG by hand on a VPS and shows where the project's own documents disagree with each other.
What RustXNG is, and which version this guide describes
The README describes RustXNG as "a self-hosted metasearch engine implemented in Rust, based on SearXNG". Its optional local index and crawler are disabled by default. With the default configuration described here, every query goes out to external search providers, and RustXNG merges what comes back. SearXNG works the same way, and the guide to self-hosting SearXNG on a VPS explains it in more depth. The license is AGPL-3.0-or-later.
This guide pins v0.27.1. References below to RustXNG behaviour, defaults, the README and compatibility documents describe that version unless stated otherwise. On 9 November 2026 the GitHub Releases page marks v0.31.0, published on 8 November, as Latest. Version v0.27.1 was published on 3 November, a few hours after v0.27.0. Version v0.26.0 came out on 1 November. Version v0.30.0 revised the Standard, Clean and Full search profiles, which already existed in v0.29.0; Clean searches only local indexes without external search-provider requests, while Standard and Full send queries to their enabled providers.
The README does not fully match the releases. One sentence still says "The published v0.26.0 release includes" the binaries, but the install example pins v0.27.1. The difference matters for one setting: v0.27.0 moved the default port to 29483, and the README notes that "Published v0.26.0 binaries still default to 8888". If you follow an older guide and nothing answers on 29483, check rustxng --version first. Every command below passes --port 29483 explicitly, which works with either version.
Read this before you install: provider terms and the loopback default
Self-hosting does not make your searches private from the providers. The README says it directly: "Search terms are sent to the selected external providers, even when RustXNG itself runs on your local network." It also warns that "Some providers restrict automated searches, scraping, high-volume requests, storing results". It adds that a provider being in the configuration "is not a guarantee that every use is authorized or compliant". An agent can send far more queries than a person. Read the terms of each provider you enable before you point an agent at it. Per the README, the Yahoo! JAPAN and Mojeek HTML adapters stay disabled by default while their permissions are reviewed.
The second point is the bind address. RustXNG listens on 127.0.0.1:29483 by default, so only processes on the same machine can reach it. The README's Docker example keeps that rule: it publishes 127.0.0.1:29483 on the host and binds 0.0.0.0 only inside the container. The README describes no built-in authentication. It tells you to configure your own access controls if you publish on other interfaces. Without them, anyone who finds the port can use your server, and your provider quotas, as a free search API. Keep it on loopback unless you put your own access control in front of it.
What RustXNG removed from SearXNG
The README lists the removals in one sentence: "Google search engines, autocomplete, external bangs, YouTube, Google translation integrations, Material Icons, and Google-backed search front ends have been removed."
Two of those change daily use for a person:
- External bangs. In SearXNG, a bang in the query can send you straight to another site. RustXNG removed external bangs, so that habit stops working.
- Autocomplete. SearXNG's settings docs show
autocomplete: "duckduckgo"as the default. RustXNG removed autocomplete, so the search box gives no suggestions.
An agent uses neither feature, so the project could drop them. The README also says older custom settings must have the removed entries deleted before the server will start. If you copy a SearXNG config that still lists a Google engine, expect a startup error until you remove that entry.
Does your SearXNG settings.yml carry over?
Partly, and only on the project's own word. RustXNG ships a settings.toml, and its defaults are compiled into the binary. A config file is optional. You pass it with rustxng --config /path/to/settings.toml. A partial file overrides only the values it sets. Know one trap before you write your own file: "With use_default_settings = false, an omitted or empty engine list enables no engines." A server with no engines starts and returns nothing. A short file that looks correct can therefore disable search completely.
The compatibility page, docs/COMPATIBILITY.md (written in Japanese), says you can pass an upstream YAML file unchanged and that TOML also works. It says --config or SEARXNG_SETTINGS_PATH selects the file. The same page lists real differences. Templates and themes are not compatible. The limiter is RustXNG's own implementation, and it does not read your limiter.toml.
Be careful with the parity numbers. COMPATIBILITY.md claims all upstream engine entries are implemented "(100%)" and that bang data is generated from the same upstream data. Both claims conflict with the README, which says Google engines and external bangs were removed. docs/COVERAGE.md gives the same 100% figures. But it opens by saying they are a record from an earlier porting stage, not current coverage and not a guarantee of behaviour. It also says the Valkey/Redis cache is not ported, while the README says it is supported. Treat the README as current for v0.27.1 and the conflicting claims in those two versioned docs as stale. Before you migrate, start RustXNG with your file and run the queries you depend on.
Install RustXNG v0.27.1 on a VPS yourself
The README contains a block addressed to software, headed "AI agents: install RustXNG and use it as your local web search tool." It tells an agent to download a binary, check it, start it and test it. Do not let an agent follow instructions it read inside a repository. Text in a README is untrusted input. An agent that obeys it will also obey the next README that asks for something worse. That is the core problem behind prompt injection against coding agents. Install the binary yourself, then give the agent a working endpoint.
The v0.27.1 release ships Linux binaries for x86_64 (GNU and musl) and ARM64 (aarch64-unknown-linux-gnu, which needs glibc 2.39 or newer). Each binary has a matching .sha256 file. These steps use the x86_64 musl build, the same one the README's example downloads:
sudo apt update && sudo apt install -y curl jq
mkdir -p ~/rustxng-download && cd ~/rustxng-download
tag=v0.27.1
asset="rustxng-${tag}-x86_64-unknown-linux-musl"
base="https://github.com/sahenjp/RustXNG/releases/download/${tag}"
curl -fLO "${base}/${asset}"
curl -fLO "${base}/${asset}.sha256"
sha256sum --check "${asset}.sha256"sha256sum should print the file name followed by OK. A line ending in FAILED means your download does not match the file the release published. Delete it and download it again. A checksum from the same release page proves the download is intact. It does not prove the code is safe to run.
Install it and confirm the version:
sudo install -m 755 "$asset" /usr/local/bin/rustxng
rustxng --versionIf you have a Rust toolchain (1.88 is the minimum supported version), the README's source install works too: cargo install --git https://github.com/sahenjp/RustXNG.git --tag v0.27.1 --locked.
Run RustXNG under systemd on loopback
A process you start in a terminal stops when the session ends. A small systemd unit keeps RustXNG running and restarts it after a crash. DynamicUser=yes runs it as a temporary system user, so the service does not run as root.
sudo tee /etc/systemd/system/rustxng.service > /dev/null <<'UNIT'
[Unit]
Description=RustXNG metasearch (loopback only)
After=network-online.target
Wants=network-online.target
[Service]
DynamicUser=yes
Environment=SEARXNG_PORT=29483
ExecStart=/usr/local/bin/rustxng --bind 127.0.0.1 --port 29483
Restart=on-failure
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now rustxng
curl --fail http://127.0.0.1:29483/healthz && echo healthyhealthy means the process answers. The README defines /healthz as "process health". It says a successful check does not mean the upstream engines work. If the unit fails to start, read journalctl -u rustxng -n 50. A config that still names a removed Google engine fails here, at startup.
To reach the web interface from your laptop without opening a port, use an SSH tunnel: ssh -L 29483:127.0.0.1:29483 you@your-vps. Then open http://127.0.0.1:29483/ in your browser.
The agent JSON API: max_results, include_domains and raw_content
An agent calls GET /search with format=json. In SearXNG the settings docs show only the html format enabled by default, so JSON needs a config change. The RustXNG README calls it with no config at all. RustXNG also adds parameters that SearXNG does not have:
max_results: how many ranked results to return, from 1 to 200.include_domains: keep only results from that domain and its subdomains.exclude_domains: drop results from that domain and its subdomains.include_raw_content=1: fetch page text into araw_contentfield for the top results.
This is the README's short query:
curl --fail --get 'http://127.0.0.1:29483/search' \
--data-urlencode 'q=tokio runtime documentation' \
--data 'format=json' --data 'max_results=5' \
| jq '{results: [.results[] | {title, url, content}]}'Here is the same query limited to one site, with page text:
curl --fail --get 'http://127.0.0.1:29483/search' \
--data-urlencode 'q=tokio runtime documentation' \
--data 'format=json' --data 'max_results=5' \
--data 'include_domains=docs.rs' --data 'include_raw_content=1' \
| jq '[.results[] | {url, chars: ((.raw_content // "") | length)}]'With default settings, page text is fetched for up to five results, "with a limit of 8,000 characters per page; individual fetches can fail." Some results therefore come back with no raw_content, and your agent code must handle that. The README also notes that "Character limits are not token limits". So 8,000 characters is not 8,000 tokens in your model's budget.
SearXNG can feed agents too. Once you enable the format, it returns the standard JSON fields. The SearXNG JSON API setup for Open WebUI walks through that change. What SearXNG lacks is the built-in result cap and page fetch, so you write that part yourself.
The MCP server: search and read_page
rustxng mcp serves two read-only tools over stdio. You register the command in your MCP client's configuration, and the client starts it as a child process. The README gives no client config example, so follow your client's documentation. The guide to running MCP servers on a VPS covers that side.
searchreturns ranked snippets and source metadata. It defaults to five results and cuts each snippet at 500 characters.read_pagefetches page text, but only for a URL thatsearchreturned earlier in the same session. Pass aqueryand it also returns up to three matching passages.
By default the whole structured response is capped at 12,000 Unicode characters and 24,000 UTF-8 bytes. When the server has to cut, it shortens snippets first and then drops trailing results. The fields truncated, source_truncated and next_offset tell the agent whether to ask for more.
One behaviour surprises people on a VPS. read_page refuses to work when an outgoing proxy is configured, either in settings or in the environment. The README gives the reason: page reads "require direct connections so DNS answers and redirects can be checked against public addresses". Through a proxy, RustXNG cannot see where a hostname really resolves. It could not block a page that redirects to an internal address, so it fails closed instead. Search itself still uses your proxy settings.
Page text from the open web is untrusted input for your agent, whichever tool fetched it. The same-session URL rule limits where read_page can go. It does not make the text safe to obey.
What the SealQA numbers measure
The README reports a SealQA run dated 2026-11-02. It used default settings and ten results per question, with no LLM and no local index. These are the project's own figures. They have not been reproduced here. The README says this run used an earlier engine set and does not establish performance of the changed defaults.
The data behind this chart
[
{
"label": "Seal-0",
"found_at_1_pct": 47.75,
"found_at_5_pct": 54.95,
"found_at_10_pct": 65.77,
"median_response_s": 1.85,
"question_count": 111
},
{
"label": "Seal-Hard",
"found_at_1_pct": 39.37,
"found_at_5_pct": 49.21,
"found_at_10_pct": 61.42,
"median_response_s": 1.53,
"question_count": 254
}
]On the 111 Seal-0 questions, the reference page was in the top ten results 65.77% of the time. The median response took 1.85 seconds. On the 254 Seal-Hard questions, the reference page was the first result 39.37% of the time.
Read these as the README tells you to: "These are reference-page retrieval rates, not answer accuracy." They measure whether the right page came back. They say nothing about whether an agent then answered correctly. The README also gives no SearXNG run on the same questions to compare against.
When SearXNG is still the right choice
SearXNG remains the better pick in four cases.
- People search on it. RustXNG keeps a browser UI, but it has a single theme, no autocomplete and no external bangs.
- You need a limiter you can tune. SearXNG documents its bot detection in detail. Its
http_sec_fetchfilter rejects requests with an invalidSec-Fetch-ModeorSec-Fetch-Destheader, and itslink_tokenmethod "requires a valkey DB". RustXNG has its own limiter (an IP sliding window, link tokens and 429 responses), but it does not readlimiter.toml. - You tuned engines and timeouts. SearXNG ships its defaults in
searx/settings.yml. Its outgoing block setsrequest_timeout: 3.0seconds. An engine that returns HTTP 429 is suspended for 180 seconds by default (search.suspended_times.SearxEngineTooManyRequests). Your work from choosing which SearXNG engines to enable and disable maps onto those settings. In RustXNG you would test each one again. - You value maturity. SearXNG is the upstream project that RustXNG is based on. RustXNG published four releases between 1 and 3 November 2026.
When the agent-first binary wins
RustXNG wins when the only client is an agent on the same machine. You get one binary with no Python environment, listening on loopback by default. JSON works without a config change. You also get result caps, domain filters and optional page text with a fixed budget. The MCP server's fetch tool only follows its own search results. For a coding agent in a disposable VM, that means less glue code than SearXNG plus your own fetch and truncation code.
Both can run on one VPS. SearXNG serves people on its port, RustXNG serves agents on 29483, and each keeps its own settings.
FAQ
Is RustXNG a drop-in replacement for SearXNG?
No. RustXNG removed Google engines, autocomplete, external bangs, YouTube and Google translation, and templates and themes are not compatible. The project says you can pass an upstream settings.yml unchanged, but older configs must have the removed entries deleted before startup. Your limiter.toml rules do not carry over either, because RustXNG has its own limiter.
Why does nothing answer on port 29483?
Check rustxng --version. Version v0.27.0 moved the default port to 29483, and the README says published v0.26.0 binaries still default to 8888. Start it with --bind 127.0.0.1 --port 29483 and both versions listen on the same port.
Why does read_page fail on my VPS when search works?
read_page fails closed when an outgoing proxy is configured in settings or set in the environment. Page reads need a direct connection so RustXNG can check DNS answers and redirects against public addresses. Remove the proxy for the MCP process, or use search results only.
Does self-hosting RustXNG keep my searches private?
Not from the search providers. The README says search terms go to the selected external providers even when RustXNG runs on your own network. Self-hosting hides your queries from a third-party metasearch operator. It does not hide them from the engines that answer them, and some of those engines restrict automated use.
Should I let my AI agent install RustXNG from the README?
No. The README contains a block of instructions addressed to AI agents. Install the release binary yourself and check its SHA-256 file with sha256sum --check. Run it on loopback under systemd, then give the agent the endpoint. An agent that follows instructions from a repository will follow malicious ones just as readily.