ヘデラ hedera's notebook

How to Set Up a Completely Private Instance of SearXNG-Docker

A few months ago, I set up my own local SearXNG docker image and it’s honestly been one of the best decisions I’ve ever made for my machine. It’s a way to add a layer of privacy between you and all of the search engines you use. Not only can you avoid having a profile of you get built by companies who sell your data, but I find SearXNG also gives you a better user experience because it aggregates results from many different engines at once. It’s so much easier to find what you’re actually looking for when you use SearXNG.

Installing Docker

To get this to work, you must have docker installed. If you don’t, take care of that first before you complete any of the next steps.

On Arch Linux, it is as simple as running sudo pacman -Syu docker.

Installing SearXNG-Docker

All of these next steps are also available on the readme at searxng-docker’s github repo.

To get searxng-docker on our machine, clone the git repo to /usr/local and navigate there.

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

Generate the secret key with the following command, so you have a secret key in your settings.yml. You just have to run it, no need to edit the actual settings.yml file.

sed -i "s|ultrasecretkey|$(openssl rand -hex 32)|g" searxng/settings.yml

Now just run docker compose up -d and you should be able to see your SearXNG instance at http://localhost:8080.

Configuring the SearXNG Instance For Use With HTTPS

Setting http://localhost:8080 to be the default search engine in Firefox doesn’t work. Firefox seems to correctly identify SearXNG’s OpenSearch plugin, but searches cannot be completed with the address bar or through other interfaces except directly through the search bar while you are already on the page http://localhost:8080. It seems that Firefox doesn’t allow such pages to be implemented as a search engine. To fix this, we must serve SearXNG over HTTPS.

Install and Setting Up mkcert

mkcert is a tool for making locally-trusted development certificates. I can install it via pacman with sudo pacman -Syu mkcert.

For install instructions on other platforms, you should see the readme at mkcert’s github repo.

Then run mkcert -install to set up a local certificate authority.

Generating Certs to Use with SearXNG

If you aren’t already in /usr/local/searxng-docker, cd there and then run

mkcert localhost

mkcert should then give you two files called localhost.pem and localhost-key.pem. Put these two files in /usr/local/searxng-docker/certs (you will have to create this directory). DO NOT share these keys. Keep them private.

You do not actually have to name the certificate “localhost.” If you want to use a fake domain name like “mysearch.test” you can do this by editing /etc/hosts and adding the line

127.0.0.1 mysearch.test

Configuring Caddyfile

Now open your Caddyfile. Add these four lines of code below the first block:

https://localhost {
	tls /certs/localhost.pem /certs/localhost-key.pem
	reverse_proxy searxng:8080
}

Make sure the tls line points to the location of the .pem files you just generated.

Then replace

# SearXNG
reverse_proxy localhost:8080

with

# SearXNG
reverse_proxy searxng:8080

Configuring docker-compose.yaml

Now open your docker-compose.yaml. Replace the entire caddy: block with this

  caddy:
    container_name: caddy
    image: docker.io/library/caddy:2-alpine
    depends_on:
      - searxng
    restart: unless-stopped
    networks:
      - searxng # <-- Attach to searxng
    ports:
      - "127.0.0.1:443:443" # <-- Map localhost port 443 to container port 443
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./certs:/certs:ro  # <-- Your mkcert certs go here
      - caddy-data:/data:rw
      - caddy-config:/config:rw
    environment:
      - SEARXNG_HOSTNAME=${SEARXNG_HOSTNAME:-localhost}
      - SEARXNG_TLS=${LETSENCRYPT_EMAIL:-internal}
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"

Effectively, we are mapping the localhost port 443 to the container port 443. You can change the host port (e.g., “8443:443”) to avoid conflicts. We also add a line to volumes so that caddy can see the certs we generated with mkcerts.

Now navigate down to the searxng: block. Replace the entire thing with this:

  searxng:
    container_name: searxng
    image: docker.io/searxng/searxng:latest
    restart: unless-stopped
    networks:
      - searxng
    expose:
      - "8080"  # <-- Internal only
    volumes:
      - ./searxng:/etc/searxng:rw
      - searxng-data:/var/cache/searxng:rw
    environment:
      - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/ # <-- The base URL is modified
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"

This makes port 8080 available only to other containers on the Docker network and not the host. No one else on the network has access to SearXNG.

Now run:

docker compose restart caddy
docker compose restart searxng

We can now access SearXNG via Caddy at https://localhost and use this local instance as our search engine in Firefox!

EXTRA: Making This Work With uBlacklist

uBlacklist is a Firefox addon that lets you add “blacklists,” or lists of sites that you don’t want showing up in your search results. It’s also available for Chrome, but using Chrome defeats the purpose of configuring SearXNG in the first place. Don’t use Chrome with this.

The default implementation of uBlacklist supports SearXNG, but only through a list of publically available instances in its SERPINFO list. That means uBlacklist cannot see your private instance of SearXNG.

To fix this, go to the extension’s Options page. Under “General”, click “SERPINFO”.

image

Then under “My SERPINFO”, add the following code:

name: SearXNG
homepage: https://github.com/ublacklist/builtin#readme

pages:
  - name: All
    includeRegex: "/search(\\?|$)"
    results:
      - root: .category-general
        url: a
        props:
          title: h3
          $category: [const, "web"]
      - root: .category-images
        url: .result-url > a
        props:
          title: .title
          $category: [const, "images"]
      - root: .category-videos
        url: a
        props:
          title: h3
          $category: [const, "videos"]
      - root: .category-news
        url: a
        props:
          title: h3
          $category: [const, "news"]
    commonProps:
      $site: searx # backwards compatibility
    matches:
     - https://localhost/*

You should be able to use SearXNG with uBlacklist now. If you’re not using “localhost” as your domain name, you need to change the last line to match it.