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:
- YouTube → Invidious
- Reddit → Teddit or Libreddit
- Twitter → Nitter
- Instagram → Bibliogram
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
- Navigate to your SearXNG instance
- Right-click the address bar → “Add Search Engine”
- 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
- Privacy Focused Search Engines Comparison 2026
- Best Privacy-Focused Search Engines Comparison 2026
- Right To Be Forgotten In Search Engines How To Request
- How to Disable Google AMP Tracking in Search Results Guide
- Facial Recognition Search Opt Out How To Remove Your Face
- AI Coding Assistant Session Data Lifecycle Built by theluckystrike — More at zovo.one