gtzhost logo

NORTH AMERICA

EUROPE

ASIA

How to Self-Host an AI Search Engine with Open WebUI + SearXNG

Public AI chat tools send every query you type to someone else's servers. If you want an AI assistant that can search the live web but keeps your queries private — and costs nothing per search — you can build one yourself with two open-source tools: Open WebUI as the chat interface and SearXNG as the search backend.

This guide walks through the full setup on a Linux server: installing both services with Docker, connecting them, and confirming web search actually works inside a chat.

What You're Building

  • Open WebUI — a self-hosted, ChatGPT-style interface that connects to local models (through Ollama) or cloud model APIs, and supports plugging in a web search provider.

  • SearXNG — a self-hosted metasearch engine. It doesn't run its own index; instead, it queries multiple public search engines, strips tracking, and returns aggregated results with no profiling of the user.

Together, they behave like a private version of an AI search assistant: your prompt goes to the model, the model (through Open WebUI) queries SearXNG for live results, and the response is generated from real, current web data — all without a third party seeing your search history.

Prerequisites

  • A Linux server (a small VPS is enough for CPU-based models; a GPU-equipped dedicated server is recommended if you're running larger local models through Ollama)

  • Docker and Docker Compose installed

  • Basic comfort with the command line

  • At least 4 GB RAM free for Open WebUI and SearXNG alone — more if you're also self-hosting a local LLM through Ollama

Step 1: Set Up SearXNG

Clone the official SearXNG Docker repository and move into it:

bash
git clone https://github.com/searxng/searxng-docker.git
cd searxng-docker

Open the .env file and set your hostname:

plaintext
SEARXNG_HOSTNAME=localhost

If SearXNG will only be reached internally by Open WebUI (recommended — don't expose it to the public internet), leave the hostname as localhost and skip the Let's Encrypt email setting.

Give the container permission to generate its own config files on first launch:

bash
sudo chmod a+rwx searxng

Start the container briefly so it generates a default settings.yml, then stop it:

bash
docker compose up -d
sleep 10
docker compose down

Enable JSON Output

By default, SearXNG only returns HTML results, which Open WebUI can't parse. Open searxng/settings.yml, find the search section, and add json under formats:

yaml
search:
  formats:
    - html
    - json

Without this step, Open WebUI's requests will be rejected with a 403 Forbidden error — this is the single most common thing people miss in this setup.

Step 2: Set Up Open WebUI

If you're pairing this with a local model through Ollama, the simplest path is a single Docker Compose file that runs all three services on the same network. Create a docker-compose.yaml:

yaml
version: "3.8"

networks:
  ai-net:
    driver: bridge

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    networks:
      - ai-net
    volumes:
      - ./ollama:/root/.ollama

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    restart: unless-stopped
    networks:
      - ai-net
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
      - ENABLE_WEB_SEARCH=True
      - WEB_SEARCH_ENGINE=searxng
      - WEB_SEARCH_RESULT_COUNT=5
      - WEB_SEARCH_CONCURRENT_REQUESTS=10
      - SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>
    volumes:
      - open-webui:/app/backend/data

  searxng:
    image: docker.io/searxng/searxng:latest
    container_name: searxng
    restart: unless-stopped
    networks:
      - ai-net
    ports:
      - "8080:8080"
    volumes:
      - ./searxng:/etc/searxng:rw
    environment:
      - SEARXNG_BASE_URL=http://localhost:8080/

volumes:
  open-webui:

Bring the whole stack up:

bash
docker compose up -d

Prefer to run Open WebUI on its own without Compose? The standalone install command is:

bash
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway \
  -v open-webui:/app/backend/data --name open-webui --restart always \
  ghcr.io/open-webui/open-webui:main

In that case, connect it to SearXNG manually in the admin settings (Step 4 below) instead of through environment variables.

Step 3: Confirm the Containers Can Talk to Each Other

Before touching the UI, verify Open WebUI can actually reach SearXNG over the internal Docker network:

bash
docker exec -it open-webui curl "http://searxng:8080/search?q=test&format=json"

If this returns a JSON blob full of search results, the connection is working. If you get a 403 or a connection refused error, double-check the JSON format setting from Step 1 and confirm both containers are on the same Docker network.

Step 4: Configure Web Search in the Open WebUI Admin Panel

Even with the environment variables set, it's worth confirming (or setting) this through the UI:

  1. Open http://your-server-ip:3000 and log in.

  2. Go to Settings > Admin > Tools > Web Search.

  3. Toggle Enable Web Search on.

  4. Set Web Search Engine to searxng.

  5. Set Searxng Query URL to http://searxng:8080/search?q=<query> — the /search?q=<query> part is required exactly as written.

  6. Adjust Search Result Count and Concurrent Requests if you want more or fewer sources per query.

  7. Save.

Step 5: Test It in a Chat

Open a new chat, click the integrations icon next to the message box, and toggle Web Search on for that conversation. Ask something time-sensitive — a current event, a recent product release, today's date-specific question. If the response cites live sources instead of relying purely on the model's training data, the integration is working end to end.

Note that this toggle is per-session: it resets when you reload the page or switch chats, so you'll need to re-enable it for each new conversation where you want live search.

Security Notes Before You Go Further

  • Never expose SearXNG directly to the public internet. It has no built-in authentication, and an open instance can be abused as an anonymous scraping proxy. Keep it on the internal Docker network only, reachable exclusively by Open WebUI.

  • Put Open WebUI behind HTTPS if you're accessing it remotely. A reverse proxy like Nginx or Caddy with a Let's Encrypt certificate is the standard approach — never leave port 3000 open to the internet without TLS.

  • Re-apply cap_drop: - ALL to the SearXNG service in your Compose file after the first successful run. It's needed off during the initial config generation, but should be restored afterward to reduce the container's privileges.

Troubleshooting

  • 403 Client Error: Forbidden in Open WebUI logs: SearXNG isn't serving JSON. Add json to formats in settings.yml and restart.

  • Web search toggle does nothing: Containers are likely on different Docker networks. Confirm both are under the same networks: entry.

  • Empty search results: Query URL is missing ?q=<query>. Fix the SEARXNG_QUERY_URL value exactly.

  • Search works but responses are slow: Too many concurrent requests for your CPU/RAM. Lower WEB_SEARCH_CONCURRENT_REQUESTS and WEB_SEARCH_RESULT_COUNT.

Frequently Asked Questions (FAQ)

Q: Do I need a GPU for this setup?

A: No. SearXNG and Open WebUI's interface don't need one. A GPU only matters if you're also running a large local model through Ollama — for smaller models or cloud API connections, a CPU-only VPS is enough.

Q: Is SearXNG actually indexing the web itself?

A: No. It aggregates results from existing public search engines and returns them without tracking or profiling the user, which is what keeps it lightweight to self-host.

Q: Can I use this with a cloud model like GPT or Claude instead of a local one?

A: Yes. Open WebUI supports OpenAI-compatible API connections alongside or instead of Ollama — you'd add your API key as an environment variable and skip the Ollama container entirely if you don't need local inference.

Q: Does this replace my need for a dedicated server?

A: For a single-user setup, a modest VPS handles this comfortably. If you're running larger local models, serving multiple users, or want GPU-accelerated inference, moving the stack to a dedicated server with a GPU becomes worth it once VPS resource limits start slowing down response times.