Last updated: March 22, 2026

How to Self-Host a Privacy Search Engine

Every search query to Google, Bing, or DuckDuckGo is logged, profiled, and used to build a behavioral record. Self-hosting a meta search engine means your queries pass through your server to multiple search backends. no account, no persistent profile, no tracking cookie. This guide covers SearXNG and Whoogle, the two strongest self-hosted options.

SearXNG vs Whoogle

Feature SearXNG Whoogle
Source Meta search (20+ engines) Google proxy
Results quality Broad, configurable Google-quality
Setup complexity Moderate Simple
Customizable engines Yes (per-query) No
Images, videos, news Yes Yes
JavaScript required Yes Optional
Resource usage ~200MB RAM ~100MB RAM

SearXNG queries Bing, DuckDuckGo, Startpage, Wikipedia, and others simultaneously and merges results. Whoogle proxies Google, so results match Google exactly. without tracking.

Option 1 - SearXNG with Docker

/opt/searxng/docker-compose.yml
version: '3.8'

services:
  searxng:
    image: searxng/searxng:latest
    restart: always
    ports:
      - 127.0.0.1:8080:8080
    volumes:
      - ./searxng:/etc/searxng:rw
    environment:
      - SEARXNG_BASE_URL=https://search.yourdomain.com/
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"

  redis:
    image: redis:alpine
    restart: always
    command: redis-server --save "" --appendonly "no"
    cap_drop:
      - ALL
    cap_add:
      - SETGID
      - SETUID
      - DAC_OVERRIDE
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"
mkdir -p /opt/searxng/searxng
cd /opt/searxng

Generate a secret key
docker compose run --rm searxng sh -c "openssl rand -hex 32 > /etc/searxng/secret_key" 2>/dev/null

Create initial settings file
cat > searxng/settings.yml << 'EOF'
use_default_settings: true

server:
  secret_key: !include secret_key
  limiter: true
  image_proxy: true
  method: GET

search:
  safe_search: 0
  autocomplete: ""
  default_lang: "en"

ui:
  static_use_hash: true
  default_locale: "en"
  query_in_title: false
  infinite_scroll: true
  center_alignment: false
  results_on_new_tab: false
  theme_args:
    simple_style: auto

Disable engines that break frequently or require accounts
engines:
  - name: google
    disabled: true   # use Google via Startpage to avoid blocks
  - name: startpage
    disabled: false
  - name: ddg definitions
    disabled: false
  - name: duckduckgo
    disabled: false
  - name: bing
    disabled: false
  - name: wikipedia
    disabled: false
  - name: github
    disabled: false
EOF

docker compose up -d

SearXNG Configuration Deep Dive

searxng/settings.yml. extended privacy configuration

server:
  secret_key: !include secret_key
  bind_address: "0.0.0.0"
  port: 8080
  limiter: true     # rate limit per IP. important for public instances
  public_instance: false  # set true if you allow public access

Outgoing requests. anonymize or route through Tor
outgoing:
  request_timeout: 3.0
  max_request_timeout: 10.0
  # Route requests through a proxy (optional)
  # proxies:
  #   http:  socks5://127.0.0.1:9050  # Tor
  #   https: socks5://127.0.0.1:9050

Privacy - do not log searches
general:
  debug: false
  donation_url: false
  contact_url: false
  enable_metrics: false  # disables the /stats page

Search result settings
search:
  safe_search: 0
  formats:
    - html
    - json    # enables the JSON API for scripts
    - csv
    - rss

Enabled engines with categories
engines:
  - name: duckduckgo
    engine: duckduckgo
    categories: [guides]
    disabled: false

  - name: startpage
    engine: startpage
    categories: general
    disabled: false
    timeout: 6.0

  - name: wikipedia
    engine: wikipedia
    categories: general
    language: en
    disabled: false

  - name: github
    engine: github
    categories: code
    disabled: false

Option 2 - Whoogle (Google Results, No Tracking)

Whoogle is simpler. it proxies Google results through your server, stripping ads, AMP links, and tracking parameters.

/opt/whoogle/docker-compose.yml
version: '3.8'

services:
  whoogle:
    image: benbusby/whoogle-search:latest
    restart: always
    ports:
      - 127.0.0.1:5000:5000
    environment:
      # Proxy outgoing requests through Tor (optional)
      # WHOOGLE_PROXY_LOC: socks5://127.0.0.1:9050
      # WHOOGLE_PROXY_TYPE: socks5

      WHOOGLE_CONFIG_COUNTRY: US
      WHOOGLE_CONFIG_LANGUAGE: lang_en
      WHOOGLE_CONFIG_SEARCH_LANGUAGE: lang_en
      WHOOGLE_CONFIG_SAFE: 0
      WHOOGLE_CONFIG_DARK: 1
      WHOOGLE_CONFIG_ALTS: 1    # replace YouTube/Twitter/Reddit with privacy frontends
      WHOOGLE_CONFIG_VIEW_IMAGE: 1
      WHOOGLE_CONFIG_GET_ONLY: 1
      WHOOGLE_CONFIG_URL: https://search.yourdomain.com/
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
cd /opt/whoogle && docker compose up -d

Whoogle replaces links to:

Nginx Reverse Proxy

/etc/nginx/sites-available/search
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;

    # If private instance. restrict to your IP ranges
    # allow 10.0.0.0/8;
    # allow 192.168.0.0/16;
    # deny all;

    # Rate limit search queries
    limit_req_zone $binary_remote_addr zone=search:10m rate=30r/m;
    limit_req zone=search burst=10 nodelay;

    location / {
        proxy_pass http://127.0.0.1:8080;   # SearXNG
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Remove identifying headers upstream
        proxy_set_header X-Real-IP "";
    }
}

Browser Integration

Set as Default Search Engine in Firefox

  1. Navigate to your SearXNG instance
  2. Right-click the address bar → “Add Search Engine”
  3. Go to about:preferences#search → set as default

Or add manually:

// In about:config (Firefox)
// browser.urlbar.suggest.searches = false (disable search suggestions sent to provider)

// Add as OpenSearch engine (SearXNG supports this automatically)
// Visit - https://search.yourdomain.com/
// Click the + icon in the address bar

Using the SearXNG JSON API

Query via API
curl "https://search.yourdomain.com/search?q=linux+security&format=json" \
  | jq '.results[:3] | .[] | {title, url, content}'

Script that searches and opens the first result
#!/bin/bash
QUERY="${*// /+}"
URL=$(curl -s "https://search.yourdomain.com/search?q=${QUERY}&format=json" \
  | jq -r '.results[0].url')
echo "Opening: $URL"
xdg-open "$URL"

Monitoring and Maintenance

Check for updates
cd /opt/searxng && docker compose pull && docker compose up -d

Check logs for errors
docker compose logs searxng --tail 50

Monitor container health
docker stats searxng

SearXNG - review which engines are returning results
Visit - https://search.yourdomain.com/stats
(disable metrics in settings if public instance)

Related Articles