Fireplexity

Guide

SearXNG with Docker Compose,
set up for AI search.

Most SearXNG Docker guides still use a repository that was archived in 2026. The settings that protect a public instance also block AI apps from using it, and the error does not explain why. This guide covers the current setup from start to finish. We tested every step on a fresh install.

The short version

If you used searxng-docker

That repository is archived. The compose file is now in the main searxng/searxng repository. It runs SearXNG and Valkey only, without Caddy. You can reuse your old settings.yml after you change the Valkey hostname.

If an AI app will call it

JSON output is off by default, so API requests return 403. When the limiter is on, each IP can make only four JSON requests an hour, and Firecrawl's requests are rejected every time. To fix this, put the app on its own Docker network and add that network to the limiter's pass list.

We ran every command below with Docker Compose v5.6 and SearXNG 2026.10.19-62366b05c. The config files are the ones we tested, not copies from the documentation.

What SearXNG is, and what it isn't

SearXNG is a free, open-source metasearch engine, licensed under AGPL-3.0. With about 38,600 GitHub stars, it is the most widely used project of its kind. It has no index of its own. It sends each query to other search engines, then merges and ranks their results. The results page has no ads or trackers. The search engines see your server's IP address, but not your users' cookies or browser details.

This design makes SearXNG popular with AI search projects. Vane includes it, self-hosted Firecrawl can use it for /search, and any program that makes HTTP requests can get free JSON results from it. The same design also makes it unreliable. SearXNG depends on search engines run by other companies, and those engines try to block automated traffic. The section on keeping it working covers this.

