Privacy

SearXNG Self-Hosted: Private Search and Its Catch

Self-hosting SearXNG: the two-container stack, why engines quietly stop answering a private instance, and the fifteen-day ban nobody warns you about.

SearXNG self-hosted — the two-container stack, engine suspensions, the Valkey question, and browser integration

⚡ The short version

SearXNG is two containers, and only one of them is doing anything until you configure it. The part no setup guide leads with: a private instance is a single IP address making every query, search engines treat that as a bot, and SearXNG responds by suspending the offending engine — for three minutes after a rate limit, and for fifteen days after a Cloudflare CAPTCHA. Knowing that is the difference between diagnosing a quiet instance and assuming it is broken.

There are seven guides to this on the first page of results and every one of them ends where the container starts. None of them tells you what happens three weeks later, when half your results come back thinner than they used to and nothing in the interface explains why.

Everything below about self-hosting SearXNG comes from the project’s own repository, read on 24 September 2026 at commit 3cd69d3: the compose file it ships, its default settings, its limiter module and its container entrypoint.

Why Do Results Quietly Stop Arriving?

Because engines are blocking you, and SearXNG is backing off on purpose.

The seven guides bury this trade, and the project states it plainly in its own limiter source.

Start from what SearXNG is. It runs no index of its own. Every search you type is forwarded to real engines — Google, Bing, Wikipedia, whichever you have enabled — and what comes back is merged and handed to you with no account attached and nothing logged. The privacy win is that the engines see a server rather than you.

The cost is in the same sentence. A public instance spreads those forwarded queries across thousands of users; your instance is one IP address making every single query. From Google’s side that pattern is a bot, and the project’s documentation says so directly — SearXNG passes through requests and is “thus classified as a bot itself”, after which the engine returns a CAPTCHA or blocks it some other way.

When that happens SearXNG does the polite thing and stops asking for a while. How long is set by the defaults in its own settings file, and the spread is the part worth memorising:

What the engine did How long SearXNG stops using it
Access denied, or HTTP 402 / 403 3 minutes
Too many requests, or HTTP 429 3 minutes
A generic CAPTCHA 1 hour
A Cloudflare access denial 1 day
A reCAPTCHA 7 days
A Cloudflare CAPTCHA 15 days

Read the bottom two rows again. One bad afternoon can take an engine out of your rotation for a fortnight, and nothing on the results page tells you that is what happened — you get fewer results and no explanation. They are defaults rather than laws, and they live in search.suspended_times, but shortening them means going back sooner to something that just refused you.

None of that is a reason to skip SearXNG. It is a reason to know what you are looking at. The instance is doing what a well-behaved client should. If results get thin, check the preferences page for which engines are currently suspended before you start rewriting configuration.

The honest consequence: a private instance is more private than a public one and, at times, worse at searching. A public instance hides you in a crowd but the crowd sees your queries. That is the actual decision, and it is not the one the setup guides frame.

What Does the Stack Actually Look Like?

Two services, and the project publishes the compose file itself:

services:
  core:
    image: docker.io/searxng/searxng:2026.9.23-3cd69d30e
    restart: always
    ports:
      - "8080:8080"
    volumes:
      - ./core-config/:/etc/searxng/:Z
      - core-data:/var/cache/searxng/

  valkey:
    image: docker.io/valkey/valkey:9-alpine
    command: valkey-server --save 30 1 --loglevel warning
    restart: always
    volumes:
      - valkey-data:/data/

volumes:
  core-data:
  valkey-data:

The broker is Valkey rather than Redis, the fork that followed Redis’ licence change — the same swap Paperless-ngx made. If you are new to reading one of these files, the Docker workflow for self-hosting covers what each block does.

The two volumes on the search container do different jobs and only one of them is yours. core-config is where your settings.yml lives, which is the file you will actually edit and the only thing here worth backing up. core-data is a cache the application rebuilds, so losing it costs you nothing but a slow first few searches. The web interface answers on port 8080, and the project’s template lets you move that with an environment variable rather than by editing the compose file.

I pinned a dated tag above where the project’s template reads ${SEARXNG_VERSION:-latest}, and the reason is the release cadence. SearXNG publishes continuously: counting the tags on Docker Hub on 24 September 2026, 87 images were tagged in September alone, across 22 separate days. Running latest here means a different build most weeks. The tag I pinned is the exact commit this post was written from. The image index lists linux/amd64, linux/arm64 and linux/arm/v7, so a 64-bit Pi is fine and a Pi Zero is not.

Does SearXNG Actually Use That Valkey Container?

Not until you tell it to, and most people never do.

Take this away from the compose file above. It starts Valkey, and SearXNG’s shipped defaults do not connect to it: server.limiter is false and valkey.url is false in the project’s own settings, and the container sets no URL for you. So out of the box you are running a database that the application never opens.

That is not a bug. Valkey is there for the limiter, which is bot protection — it tracks request behaviour per IP so that other people’s bots cannot ride your instance into a ban. Whether you need it follows directly from who can reach the thing:

✅ Turn the limiter on

  • The instance has a public URL
  • Anyone outside your household can load it
  • You want the engine suspensions above to be someone else's fault less often

❌ Leave it off

  • It only answers on your LAN or a private network
  • Every user is you and three people you know
  • You would rather not debug client IP handling

