Deployment guide

SearXNG on a VPS: private metasearch for devs and AI agents

Deploy on a VPS Cloud →

Tutorial

Self-hosting

SearXNG on a VPS: private metasearch for devs and AI agents

Every web search you send to Google leaves a trace. Every API call to a commercial Search API adds to your bill. SearXNG solves both problems at once: a self-hosted metasearch engine that queries 280+ upstream engines and returns merged results — on your VPS, under your control, at zero per-query cost.

10 min read8 steps
Contents· The problem: why commercial search APIs are not the answer1/11
  1. 01The problem: why commercial search APIs are not the answer
  2. 02What SearXNG provides out of the box
  3. 03Architecture: two containers, under 512 MB RAM
  4. 04Self-hosting SearXNG on a VPS: step by step
  5. 05Advanced SearXNG configuration
  6. 06Using SearXNG as a search source for AI agents
  7. 07Securing and optimising your instance
  8. 08SearXNG vs alternatives: which self-hosted search engine to choose?
  9. 09Restrict access on public instances
  10. 10Troubleshooting: 4 common errors
  11. 11SearXNG as the search backbone for your AI stack

The problem: why commercial search APIs are not the answer

Building an AI agent that needs to search the web? Your options are: pay Google $5 per 1,000 queries, hit Bing's API rate limits, or use DuckDuckGo's unofficial API that breaks without notice. None of these give you full control, and all of them send your queries — and your users' queries — to third-party servers.

For development teams in Morocco and the MENA region, there's an additional friction: regional blocks, censorship, and the fact that results from a US-centric engine are often irrelevant to local searches. A self-hosted metasearch engine sidesteps all of this.

What SearXNG provides out of the box

  • 280+ upstream engines — Google, Bing, DuckDuckGo, Brave, Wikipedia, Reddit, GitHub, arXiv, YouTube, Twitter/X and hundreds more queried simultaneously.
  • Zero tracking — no cookies, no user profiling, no search history stored. Privacy by architecture: the engine sends queries to upstream services, not you.
  • JSON API — add ?format=json to any query and get machine-readable results. Natively supported by Open WebUI, n8n, Flowise, LangChain and CrewAI.
  • Redis caching — shared result cache reduces upstream load; rate-limiting prevents abuse on public instances.
  • AGPL-3.0 — 33 k+ GitHub stars, rolling releases, Docker image updated weekly.

Architecture: two containers, under 512 MB RAM

SearXNG runs as two Docker containers: the Python engine itself (under 256 MB RAM) and a Redis instance (~30 MB) for caching and rate-limiting. No database, no persistent state beyond the Redis cache. With 1 GB of RAM, SearXNG leaves plenty of room for Nginx and the OS — a 2 GB VPS is comfortable for teams with multiple concurrent users or heavy AI agent traffic.