One change in 2026 surprises returning users: Google and Bing are off by default. In the current settings.yml, general web results come from Brave, DuckDuckGo, Google CSE (Google's custom search service), Wikipedia and Wikidata. The google and bing engines are set to disabled: true. You can turn them back on. The trade-off is explained below.

searxng-docker is archived: what replaced it

For years, the standard install used the separate searxng/searxng-docker repository. You cloned it, edited a .env file, and got SearXNG, Redis and a Caddy reverse proxy with automatic HTTPS. In March 2026, the project reworked its container setup. The old repository is now archived, and its README says it is superseded. Older guides may still work for now, but they follow a layout that is no longer maintained.

Old and new Docker setups — October 2026
Official compose (current)searxng-docker (archived)
Where it livescontainer/ in searxng/searxngSeparate repo, read-only
ServicesSearXNG (core) and ValkeySearXNG, Redis/Valkey and Caddy
HTTPSBring your own reverse proxyCaddy with Let's Encrypt
Config folder./core-config/ → /etc/searxng/./searxng/
Port8080 on all interfaces unless you set SEARXNG_HOST127.0.0.1:8080, with Caddy on 80/443
Redis/Valkey servicevalkey (container searxng-valkey)redis, running a Valkey image

The most important change is the removal of Caddy. The old setup bound SearXNG to localhost and set up HTTPS automatically. The new setup serves plain HTTP on every network interface, and you choose what to put in front of it. For a search backend that only your own app uses, this is simpler, because there are fewer services to run.

Migrating an existing install

Migration takes four steps. Set up the new layout in a new folder (see Step 1), stop it, move your old config into it, and change one hostname:

From an old searxng-docker checkout
$ docker compose down                           # in the new ./searxng folder
$ sudo mv ./searxng-docker/searxng/* ./searxng/core-config/
# in core-config/settings.yml, point Valkey at the new service name:
#   valkey:
#     url: valkey://valkey:6379/0
# copy any variables you set in the old .env into the new one, then:
$ docker compose up -d

Keep the old folder until the new instance returns search results. If your old instance was public, you now need your own reverse proxy, because the new setup does not include Caddy.

Step 1: install SearXNG with Docker Compose

You need Docker Engine with the Compose plugin, or Podman. The compose file uses :Z volume labels, so it works on systems with SELinux enforcing. We ran it on Fedora without changes. Download the two template files and start the services:

Fresh install — official compose instancing
$ 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
$ echo 'SEARXNG_HOST=127.0.0.1' >> .env           # listen on localhost only (see below)
$ docker compose up -d
$ docker compose ps
NAME             IMAGE                              STATUS    PORTS
searxng-core     docker.io/searxng/searxng:latest   Up        127.0.0.1:8080->8080/tcp
searxng-valkey   docker.io/valkey/valkey:9-alpine   Up        6379/tcp

Open http://localhost:8080 and run a search. On first start, the container creates a minimal settings.yml in core-config/ and replaces the placeholder secret_key with a random value. You no longer need to generate a key with openssl.

Three things the template doesn't tell you

The port is open to the internet by default. Without SEARXNG_HOST, Compose publishes port 8080 on every network interface. Docker's documentation states that published ports bypass ufw, because Docker routes the traffic before the firewall rules apply. Even if ufw blocks all incoming traffic on your VPS, anyone can still reach your instance. Set SEARXNG_HOST=127.0.0.1 unless you want the instance to be public.

Your normal user can't edit the config. On start, the container makes its searxng user (UID 977) the owner of core-config/. As a result, nano core-config/settings.yml fails with “permission denied”. Use sudo, or edit the file inside the container with docker compose exec --user root core vi /etc/searxng/settings.yml.

Docker Hub limits anonymous downloads. If docker compose pull fails with a rate-limit error, change the image: line to the copy at ghcr.io/searxng/searxng.

Step 2: turn on the JSON API

AI apps need results in JSON, not HTML. A new instance does not provide JSON:

A fresh instance
$ curl -s -o /dev/null -w '%{http_code}\n' 'http://127.0.0.1:8080/search?q=test&format=json'
403

The default settings allow only html. According to the API documentation, a request for any format that is not enabled returns 403. The generated file starts with use_default_settings: true, so you only need to add the settings you change. This is the complete file we used:

core-config/settings.yml
use_default_settings: true

server:
  secret_key: "keep-the-one-the-container-generated"
  image_proxy: true
  limiter: true              # only if people or bots you don't control can reach it — Step 3

search:
  formats:
    - html
    - json

valkey:
  url: valkey://valkey:6379/0   # the compose service name, not localhost
Apply and check
$ docker compose restart core
$ curl -s 'http://127.0.0.1:8080/search?q=searxng+docker&format=json' -H 'Accept-Language: en' | jq '.results | length'
20

The response has seven top-level keys: query, results, answers, corrections, infoboxes, suggestions and unresponsive_engines. Each result includes url, title, content (a short snippet), the engines that returned it, and a score. SearXNG returns snippets, not full pages. If your model needs more than a few sentences of text, another tool must fetch the pages. In a fully local Fireplexity, Firecrawl does this.

Other useful parameters: categories (for example general, news, images), engines to pick engines explicitly, language, time_range (day, month, year), pageno and safesearch (0–2).

Step 3: the limiter, and why it blocks AI apps

The limiter is SearXNG's bot protection. It requires Valkey, which is why the compose file includes Valkey. It is off by default, and it turns on automatically when you set public_instance: true. If your instance is reachable from the internet, you should turn it on. Without it, bots that send many requests to your instance can get your server's IP blocked by Google and DuckDuckGo.

The problem is that the limiter treats most API clients as bots. We read the source code and then tested it. For every /search request, the limiter returns 429 in these cases:

  • The request has no Accept-Language header, its Accept header does not allow HTML, or it does not accept gzip or deflate compression.
  • The user agent matches a block list that includes curl, python-requests, Python, Go-http-client, Java and okhttp.
  • The request asks for a format other than HTML, and the same IP has already made four such requests in the past hour (API_MAX = 4 over a 3,600-second window). This limit is fixed in the code. You cannot change it in the settings.

These are the results from our test instance with the limiter on:

JSON requests with the limiter on — measured, SearXNG 2026.10.19
ClientResultWhy
Plain curl429 on every requestUser agent on the bot list, no Accept-Language
Firecrawl-style axios request429 on every requestAxios sends no Accept-Language
Same, with Accept-Language: en200 × 4, then 429The four-an-hour API limit
Any client on a pass_ip network200 × 8 of 8Pass list skips every check

Firecrawl hides this problem. Its SearXNG client catches errors and returns an empty result list, so a blocked search looks the same as a search with no results. An answer engine built on it then answers without sources, or invents an answer.

The fix: decide who will use the instance

Private backend — only your app

  • Leave limiter: false.
  • Don't publish the port publicly: SEARXNG_HOST=127.0.0.1, or no port at all and a shared Docker network.
  • No outside client can reach it, so it needs no rate limit.

Public instance — people and your app

  • Turn on limiter: true and put a reverse proxy in front.
  • Add the proxy to trusted_proxies so the limiter sees real client IPs.
  • Put your app on its own network and list it in pass_ip.

For a public instance, give the app a network with a fixed subnet. Do not rely on Docker's default addresses. On our machine, the compose network used 192.168.80.0/20, not the 172.x range that most examples assume. As a result, a pass_ip entry for 172.16.0.0/12 had no effect, and no error was shown. Create this file next to docker-compose.yml:

compose.override.yml — picked up automatically by docker compose
services:
  core:
    networks: [default, ai]
    # ports: !reset []        # uncomment to stop publishing the port at all (Compose 2.24+)

networks:
  ai:
    name: searxng-ai          # fixed name, so other compose projects can join it
    ipam:
      config:
        - subnet: 10.89.0.0/24

Next, add the network to the limiter's configuration. Create limiter.toml next to settings.yml. It only needs the settings you change:

core-config/limiter.toml
[botdetection]
trusted_proxies = [
  '127.0.0.0/8',
  '::1',
  '192.168.80.0/20',   # the network your reverse proxy container is on — check yours
]

[botdetection.ip_lists]
pass_ip = [
  '10.89.0.0/24',      # searxng-ai: your AI app, no limits
]

The limiter reads the client IP from the X-Forwarded-For header, but only when the request comes from a proxy listed in trusted_proxies. By default, only localhost is trusted. Behind a proxy container, every visitor would appear to have the same IP and would share one limit of four API requests an hour. To find your network ranges, run docker network inspect searxng_default.

We tested this setup with both files in place:

  • Browsers that connected through the proxy loaded search pages normally.
  • A client that requested JSON through the proxy was blocked after four requests.
  • The app on the searxng-ai network was never blocked.

Step 4: connect your AI app

Once the searxng-ai network exists, any container on it can reach SearXNG at http://searxng-core:8080. You don't need to expose the port outside the machine.

Firecrawl (and Fireplexity on self-hosted Firecrawl)

Self-hosted Firecrawl uses SearXNG for /search when SEARXNG_ENDPOINT is set. Search runs in the api service, so connect that service to the network:

In your Firecrawl checkout
# .env
SEARXNG_ENDPOINT=http://searxng-core:8080
SEARXNG_CATEGORIES=general        # optional; SEARXNG_ENGINES=brave,duckduckgo also works

# docker-compose.override.yaml
services:
  api:
    networks: [backend, searxng-ai]
networks:
  searxng-ai:
    external: true

We tested this setup with a container that sent the same kind of request as Firecrawl: an axios-style client, format=json, and no Accept-Language header. With the limiter on, all six requests succeeded, because the network is on the pass list. Firecrawl requests 20 results per page and uses the url, title and content fields. It does not get news or image results this way, so Fireplexity's news and image panels stay empty on self-hosted Firecrawl. The self-hosting guide covers the rest of the setup, including how to switch to a local model.

Vane

Vane's full image includes its own SearXNG. To use your instance instead, run the slim image and set the URL:

Vane slim, on the same network
$ docker run -d --name vane -p 127.0.0.1:3000:3000 --network searxng-ai \
    -e SEARXNG_API_URL=http://searxng-core:8080 \
    -v vane-data:/home/vane/data itzcrazykns1337/vane:slim-latest

Vane's README also requires the Wolfram Alpha engine, which is disabled by default. Enable it in settings.yml:

core-config/settings.yml — append
engines:
  - name: wolframalpha
    disabled: false

Your own code

Any HTTP client works. Send GET /search?q=...&format=json, read results, and check unresponsive_engines in every response. This list is the only sign that an engine has been blocked. Logging it is a simple, low-cost way to monitor your instance.

Keeping a private instance working

The steps above fix the limits on your own instance. They cannot stop the search engines from limiting you. Every query comes from one server IP, and the large search engines treat steady automated traffic from one IP as scraping. Our test instance ran on a home internet connection. After a few minutes of light testing, DuckDuckGo returned a CAPTCHA, and Google (enabled with engines=google) returned “access denied”. Bing and Google CSE kept working. Data-centre IPs are usually blocked sooner.

When an engine returns an error, SearXNG stops using it for a set time instead of retrying immediately. These are the current default times:

Engine suspension after an error — settings.yml, October 2026
Error from the engineSuspended forSetting
Access denied, HTTP 402/4033 minutesSearxEngineAccessDenied: 180
Too many requests, HTTP 4293 minutesSearxEngineTooManyRequests: 180
CAPTCHA1 hourSearxEngineCaptcha: 3600
Cloudflare access denied1 daycf_SearxEngineAccessDenied: 86400
Google reCAPTCHA7 daysrecaptcha_SearxEngineCaptcha: 604800
Cloudflare CAPTCHA15 dayscf_SearxEngineCaptcha: 1296000

Until early 2026, a CAPTCHA suspended an engine for a full day, and older guides still give that figure. As engines are suspended, a self-hosted answer engine returns fewer and worse results, without any warning. These steps help:

  • Monitor errors. The /stats/errors page on your instance lists each failing engine and the reason. Also log unresponsive_engines from your app.
  • Use several engines. With several engines in general, a suspended engine costs you some results, not all of them. If you choose a single engine with engines=, your app is only as reliable as that engine.
  • Enable Google with care. Add - name: google with disabled: false to turn it back on. On a busy instance, Google is usually the first engine to block you.
  • Use proxies for high volume. The outgoing.proxies setting in settings.yml takes a list of proxies to rotate between. On a server with several IP addresses, outgoing.source_ips rotates between them.
  • Cache results in your app. AI apps often repeat the same searches. Even a short cache reduces the number of queries sent to the engines.

If you need reliable search without this maintenance, use a paid search API, where the provider keeps search working. Our comparison of Firecrawl alternatives lists Tavily, Exa and Brave-based options with per-query prices.

Hardware, updates and pinning

SearXNG needs few resources. On our test machine, the core container used about 127 MB of memory and Valkey used 4 MB, with almost no CPU use when idle. The SearXNG image takes 383 MB of disk space and the Valkey image 67 MB. A JSON query took about 1.8 seconds, almost all of it spent waiting for the search engines. The smallest VPS plan is enough. The server's IP address matters more than its size.

Updating
$ docker compose down
$ docker compose pull
$ docker compose up -d
# to stay on a known build, pin it in .env:
# SEARXNG_VERSION=2026.10.19-62366b05c

Images are tagged by date and commit, and new images are released most days. Engine fixes are released quickly, so an old image is a common reason an engine stops working. latest is fine for a personal instance. If an app depends on the instance, pin a version. Before you download a new docker-compose.yml, check what changed, as the documentation advises.

Common questions

What is SearXNG?

A free, open-source metasearch engine under AGPL-3.0. It has no index of its own: it sends your query to engines such as Brave, DuckDuckGo, Google and Wikipedia, merges what comes back, and strips cookies and identifying data from the requests. You can use a public instance or run your own, usually with Docker.

Is searxng-docker deprecated?

Yes. The repository was archived in 2026 and its README says it is superseded. New installs use docker-compose.yml and .env.example from the container/ folder of searxng/searxng. The new setup runs SearXNG and Valkey only, with no bundled Caddy.

Why does SearXNG return 403 for format=json?

The JSON format is off by default. Add json to search.formats in settings.yml and restart the container.

Why does my app get 429 Too Many Requests?

The limiter is on. It rejects requests without browser-like headers, including Accept-Language, and allows each IP four non-HTML requests an hour. Keep the limiter off on a private instance only your app can reach, or put the app's network in pass_ip in limiter.toml.

Is SearXNG safe to use?

The software is open source and widely used, and it removes cookies and identifying data before forwarding a query. The question is who runs the instance. A public instance's operator can log your searches. On your own instance, the search engines see your server's IP. Your own instance on a server you control is the most private option, as long as you haven't left its port open to the internet.

Can I use a public SearXNG instance for my AI app?

Not reliably. Many public instances disable JSON, and those that allow it usually run the limiter, which caps API use at four requests per IP per hour. Their operators try to block automated traffic like this. Run your own instance instead. It needs about 130 MB of memory.

Sources

  1. SearXNG: container installation — compose instancing, management commands, GHCR mirror, Valkey hostname, migrating from searxng-docker
  2. searxng/searxng container/ — docker-compose.yml, .env.example, entrypoint.sh (secret key generation, ownership) and Dockerfile (Granian, UID 977), read at commit 62366b0; compose rework in PR #5906
  3. searxng/searxng-docker — archived repository and superseded notice
  4. SearXNG default settings.yml — output formats, limiter and Valkey defaults, suspension times, engine defaults, outgoing proxies; Google default changed in PR #6546
  5. SearXNG limiter — Valkey requirement, limiter.toml, trusted_proxies, pass_ip; header checks and the API limit from the botdetection source
  6. SearXNG search API — parameters, and 403 for formats that are not enabled
  7. SearXNG: why use a private instance — privacy properties of public and private instances
  8. Docker: packet filtering and firewalls — published ports bypass ufw
  9. firecrawl/firecrawl — apps/api/src/search/v2/searxng.ts and docker-compose.yaml, read at commit dcbc947 for the request shape, environment variables and error handling
  10. Vane on GitHub — slim image, SEARXNG_API_URL, JSON and Wolfram Alpha requirements

Tested on 19 October 2026 with SearXNG 2026.10.19-62366b05c, Valkey 9 and Docker Compose v5.6.0 on Fedora, from a residential connection. Memory, latency and blocking figures are from that one machine and will differ on yours, especially the blocking. This site is an independent community page and is not affiliated with SearXNG, Firecrawl or the Vane project.

SearXNG finds the sources.
Fireplexity reads them.

SearXNG returns links and snippets. Fireplexity turns them into an answer with citations. The self-hosting guide shows how to run both on your own servers.