If you do turn it on, set limiter: true and the Valkey URL in core-config/settings.yml together. One without the other does nothing useful.

Secret Key and Base URL: What Must You Actually Set?

Less than the guides say, and one of the two variables they name does not exist.

The secret key looks after itself in the container. On first start, the entrypoint copies a settings template into your config volume and replaces the placeholder string with 24 random bytes it generates on the spot. A fresh container does not run on the shared default. The advice to set it by hand comes from the bare-metal install, where nothing does that for you.

The variable name in most guides is wrong. Searching the whole repository on 24 September 2026 returns no SEARXNG_SECRET_KEY at all. The environment variable that exists is SEARXNG_SECRET, and it overrides server.secret_key. Copying a three-year-old blog snippet gets you a variable the application ignores in silence.

SEARXNG_BASE_URL is real and does matter. It defaults to false, and it is what SearXNG uses to build correct absolute links back to itself. Leave it unset behind a proxy and the links it generates point at the wrong place. This is the one setting to fill in before you put a domain in front of it.

Behind a Reverse Proxy, or Only on Your Own Network?

Either, but a proxy changes what the limiter can see, so decide before you turn it on.

The limiter works from the client IP, and behind a proxy it reads that from the X-Forwarded-For header. The project’s own documentation calls a correct setup of X-Forwarded-For and X-Real-IP essential for assigning a request to an IP at all. Get it wrong and every request appears to come from your proxy, which means the limiter either blocks everyone or nobody. The mechanics of setting those headers are in the guide to running a reverse proxy with Nginx Proxy Manager.

If the instance is only for you, the simpler answer is not to publish it at all. A private mesh network like Tailscale gives you a stable address without anything facing the internet, and with no public URL the limiter question mostly evaporates. A Cloudflare Tunnel is workable here too — a search page is text, so it does not run into the large-file terms that rule tunnels out for media — though it does mean Cloudflare sees every query, which sits oddly with why you built this.

A different job from Pi-hole. Blocking trackers at the DNS layer, which is what Pi-hole does, stops your devices talking to ad networks. It does nothing about the search engine itself knowing what you asked. SearXNG is the other half of that, and running both is the normal arrangement rather than a redundant one.

How Do You Make It the Browser’s Default?

Visit it once, then add it in your browser’s search settings — SearXNG does the hard part for you.

Every page it serves carries an OpenSearch description document, which is the standard mechanism a browser uses to discover a site’s search endpoint. After one visit, Firefox and Chromium-family browsers will offer your instance in the list of search engines you can add, and from there it becomes the address bar’s default.

That step sounds trivial and it is the one that decides the whole project. An instance you have to navigate to first gets used for the searches you remember to be private about, which is not many. An instance wired into the address bar gets used for everything, which is the point. Do it on the phone too; the same mechanism works there.

Should You Run It?

Not if you want search that never has an off day. The engine suspensions above are real, they are invisible from the results page, and if you are the sort of person who will blame the tool, this will annoy you monthly. Use a reputable public instance instead — you give up per-query privacy from the operator and get better uptime.

Run it if you would rather the engines not build a profile of you, and you can tolerate occasionally thinner results. It is two containers, one of which you may not need, and it replaces a service you are otherwise paying for with your query history — the same trade as every other entry in the list of self-hosted apps that replace subscriptions, except the currency is data rather than money.

Frequently Asked Questions About SearXNG

Why does SearXNG say no results from some engines?

Because that engine has blocked or challenged your instance, and SearXNG has suspended it for a while rather than hammering it. A private instance is one IP address making every search, which looks like a bot, and SearXNG’s own limiter documentation says the project is classified as a bot for exactly that reason. The suspensions are short for a plain rate-limit and very long for a CAPTCHA.

How long does SearXNG stop using a blocked engine?

It depends which wall it hit, and the range is enormous. Read from the project’s default settings on 24 September 2026: three minutes for an access-denied or too-many-requests response, one hour for a generic CAPTCHA, seven days for a reCAPTCHA, one day for a Cloudflare access denial, and fifteen days for a Cloudflare CAPTCHA. Those are defaults you can change, not fixed limits.

Does SearXNG need the Valkey container?

Not to return search results, and this surprises people who copy the project’s compose file. That file starts Valkey, but the shipped defaults leave both the limiter and the database URL switched off, so nothing connects the two until you wire them up yourself. Valkey exists for the bot-protection limiter, which matters when your instance is reachable by strangers and does nothing when it is not.

Do I still have to set a SearXNG secret key?

Not in the container, and the variable most guides name no longer exists. On first start the entrypoint copies a settings template and replaces the placeholder key with random bytes it generates, so a fresh container never runs on the shared default. Searching the project source on 24 September 2026 finds no SEARXNG_SECRET_KEY anywhere; the variable that does exist is called SEARXNG_SECRET.

Can SearXNG replace Google for everyday searching?

For most queries, yes, provided you make it the browser default and accept the trade. It carries an OpenSearch description on every page, so a browser can add it as a search engine after one visit. The trade is that results are aggregated from engines that may be blocking you at any given moment, so a bad answer is sometimes your instance being throttled rather than the web being empty.

Product links on this site are plain links. We earn nothing from them — see our disclosure policy.