SearXNG + Tor in Docker: Your Own Private Search Engine

A step-by-step guide to deploying SearXNG in Docker with Tor integration and Caddy HTTPS reverse proxy. Private, self-hosted search that aggregates 40+ engines without leaking your queries.

SearXNG + Tor in Docker: Your Own Private Search Engine

Every search you type into Google, Bing, or DuckDuckGo gets logged, profiled, and sold. Your search history is a detailed map of your thoughts, fears, medical concerns, financial worries, and political leanings.

SearXNG fixes this. It’s an open-source metasearch engine that queries 40+ search engines on your behalf — without sending your identity along for the ride. Add Tor routing and you’ve got a search engine that doesn’t even reveal your IP to the engines it queries.

This guide gets you from zero to running in about fifteen minutes.


What You’re Building

Browser ──HTTPS:443──► Caddy ──HTTP:8080──► SearXNG (Docker)
                                                │
                                          SOCKS5:9050
                                                │
                                           Tor (systemd)
  • SearXNG aggregates results from Google, Bing, DuckDuckGo, Brave, and dozens more
  • Tor anonymises outgoing queries so search engines can’t see your IP
  • Caddy encrypts browser-to-server traffic with HTTPS (even on a LAN, encrypted is better)
  • Docker keeps everything contained and easy to update

Prerequisites

  • A Linux box (Raspberry Pi, old laptop, VM — anything with Docker)
  • Docker installed (sudo apt install docker.io or official docs)
  • Root/sudo access
  • 512MB RAM minimum (1GB+ recommended)

Step 1: Install and Configure Tor

sudo apt update && sudo apt install -y tor

Edit /etc/tor/torrc and add:

SocksPort 0.0.0.0:9050

Start it:

sudo systemctl enable --now tor

Verify Tor works:

curl -x socks5h://127.0.0.1:9050 https://check.torproject.org 2>&1 | grep -i congratulations

You should see: “Congratulations. This browser is configured to use Tor.”


Step 2: Configure SearXNG

Create the config directory and settings file:

sudo mkdir -p /etc/searxng

Generate a secret key:

python3 -c "import secrets; print(secrets.token_hex(32))"

Create /etc/searxng/settings.yml:

use_default_settings: true

general:
  instance_name: "SearXNG Local"
  enable_metrics: true

server:
  secret_key: "PASTE_YOUR_GENERATED_KEY_HERE"
  limiter: false
  image_proxy: true
  bind_address: "0.0.0.0:8080"

search:
  safe_search: 0
  default_lang: en
  formats:
    - html
    - json

ui:
  default_theme: simple
  theme_args:
    simple_style: light

outgoing:
  request_timeout: 15
  max_request_timeout: 25
  proxies:
    http: socks5h://127.0.0.1:9050
    https: socks5h://127.0.0.1:9050

engines:
  - name: google
    disabled: false
  - name: bing
    disabled: false
  - name: duckduckgo
    disabled: false
  - name: brave
    disabled: false
  - name: startpage
    disabled: false
  - name: wikipedia
    disabled: false
  - name: google news
    disabled: false
  - name: bing news
    disabled: false
  - name: duckduckgo news
    disabled: false
  - name: github
    disabled: false
  - name: stackoverflow
    disabled: false
  - name: arxiv
    disabled: false
  - name: reddit
    disabled: false

The proxies block under outgoing routes all search queries through Tor. Remove it if you prefer direct queries (e.g., when your network already uses a VPN).

Timeout note: Tor adds latency. The 15/25 second timeouts accommodate this. Without Tor, 10/20 is fine.


Step 3: Launch SearXNG

docker run -d \
  --name searxng \
  --network host \
  --restart unless-stopped \
  -v /etc/searxng:/etc/searxng \
  searxng/searxng:latest

Why --network host? SearXNG needs to reach Tor’s SOCKS proxy at 127.0.0.1:9050. Host networking makes this seamless — no Docker bridge routing needed.

Verify it’s running:

curl -s 'http://localhost:8080/search?q=test&format=json' | python3 -m json.tool | head -20

You should see JSON search results. Open http://YOUR_HOST_IP:8080 in a browser for the web interface.


Even on a private network, encrypting traffic is good practice. Caddy makes this trivial with automatic self-signed certificates.

Install Caddy:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy

Edit /etc/caddy/Caddyfile:

http://YOUR_HOST_IP {
    redir https://{host}{uri} permanent
}

https://YOUR_HOST_IP {
    tls internal
    reverse_proxy localhost:8080
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "no-referrer"
    }
}

Replace YOUR_HOST_IP with the machine’s LAN IP (e.g., 10.0.0.50).

tls internal generates a self-signed certificate — public CAs like Let’s Encrypt won’t issue certs for private IPs.

caddy validate --config /etc/caddy/Caddyfile
sudo systemctl restart caddy

To avoid browser warnings, trust the self-signed CA system-wide:

sudo cp /var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt \
    /usr/local/share/ca-certificates/caddy-local-ca.crt
sudo update-ca-certificates

For browser trust, import the same root.crt file into your browser’s certificate authorities (Firefox: Settings → Privacy → Certificates → Import).


Step 5: Verify the Full Stack

# HTTP direct
curl -s 'http://localhost:8080/search?q=privacy&format=json' \
  | python3 -c "import sys,json; r=json.load(sys.stdin); print(f'{len(r.get(\"results\",[]))} results')"

# HTTPS through Caddy
curl -s 'https://YOUR_HOST_IP/search?q=privacy&format=json' \
  | python3 -c "import sys,json; r=json.load(sys.stdin); print(f'{len(r.get(\"results\",[]))} results')"

# Tor verification
docker exec searxng curl -x socks5h://127.0.0.1:9050 \
  https://check.torproject.org 2>&1 | grep -i congratulations

All three should succeed. You now have a private, Tor-routed, HTTPS-encrypted search engine running on your own hardware.


Maintenance

# View logs
docker logs searxng --tail 50

# Restart after settings change
docker restart searxng

# Update SearXNG
docker pull searxng/searxng:latest
docker stop searxng && docker rm searxng
# Re-run the docker run command from Step 3

# Check Tor status
sudo systemctl status tor

Optional: JSON API for Automation

With json in the formats list, SearXNG doubles as a search API:

curl -s 'http://localhost:8080/search?q=linux+hardening&format=json' | jq '.results[:3]'

This is useful for feeding search results into scripts, monitoring tools, or AI pipelines — all without touching a commercial API or leaking your queries.


What You’ve Gained

Before After
Google logs every search Your queries stay on your hardware
One engine’s bias 40+ engines aggregated
Your IP visible to search engines Tor hides your origin
HTTP on LAN HTTPS encrypted
Dependent on external services Self-hosted, yours to control

Your search history is nobody’s business but yours.


Search is thinking out loud. Keep your thoughts private.

AI disclosure

This article predates the formal AI disclosure regime introduced on 19 May 2026. AI tools were used to polish and generate some text in this article. Editorial responsibility: Thomas A. Kleppestø.

Get the next guide

New privacy and security guides, plus the occasional investigation. No tracking, no spam, unsubscribe any time by replying. We never share your address.

Prefer not to sign up? Just email a tip or a correction to HAL0zum@proton.me, or use our PGP key for sensitive material.