Metasuche selbst gemacht

linux howto docker searx docker-compose filtron

Searx ist eine Metasuchmaschine, die jeder auf seinem eigenen Server selbst betreiben kann. Tut man dies öffentlich, sollte man jedoch noch ein paar zusätzliche Vorkehrungen treffen und z.B. Suchanfragen mittels Filtron filtern. Sonst wird man von den angefragten Suchmaschinen schnell ausgesperrt.

Ich betreibe seit einiger Zeit die öffentliche Searx-Instanz unter https://searx.xyz. Das hat auch lange sehr gut funktioniert, bis einige Bots die Seite mit Anfragen bombardiert haben. Die Seite selbst hat das Problemlos weggesteckt. Allerdings funktioniert searx so, dass die eingegebene Suchanfrage an bis zu 70 Suchmaschinen weitergereicht wird. Diese mögen es in der Regel nicht, wenn eine einzelne IP zu viele Anfragen (ggf. auch noch mit seltsamen Inhalten) anstellt. Google verweigerte mir daraufhin Antworten und wollte stattdessen ein Captcha ausgefüllt bekommen.

Glücklicherweise haben die searx Entwickler aber das Tool filtron im Gepäck. Filtron ist im Grunde ein vor searx geschalteter Proxy, der die Anfragen filtern kann. Hierzu benötigt man ein Ruleset (rules.json):

[
    {
        "name": "search request",
        "filters": ["Param:q", "Path=^(/|/search)$"],
        "subrules": [
            {
                "name": "roboagent limit",
                "limit": 0,
                "filters": ["Header:User-Agent=(curl|cURL|Wget|python-requests|Scrapy|FeedFetcher|Go-http-client)"],
                "actions": [
                    {
                     "name": "block",
                     "params": {"message": "Rate limit exceeded"}}
                ]
            },
            {
                "name": "botlimit",
                "limit": 0,
                "stop": true,
                "filters": ["Header:User-Agent=(Googlebot|bingbot|Baiduspider|yacybot|YandexMobileBot|YandexBot|Yahoo! Slurp|MJ12bot|AhrefsBot|archive.org_bot|msnbot|MJ12bot|SeznamBot|linkdexbot|Netvibes|SMTBot|zgrab|James BOT)"],
                "actions": [
                    {
                     "name": "block",
                     "params": {"message": "Rate limit exceeded"}}
                ]
            },
            {
                "name": "IP limit",
                "interval": 300,
                "limit": 256,
                "stop": true,
                "aggregations": ["Header:X-Forwarded-For"],
                "actions": [
                    {
                     "name": "block",
                     "params": {"message": "Rate limit exceeded, try again later."}}
                ]
            },
            {
                "name": "rss/json limit",
                "interval": 600,
                "limit": 4,
                "stop": true,
                "filters": ["Param:format=(csv|json|rss)"],
                "actions": [
                    {
                     "name": "block",
                     "params": {"message": "Rate limit exceeded, try again later."}}
                ]
            },
            {
                "name": "useragent limit",
                "interval": 300,
                "limit": 128,
                "aggregations": ["Header:User-Agent"],
                "actions": [
                    {
                     "name": "block",
                     "params": {"message": "Rate limit exceeded, try again later."}}
                ]
            }
        ]
    }
]

Der erste Abschnitt (name: search request) sorgt dafür dass nur Suchanfragen beachtet werden. Die eigentliche Filterarbeit findet in den subrules statt. Die Regel roboagent limit sperrt Tools wie curl und wget aus (limit: 0), mit denen gerne Abfragen von Websites automatisiert werden. Sicher ist das nicht, da man den Agent einfach maskieren kann. Dasselbe gilt für bekannte Bots, z.B. von Suchmaschinen (botlimit). Die Regel IP limit sorgt dafür dass von einer bestimmten IP “nur” 256 Abfragen in 300 Sekunden möglich sind. Werden in dieser Zeit mehr Anfragen gestellt wird die Meldung Rate limit exceeded, try again later. ausgegeben. Die Regel rss/json limit schränkt den Abruf von Suchergebnissen in den Formaten csv, json und rss auf 4 in 600 Sekunden ein, diese Abfragen werden hauptsächlich von Bots gestellt und waren der Hauptgrund warum Google mir nicht mehr antworten wollte, daher ist die Regel sehr strikt. Die Regel useragent limit sollte nun selbsterklärend sein.