Self-hosting SearXNG on a VPS: step by step

  1. Order a VPS

    Choose a ServOrbit Cloud VPS with at least 1 GB RAM (Ubuntu 22.04). The provisioner handles Docker and Docker Compose installation automatically.

  2. Create the docker-compose.yml file

    Create a directory /opt/searxng and place this docker-compose.yml file in it:

    services:
      redis:
        image: redis:7-alpine
        restart: unless-stopped
        command: redis-server --save "" --appendonly no
        volumes:
          - redis-data:/data
      searxng:
        image: searxng/searxng:latest
        restart: unless-stopped
        ports:
          - "127.0.0.1:8080:8080"
        volumes:
          - ./settings:/etc/searxng:rw
        environment:
          - SEARXNG_BASE_URL=https://search.yourdomain.com/
          - SEARXNG_SECRET_KEY=CHANGE_THIS_32_CHAR_SECRET_MIN
        depends_on:
          - redis
        cap_drop:
          - ALL
        cap_add:
          - CHOWN
          - SETGID
          - SETUID
          - DAC_OVERRIDE
    volumes:
      redis-data:

    Generate a strong secret key with openssl rand -hex 32 and replace CHANGE_THIS_32_CHAR_SECRET_MIN.

  3. Configure settings.yml

    Create the ./settings directory and copy the default configuration file:

    mkdir -p /opt/searxng/settings
    docker run --rm searxng/searxng:latest cat /etc/searxng/settings.yml \
      > /opt/searxng/settings/settings.yml

    Open settings.yml and adjust the key settings:

    general:
      instance_name: "My SearXNG"
      debug: false
    
    search:
      safe_search: 0
      autocomplete: ""
      formats:
        - html
        - json
    
    server:
      limiter: true
      image_proxy: false
      http_protocol_version: "1.1"
    
    redis:
      url: redis://redis:6379/0

    The redis: block points to the Redis container by its service name.

  4. Configure Nginx as a reverse proxy with TLS

    Install Nginx and Certbot, then create /etc/nginx/sites-available/searxng:

    server {
        listen 80;
        server_name search.yourdomain.com;
        return 301 https://$host$request_uri;
    }
    server {
        listen 443 ssl;
        server_name search.yourdomain.com;
        ssl_certificate     /etc/letsencrypt/live/search.yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/search.yourdomain.com/privkey.pem;
        ssl_protocols       TLSv1.2 TLSv1.3;
        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;
        }
    }

    Enable the site and get the certificate: certbot --nginx -d search.yourdomain.com && ln -s /etc/nginx/sites-available/searxng /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx.

  5. Start the containers

    From /opt/searxng, run docker compose up -d. Check that both containers are Up with docker compose ps. View engine logs with docker compose logs -f searxng.

  6. Enable JSON API and test

    The JSON API is already enabled if you added json to the formats list in settings.yml. Test from the VPS:

    curl -s 'https://search.yourdomain.com/search?q=SearXNG+self+hosted&format=json' \
      | jq '.results[0] | {title, url, content}'

    You should get a JSON object with title, url and content. If the API returns 403, verify that formats contains json and restart the container.

  7. Enable the bot rate limiter

    The built-in limiter (Redis-backed) blocks clients sending too many requests. Enable it via limiter: true in settings.yml. To reinforce protection at the Nginx level, add inside the server block:

    limit_req_zone $binary_remote_addr zone=searxng:10m rate=10r/m;
    # inside location / :
    limit_req zone=searxng burst=5 nodelay;

    This limits each IP to 10 requests per minute with a burst tolerance of 5.

  8. Connect Open WebUI or n8n

    In Open WebUI: Settings → Web Search → Provider: SearXNG → URL: https://search.yourdomain.com. In n8n: HTTP Request node → GET https://search.yourdomain.com/search?format=json, passing your query in the q parameter. Your AI agents now have live, unfiltered, private web search.

Advanced SearXNG configuration

Beyond the basic settings, settings.yml exposes options that turn SearXNG into a tool tailored for your use case.

Enable or disable engines: under the engines: key, each engine has a disabled: true field to turn it off. Disable slow or geo-blocked engines to speed up responses. For example, to keep only Google, Bing, Brave and Wikipedia for general searches:

engines:
  - name: google
    disabled: false
  - name: bing
    disabled: false
  - name: brave
    disabled: false
  - name: duckduckgo
    disabled: true

JSON response format for AI agents: JSON results contain results[].title, results[].url, results[].content (snippet), results[].engine and results[].score. Pass &categories=general,news to filter by category, or &language=en to target a language.

SafeSearch: the safe_search key accepts 0 (off), 1 (moderate) or 2 (strict). For AI agents indexing professional content, 0 returns the broadest results.

Languages and regions: add &language=ar-MA to get Moroccan Arabic results, or &language=fr-FR for French. The full list of language codes is available in the SearXNG GitHub source (file searx/languages.py).

Using SearXNG as a search source for AI agents

The /search?q=...&format=json endpoint is the universal entry point for all AI agent frameworks. Here is how to integrate it in the three most common environments.

n8n: create an *HTTP Request* node with method GET, URL https://search.yourdomain.com/search, with parameters q (query expression), format = json and optionally categories = general. A following *Code* node can extract $json.results.slice(0,5).map(r => r.url + ' — ' + r.content) to feed your LLM.

LangChain (Python): the LangChain community package includes a SearxSearchWrapper tool since version 0.1:

from langchain_community.utilities import SearxSearchWrapper

search = SearxSearchWrapper(
    searx_host="https://search.yourdomain.com",
    k=5
)
results = search.results("open source AI news", num_results=5)

Open WebUI: once the URL is configured in Settings, each conversation can activate web search via the dedicated icon. Open WebUI queries SearXNG, injects snippets into the model context and automatically cites sources. No API key required.

Raw curl for shell scripts or minimal agents:

curl -s "https://search.yourdomain.com/search?q=searxng+api+json&format=json" \
  | jq '[.results[:3] | .[] | {title, url, content}]'

The result is a JSON array directly injectable into a prompt.

Securing and optimising your instance

An open SearXNG instance quickly attracts crawlers and scrapers. Here are the four levers to activate.

Redis rate limit: with limiter: true in settings.yml, Redis counts requests per IP over a sliding window. The default threshold is conservative; you can tune it in searxng/limiter.toml in recent versions of the Docker image.

HTTP Basic Auth: for an instance reserved for your team or AI agents, add inside the Nginx location / block:

auth_basic "Private SearXNG";
auth_basic_user_file /etc/nginx/.htpasswd;

Generate the file with htpasswd -c /etc/nginx/.htpasswd user. AI agents pass credentials in the URL: https://user:[email protected]/search?....

Redis cache and TTL: Redis is configured by default without persistence (--save "") to avoid disk accumulation. To adjust the SearXNG cache TTL, modify the cache: key in settings.yml — for example cache: {ttl: 86400} to keep results for 24 hours and reduce calls to upstream engines.

User-Agent rotation: SearXNG automatically rotates User-Agents to avoid bans by upstream engines. If an engine starts returning CAPTCHAs, temporarily disable it with disabled: true in settings.yml and re-enable it after a few hours.

SearXNG vs alternatives: which self-hosted search engine to choose?

Scroll the table

CriterionSearXNGSearx (original)WhoogleBrave Search API
Aggregated sources280+ engines100+ enginesGoogle onlyBrave only
Native JSON APIYes (`?format=json`)YesNoYes (key required)
Minimum RAM~300 MB (with Redis)~200 MB~128 MBZero (SaaS)
Active maintenanceYes (2026)Abandoned (archived)Yes (2026)Yes (SaaS)
Cost per queryZeroZeroZero$3 / 1,000 queries

Restrict access on public instances

If your SearXNG instance is publicly reachable, add HTTP Basic Auth in Nginx or set limiter: true in settings.yml (Redis is required for the limiter). For AI-agent-only use, you can disable the HTML interface entirely and only expose the JSON endpoint — edit formats to remove html and restrict direct browser access.

Troubleshooting: 4 common errors

1. 429 Too Many Requests — upstream engine ban: Google or Bing has detected abnormal volume and temporarily banned your VPS IP. Symptom: SearXNG returns results from all engines except one, or the JSON response includes 'is_onion': false but no Google results. Immediate fix: disable the affected engine in settings.yml (disabled: true) and wait 2–6 hours. Long term: enable multiple redundant engines so a single ban doesn't empty results.

2. Error: Connection refused to Redis (127.0.0.1:6379): the SearXNG container is trying to reach Redis on 127.0.0.1 instead of the service name redis. Cause: the SEARXNG_REDIS_URL variable or the redis.url key in settings.yml points to localhost instead of redis://redis:6379/0. Fix: check settings.yml — the key must be url: redis://redis:6379/0 (Docker Compose service name, not localhost).

3. 403 Forbidden on /search?format=json: the JSON API is disabled. Symptom: the HTML interface works but requests with &format=json return 403. Fix: open settings.yml, verify that formats: contains json, save, then restart the container with docker compose restart searxng.

4. Slow instance (> 5 s per query): too many engines enabled simultaneously or geo-blocked engines timing out. Diagnosis: check logs with docker compose logs searxng | grep 'timeout\|error'. Fix: reduce active engines to the 5–8 most relevant for your use case, and increase the global timeout in settings.yml (request_timeout: 3.0 in seconds).

SearXNG as the search backbone for your AI stack

SearXNG has become the de facto web search backend for self-hosted AI stacks in 2026. Open WebUI, n8n, Flowise, LangChain, CrewAI and most LLM orchestration frameworks have native SearXNG integration. The pattern is always the same: your LLM decides it needs current information, calls your SearXNG endpoint with a query, gets back a JSON array of results with titles, URLs and snippets, and uses those to ground its response.

This eliminates three pain points in one deployment: no per-query billing, no data leakage to Google or Bing, and no rate limit surprises at 2 AM when your agent is running a research batch.

Private search, on your own server

Deploy SearXNG on a ServOrbit VPS and give your team and AI agents a private, uncensored search endpoint — no tracking, no API keys, no per-query billing.