Ich betreibe searx als Docker-Container und natürlich bot es sich hier an filtron ebenfalls in einem Docker-Container zu verpacken. Hier nutze ich folgendes Dockerfile:

FROM golang:alpine

ENV APP_PORT 8888
ENV RULES_FILE /etc/filtron/rules.json

RUN apk add --no-cache git
RUN go get github.com/asciimoo/filtron
RUN mkdir /etc/filtron
EXPOSE 4004 4005

ADD rules.json /etc/filtron/rules.json
ADD entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Das Dockerfile von searx selbst sieht wie folgt aus:

FROM alpine:3.5
MAINTAINER searx https://github.com/asciimoo/searx
LABEL description "A privacy-respecting, hackable metasearch engine."
ENV BASE_URL=False IMAGE_PROXY=True
EXPOSE 8888
WORKDIR /usr/local/searx
CMD ["/sbin/tini","--","/usr/local/searx/run.sh"]
RUN adduser -D -h /usr/local/searx -s /bin/sh searx searx \
 && echo '#!/bin/sh' >> run.sh \
 && echo 'sed -i "s|base_url : False|base_url : $BASE_URL|g" searx/settings.yml' >> run.sh \
 && echo 'sed -i "s/image_proxy : False/image_proxy : $IMAGE_PROXY/g" searx/settings.yml' >> run.sh \
 && echo 'sed -i "s/ultrasecretkey/openssl rand -hex 16/g" searx/settings.yml' >> run.sh \
 && echo 'python searx/webapp.py' >> run.sh \
 && chmod +x run.sh
COPY requirements.txt ./requirements.txt
RUN echo "@commuedge http://nl.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories \
 && apk -U add \
    build-base \
    python \
    python-dev \
    py-pip \
    libxml2 \
    libxml2-dev \
    libxslt \
    libxslt-dev \
    libffi-dev \
    openssl \
    openssl-dev \
    ca-certificates \
    tini@commuedge \
 && pip install --no-cache -r requirements.txt \
 && apk del \
    build-base \
    python-dev \
    libffi-dev \
    openssl-dev \
    libxslt-dev \
    libxml2-dev \
    openssl-dev \
    ca-certificates \
 && rm -f /var/cache/apk/*
COPY . .
RUN chown -R searx:searx *
USER searx

RUN sed -i "s/127.0.0.1/0.0.0.0/g" searx/settings.yml

Mittels der beiden Dockerfiles erstelle ich mit docker build . -t localhost:5000/filtron respektive docker build . -t localhost:5000/searx lokale Images, die ich mittels docker push localhost:5000/filtron bzw. docker push localhost:5000/searx in mein lokales Docker-Repository lade (das ist nicht nötig, erleichtert mir aber ein paar interne Prozesse).

Damit searx und filtron problemlos miteinander kommunizieren können kombiniere ich beide Container mit docker-compose:

version: '2'

services:
  searx:
    image: localhost:5000/searx
    depends_on:
      - filtron
    networks:
      - searx
    restart: always

filtron:
    image: localhost:5000/filtron
    ports:
      - "127.0.0.1:8888:4004"
    environment:
      - APP_PORT=8888
      - RULES_FILE=/etc/filtron/rules.json
    networks:
      - searx
    restart: always

networks:
  searx:
    driver: bridge

Da ich die beiden nötigen Images im lokalen Repo verwalte kann ich einfach die fertigen Images von dort herunterladen. Alternativ könnte ich image durch ein Buildverzeichnis mit den jeweiligen Dockerfiles von searx und filtron ersetzen, dann erzeugt docker-compose die nötigen Images on-the-fly.

Mittels docker-compose up bzw. docker-compose create && docker-compose start können die beiden Container nun gestartet werden. filtron steht daraufhin unter der Adresse 127.0.0.1:8888 zur Verfügung und leitet Anfragen an searx weiter.


Kommentare

Kommentare unterstützt von Disqus.

Nächster Beitrag Vorheriger Beitrag