Merge branch 'master' into duckduckgo_correction

This commit is contained in:
Noémi Ványi 2020-06-28 20:28:12 +02:00 committed by GitHub
commit 93cbd85b8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
100 changed files with 7507 additions and 641 deletions

55
.config.sh Normal file
View file

@ -0,0 +1,55 @@
# -*- coding: utf-8; mode: sh -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck shell=bash disable=SC2034
#
# This environment is used by ./utils scripts like filtron.sh or searx.sh. The
# default values are *most flexible* and *best maintained*, you normally not
# need to change the defaults (except PUBLIC_URL).
#
# Before you change any value here you have to uninstall any previous
# installation. Further is it recommended to backup your changes simply by
# adding them to you local brand (git branch)::
#
# git add .config
# The public URL of the searx instance: PUBLIC_URL="https://mydomain.xy/searx"
# The default is taken from ./utils/brand.env.
PUBLIC_URL="${SEARX_URL}"
if [[ ${PUBLIC_URL} == "https://searx.me" ]]; then
# hint: Linux containers do not have DNS entries, lets use IPs
PUBLIC_URL="http://$(primary_ip)/searx"
fi
# searx.sh
# ---------
# SEARX_INTERNAL_URL="127.0.0.1:8888"
# Only change, if you maintain a searx brand in your searx fork.
# GIT_BRANCH="${GIT_BRANCH:-master}"
# filtron.sh
# ----------
# FILTRON_API="127.0.0.1:4005"
# FILTRON_LISTEN="127.0.0.1:4004"
# FILTRON_TARGET="127.0.0.1:8888"
# morty.sh
# --------
# morty listen address
# MORTY_LISTEN="127.0.0.1:3000"
# PUBLIC_URL_PATH_MORTY="/morty/"
# system services
# ---------------
# Common $HOME folder of the service accounts
# SERVICE_HOME_BASE="/usr/local"
# **experimental**: Set SERVICE_USER to run all services by one account, but be
# aware that removing discrete components might conflict!
# SERVICE_USER=searx

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
# to sync with .dockerignore
.coverage
coverage/
cache/
.installed.cfg
engines.cfg
env

View file

@ -1,24 +1,31 @@
# -*- coding: utf-8; mode: makefile-gmake -*-
.DEFAULT_GOAL=help
# START Makefile setup
export GIT_URL=https://github.com/asciimoo/searx
export GIT_BRANCH=master
export SEARX_URL=https://searx.me
export DOCS_URL=https://asciimoo.github.io/searx
# END Makefile setup
include utils/makefile.include
PYOBJECTS = searx
DOC = docs
PY_SETUP_EXTRAS ?= \[test\]
PYDIST=./dist/py
PYBUILD=./build/py
include utils/makefile.include
include utils/makefile.python
include utils/makefile.sphinx
all: clean install
PHONY += help
help:
PHONY += help-min help-all help
help: help-min
@echo ''
@echo 'to get more help: make help-all'
help-min:
@echo ' test - run developer tests'
@echo ' docs - build documentation'
@echo ' docs-live - autobuild HTML documentation while editing'
@ -33,9 +40,18 @@ help:
@echo ' docker - build Docker image'
@echo ' node.env - download & install npm dependencies locally'
@echo ''
@$(MAKE) -s -f utils/makefile.include make-help
@echo 'environment'
@echo ' SEARX_URL = $(SEARX_URL)'
@echo ' GIT_URL = $(GIT_URL)'
@echo ' DOCS_URL = $(DOCS_URL)'
@echo ''
@$(MAKE) -s -f utils/makefile.python python-help
@$(MAKE) -e -s make-help
help-all: help-min
@echo ''
@$(MAKE) -e -s python-help
@echo ''
@$(MAKE) -e -s docs-help
PHONY += install
install: buildenv pyenvinstall
@ -44,7 +60,7 @@ PHONY += uninstall
uninstall: pyenvuninstall
PHONY += clean
clean: pyclean node.clean test.clean
clean: pyclean docs-clean node.clean test.clean
$(call cmd,common_clean)
PHONY += run
@ -61,14 +77,24 @@ run: buildenv pyenvinstall
# docs
# ----
sphinx-doc-prebuilds:: buildenv pyenvinstall prebuild-includes
PHONY += docs
docs: buildenv pyenvinstall sphinx-doc
docs: sphinx-doc-prebuilds sphinx-doc
$(call cmd,sphinx,html,docs,docs)
PHONY += docs-live
docs-live: buildenv pyenvinstall sphinx-live
docs-live: sphinx-doc-prebuilds sphinx-live
$(call cmd,sphinx_autobuild,html,docs,docs)
PHONY += prebuild-includes
prebuild-includes:
$(Q)mkdir -p $(DOCS_BUILD)/includes
$(Q)./utils/searx.sh doc | cat > $(DOCS_BUILD)/includes/searx.rst
$(Q)./utils/filtron.sh doc | cat > $(DOCS_BUILD)/includes/filtron.rst
$(Q)./utils/morty.sh doc | cat > $(DOCS_BUILD)/includes/morty.rst
$(GH_PAGES)::
@echo "doc available at --> $(DOCS_URL)"
@ -94,12 +120,14 @@ useragents.update: pyenvinstall
buildenv:
$(Q)echo "build searx/brand.py"
$(Q)echo "GIT_URL = '$(GIT_URL)'" > searx/brand.py
$(Q)echo "GIT_BRANCH = '$(GIT_BRANCH)'" >> searx/brand.py
$(Q)echo "ISSUE_URL = 'https://github.com/asciimoo/searx/issues'" >> searx/brand.py
$(Q)echo "SEARX_URL = '$(SEARX_URL)'" >> searx/brand.py
$(Q)echo "DOCS_URL = '$(DOCS_URL)'" >> searx/brand.py
$(Q)echo "PUBLIC_INSTANCES = 'https://searx.space'" >> searx/brand.py
$(Q)echo "build utils/brand.env"
$(Q)echo "export GIT_URL='$(GIT_URL)'" > utils/brand.env
$(Q)echo "export GIT_BRANCH='$(GIT_BRANCH)'" >> utils/brand.env
$(Q)echo "export ISSUE_URL='https://github.com/asciimoo/searx/issues'" >> utils/brand.env
$(Q)echo "export SEARX_URL='$(SEARX_URL)'" >> utils/brand.env
$(Q)echo "export DOCS_URL='$(DOCS_URL)'" >> utils/brand.env
@ -182,8 +210,7 @@ gecko.driver:
# test
# ----
PHONY += test test.pylint test.pep8 test.unit test.coverage test.robot
PHONY += test test.sh test.pylint test.pep8 test.unit test.coverage test.robot
test: buildenv test.pylint test.pep8 test.unit gecko.driver test.robot
ifeq ($(PY),2)
@ -191,6 +218,7 @@ test.pylint:
@echo "LINT skip liniting py2"
else
# TODO: balance linting with pylint
test.pylint: pyenvinstall
$(call cmd,pylint,\
searx/preferences.py \
@ -202,6 +230,17 @@ endif
# E402 module level import not at top of file
# W503 line break before binary operator
# ubu1604: uses shellcheck v0.3.7 (from 04/2015), no longer supported!
test.sh:
shellcheck -x -s bash utils/brand.env
shellcheck -x utils/lib.sh
shellcheck -x utils/filtron.sh
shellcheck -x utils/searx.sh
shellcheck -x utils/morty.sh
shellcheck -x utils/lxc.sh
shellcheck -x utils/lxc-searx.env
shellcheck -x .config.sh
test.pep8: pyenvinstall
@echo "TEST pep8"
$(Q)$(PY_ENV_ACT); pep8 --exclude=searx/static --max-line-length=120 --ignore "E402,W503" searx tests

View file

@ -33,7 +33,7 @@ p.sidebar-title, .sidebar p {
/* admonitions
*/
div.admonition, div.topic {
div.admonition, div.topic, div.toctree-wrapper {
background-color: #fafafa;
margin: 8px 0px;
padding: 1em;
@ -42,6 +42,16 @@ div.admonition, div.topic {
border-right: none;
border-bottom: none;
border-left: 5pt solid #ccc;
list-style-type: disclosure-closed;
}
div.toctree-wrapper p.caption {
font-weight: normal;
font-size: 24px;
margin: 0 0 10px 0;
padding: 0;
line-height: 1;
display: inline;
}
p.admonition-title:after {
@ -128,3 +138,32 @@ caption {
caption-side: top;
text-align: left;
}
/* bugs since sphinx 3.1
See sphinx-doc project, PR 7838 & 7484 with elementary patch to the basic CSS:
- https://github.com/sphinx-doc/sphinx/issues/7838#issuecomment-646009605
- https://github.com/sphinx-doc/sphinx/pull/7484#issuecomment-646058972
*/
li > p:first-child {
margin-top: 0;
}
li > p:last-child {
margin-bottom: 0;
}
div.admonition dl {
margin-bottom: 0;
}
div.sidebar {
clear: none;
}
div.admonition, div.topic, pre {
clear: none;
}

View file

@ -4,11 +4,11 @@ digraph G {
edge [fontname="Sans"];
browser [label="Browser", shape=Mdiamond];
rp [label="Reverse Proxy", href="url to configure reverse proxy"];
filtron [label="Filtron", href="https://github.com/asciimoo/filtron"];
morty [label="Morty", href="https://github.com/asciimoo/morty"];
rp [label="Reverse Proxy", href="https://asciimoo.github.io/searx/utils/filtron.sh.html#public-reverse-proxy"];
filtron [label="Filtron", href="https://asciimoo.github.io/searx/utils/filtron.sh.html"];
morty [label="Morty", href="https://asciimoo.github.io/searx/utils/morty.sh.html"];
static [label="Static files", href="url to configure static files"];
uwsgi [label="uwsgi", href="url to configure uwsgi"]
uwsgi [label="uwsgi", href="https://asciimoo.github.io/searx/utils/searx.sh.html"]
searx1 [label="Searx #1"];
searx2 [label="Searx #2"];
searx3 [label="Searx #3"];

View file

@ -4,17 +4,21 @@
Architecture
============
.. sidebar:: Needs work!
.. sidebar:: Further reading
This article needs some work / Searx is a collaborative effort. If you have
any contribution, feel welcome to send us your :pull:`PR <../pulls>`, see
:ref:`how to contribute`.
- Reverse Proxy: :ref:`Apache <apache searx site>` & :ref:`nginx <nginx searx
site>`
- Filtron: :ref:`searx filtron`
- Morty: :ref:`searx morty`
- uWSGI: :ref:`searx uwsgi`
- Searx: :ref:`installation basic`
Herein you will find some hints and suggestions about typical architectures of
searx infrastructures.
We start with a contribution from :pull:`@dalf <1776#issuecomment-567917320>`.
It shows a *reference* setup for public searx instances.
It shows a *reference* setup for public searx instances which can build up and
maintained by the scripts from our :ref:`toolboxing`.
.. _arch public:

View file

@ -9,8 +9,27 @@ Buildhosts
If you have any contribution send us your :pull:`PR <../pulls>`, see
:ref:`how to contribute`.
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
To get best results from build, its recommend to install additional packages
on build hosts.
on build hosts (see :ref:`searx.sh`).::
sudo -H ./utils/searx.sh install buildhost
This will install packages needed by searx:
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START distro-packages
:end-before: END distro-packages
and packages needed to build docuemtation and run tests:
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START build-packages
:end-before: END build-packages
.. _docs build:
@ -35,8 +54,17 @@ processing additional packages are needed. The XeTeX_ needed not only for PDF
creation, its also needed for :ref:`math` when HTML output is build.
To be able to do :ref:`sphinx:math-support` without CDNs, the math are rendered
as images (``sphinx.ext.imgmath`` extension). If your docs build (``make
docs``) shows warnings like this::
as images (``sphinx.ext.imgmath`` extension).
Here is the extract from the :origin:`docs/conf.py` file, setting math renderer
to ``imgmath``:
.. literalinclude:: ../conf.py
:language: python
:start-after: # sphinx.ext.imgmath setup
:end-before: # sphinx.ext.imgmath setup END
If your docs build (``make docs``) shows warnings like this::
WARNING: dot(1) not found, for better output quality install \
graphviz from http://www.graphviz.org
@ -47,8 +75,6 @@ docs``) shows warnings like this::
you need to install additional packages on your build host, to get better HTML
output.
.. _system requirements:
.. tabs::
.. group-tab:: Ubuntu / debian
@ -92,12 +118,38 @@ For PDF output you also need:
$ sudo dnf install \
texlive-collection-fontsrecommended texlive-collection-latex \
dejavu-sans-fonts dejavu-serif-fonts dejavu-sans-mono-fonts
dejavu-sans-fonts dejavu-serif-fonts dejavu-sans-mono-fonts \
ImageMagick
.. _system requirements END:
.. _sh lint:
.. literalinclude:: ../conf.py
:language: python
:start-after: # sphinx.ext.imgmath setup
:end-before: # sphinx.ext.imgmath setup END
Lint shell scripts
==================
.. _ShellCheck: https://github.com/koalaman/shellcheck
To lint shell scripts, we use ShellCheck_ - A shell script static analysis tool.
.. SNIP sh lint requirements
.. tabs::
.. group-tab:: Ubuntu / debian
.. code-block:: sh
$ sudo apt install shellcheck
.. group-tab:: Arch Linux
.. code-block:: sh
$ sudo pacman -S shellcheck
.. group-tab:: Fedora / RHEL
.. code-block:: sh
$ sudo dnf install ShellCheck
.. SNAP sh lint requirements

View file

@ -1,18 +1,51 @@
.. _searx filtron:
==========================
How to protect an instance
==========================
Searx depens on external search services. To avoid the abuse of these services
.. sidebar:: further reading
- :ref:`filtron.sh`
- :ref:`nginx searx site`
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. _filtron: https://github.com/asciimoo/filtron
Searx depends on external search services. To avoid the abuse of these services
it is advised to limit the number of requests processed by searx.
An application firewall, ``filtron`` solves exactly this problem. Information
on how to install it can be found at the `project page of filtron
<https://github.com/asciimoo/filtron>`__.
An application firewall, filtron_ solves exactly this problem. Filtron is just
a middleware between your web server (nginx, apache, ...) and searx, we describe
such infratructures in chapter: :ref:`architecture`.
filtron & go
============
.. _Go: https://golang.org/
.. _filtron README: https://github.com/asciimoo/filtron/blob/master/README.md
Filtron needs Go_ installed. If Go_ is preinstalled, filtron_ is simply
installed by ``go get`` package management (see `filtron README`_). If you use
filtron as middleware, a more isolated setup is recommended. To simplify such
an installation and the maintenance of, use our script :ref:`filtron.sh`.
.. _Sample configuration of filtron:
Sample configuration of filtron
===============================
.. sidebar:: Tooling box
- :origin:`/etc/filtron/rules.json <utils/templates/etc/filtron/rules.json>`
An example configuration can be find below. This configuration limits the access
of:
@ -24,105 +57,104 @@ of:
.. code:: json
[{
"name":"search request",
"filters":[
[
{
"name": "search request",
"filters": [
"Param:q",
"Path=^(/|/search)$"
],
"interval":"<time-interval-in-sec (int)>",
"limit":"<max-request-number-in-interval (int)>",
"subrules":[
"interval": "<time-interval-in-sec (int)>"
"limit": "<max-request-number-in-interval (int)>",
"subrules": [
{
"name":"roboagent limit",
"interval":"<time-interval-in-sec (int)>",
"limit":"<max-request-number-in-interval (int)>",
"filters":[
"Header:User-Agent=(curl|cURL|Wget|python-requests|Scrapy|FeedFetcher|Go-http-client)"
],
"actions":[
{
"name":"block",
"params":{
"message":"Rate limit exceeded"
}
}
"name": "missing Accept-Language",
"filters": ["!Header:Accept-Language"],
"limit": "<max-request-number-in-interval (int)>",
"stop": true,
"actions": [
{"name":"log"},
{"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": "suspiciously Connection=close header",
"filters": ["Header:Connection=close"],
"limit": "<max-request-number-in-interval (int)>",
"stop": true,
"actions": [
{"name":"log"},
{"name": "block",
"params": {"message": "Rate limit exceeded"}}
]
},
{
"name":"IP limit",
"interval":"<time-interval-in-sec (int)>",
"limit":"<max-request-number-in-interval (int)>",
"stop":true,
"aggregations":[
"name": "IP limit",
"interval": "<time-interval-in-sec (int)>"
"limit": "<max-request-number-in-interval (int)>",
"stop": true,
"aggregations": [
"Header:X-Forwarded-For"
],
"actions":[
{
"name":"block",
"params":{
"message":"Rate limit exceeded"
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
},
{
"name":"rss/json limit",
"interval":"<time-interval-in-sec (int)>",
"limit":"<max-request-number-in-interval (int)>",
"stop":true,
"filters":[
"name": "rss/json limit",
"filters": [
"Param:format=(csv|json|rss)"
],
"actions":[
{
"name":"block",
"params":{
"message":"Rate limit exceeded"
"interval": "<time-interval-in-sec (int)>"
"limit": "<max-request-number-in-interval (int)>",
"stop": true,
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
},
{
"name":"useragent limit",
"interval":"<time-interval-in-sec (int)>",
"limit":"<max-request-number-in-interval (int)>",
"aggregations":[
"name": "useragent limit",
"interval": "<time-interval-in-sec (int)>"
"limit": "<max-request-number-in-interval (int)>",
"aggregations": [
"Header:User-Agent"
],
"actions":[
{
"name":"block",
"params":{
"message":"Rate limit exceeded"
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
}
]
}]
}
]
.. _filtron route request:
Route request through filtron
=============================
.. sidebar:: further reading
- :ref:`filtron.sh overview`
- :ref:`installation nginx`
- :ref:`installation apache`
Filtron can be started using the following command:
.. code:: sh
@ -136,13 +168,24 @@ Use it along with ``nginx`` with the following example configuration.
.. code:: nginx
location / {
# https://example.org/searx
location /searx {
proxy_pass http://127.0.0.1:4004/;
proxy_set_header Host $http_host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_pass http://127.0.0.1:4004/;
proxy_set_header X-Script-Name /searx;
}
location /searx/static {
/usr/local/searx/searx-src/searx/static;
}
Requests are coming from port 4004 going through filtron and then forwarded to
port 8888 where a searx is being run.
port 8888 where a searx is being run. For a complete setup see: :ref:`nginx
searx site`.

View file

@ -3,9 +3,16 @@ Administrator documentation
===========================
.. toctree::
:maxdepth: 1
:maxdepth: 2
:caption: Contents
installation
installation-searx
installation-uwsgi
installation-nginx
installation-apache
installation-docker
update-searx
settings
api
architecture

View file

@ -0,0 +1,514 @@
.. _installation apache:
===================
Install with apache
===================
.. _Apache: https://httpd.apache.org/
.. _Apache Debian:
https://cwiki.apache.org/confluence/display/HTTPD/DistrosDefaultLayout#DistrosDefaultLayout-Debian,Ubuntu(Apachehttpd2.x):
.. _README.Debian:
https://salsa.debian.org/apache-team/apache2/raw/master/debian/apache2.README.Debian
.. _Apache Arch Linux:
https://wiki.archlinux.org/index.php/Apache_HTTP_Server
.. _Apache Fedora:
https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-apache-http-server/index.html
.. _Apache directives:
https://httpd.apache.org/docs/trunk/mod/directives.html
.. _Getting Started:
https://httpd.apache.org/docs/current/en/getting-started.html
.. _Terms Used to Describe Directives:
https://httpd.apache.org/docs/current/en/mod/directive-dict.html
.. _Configuration Files:
https://httpd.apache.org/docs/current/en/configuring.html
.. _ProxyPreserveHost: https://httpd.apache.org/docs/trunk/mod/mod_proxy.html#proxypreservehost
.. _LoadModule:
https://httpd.apache.org/docs/2.4/mod/mod_so.html#loadmodule
.. _DocumentRoot:
https://httpd.apache.org/docs/trunk/mod/core.html#documentroot
.. _Location:
https://httpd.apache.org/docs/trunk/mod/core.html#location
.. _uWSGI Apache support:
https://uwsgi-docs.readthedocs.io/en/latest/Apache.html
.. _mod_proxy_uwsgi:
https://uwsgi-docs.readthedocs.io/en/latest/Apache.html#mod-proxy-uwsgi
.. sidebar:: further read
- `Apache Arch Linux`_
- `Apache Debian`_ and `README.Debian`_
- `Apache Fedora`_
- `Apache directives`_
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
----
**Install** :ref:`apache searx site` using :ref:`filtron.sh <filtron.sh overview>`
.. code:: bash
$ sudo -H ./utils/filtron.sh apache install
**Install** :ref:`apache searx site` using :ref:`morty.sh <morty.sh overview>`
.. code:: bash
$ sudo -H ./utils/morty.sh apache install
----
The apache HTTP server
======================
If Apache_ is not installed, install it now. If apache_ is new to you, the
`Getting Started`_, `Configuration Files`_ and `Terms Used to Describe
Directives`_ documentation gives first orientation. There is also a list of
`Apache directives`_ *to keep in the pocket*.
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
sudo -H apt-get install apache2
.. group-tab:: Arch Linux
.. code:: sh
sudo -H pacman -S apache
sudo -H systemctl enable httpd
sudo -H systemctl start http
.. group-tab:: Fedora / RHEL
.. code:: sh
sudo -H dnf install httpd
sudo -H systemctl enable httpd
sudo -H systemctl start httpd
Now at http://localhost you should see any kind of *Welcome* or *Test* page.
How this default intro site is configured, depends on the linux distribution
(compare `Apache directives`_).
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
less /etc/apache2/sites-enabled/000-default.conf
In this file, there is a line setting the `DocumentRoot`_ directive:
.. code:: apache
DocumentRoot /var/www/html
And the *welcome* page is the HTML file at ``/var/www/html/index.html``.
.. group-tab:: Arch Linux
.. code:: sh
less /etc/httpd/conf/httpd.conf
In this file, there is a line setting the `DocumentRoot`_ directive:
.. code:: apache
DocumentRoot "/srv/http"
<Directory "/srv/http">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
The *welcome* page of Arch Linux is a page showing directory located at
``DocumentRoot``. This is *directory* page is generated by the Module
`mod_autoindex <https://httpd.apache.org/docs/2.4/mod/mod_autoindex.html>`_:
.. code:: apache
LoadModule autoindex_module modules/mod_autoindex.so
...
Include conf/extra/httpd-autoindex.conf
.. group-tab:: Fedora / RHEL
.. code:: sh
less /etc/httpd/conf/httpd.conf
In this file, there is a line setting the ``DocumentRoot`` directive:
.. code:: apache
DocumentRoot "/var/www/html"
...
<Directory "/var/www">
AllowOverride None
# Allow open access:
Require all granted
</Directory>
On fresh installations, the ``/var/www`` is empty and the *default
welcome page* is shown, the configuration is located at::
less /etc/httpd/conf.d/welcome.conf
.. _apache searx site:
Apache Reverse Proxy
====================
.. sidebar:: public to the internet?
If your searx instance is public, stop here and first install :ref:`filtron
reverse proxy <filtron.sh>` and :ref:`result proxy morty <morty.sh>`, see
:ref:`installation scripts`. If already done, follow setup: *searx via
filtron plus morty*.
To setup a Apache revers proxy you have to enable the *headers* and *proxy*
modules and create a `Location`_ configuration for the searx site. In most
distributions you have to un-comment the lines in the main configuration file,
except in :ref:`The Debian Layout`.
To pass the HTTP HOST header
With ProxyPreserveHost_ the incoming Host HTTP request header is passed to the
proxied host.
.. tabs::
.. group-tab:: Ubuntu / debian
In the Apache setup, enable headers and proxy modules:
.. code:: sh
sudo -H a2enmod headers
sudo -H a2enmod proxy
sudo -H a2enmod proxy_http
In :ref:`The Debian Layout` you create a ``searx.conf`` with the
``<Location /searx >`` directive and save this file in the *sites
available* folder at ``/etc/apache2/sites-available``. To enable the
``searx.conf`` use :man:`a2ensite`:
.. code:: sh
sudo -H a2ensite searx.conf
.. group-tab:: Arch Linux
In the ``/etc/httpd/conf/httpd.conf`` file, activate headers and proxy
modules (LoadModule_):
.. code:: apache
FIXME needs test
LoadModule headers_module modules/mod_headers.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
.. group-tab:: Fedora / RHEL
In the ``/etc/httpd/conf/httpd.conf`` file, activate headers and proxy
modules (LoadModule_):
.. code:: apache
FIXME needs test
LoadModule headers_module modules/mod_headers.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
.. tabs::
.. group-tab:: searx via filtron plus morty
Use this setup, if your instance is public to the internet, compare
figure: :ref:`architecture <arch public>` and :ref:`installation scripts`.
1. Configure a reverse proxy for :ref:`filtron <filtron.sh>`, listening on
*localhost 4004* (:ref:`filtron route request`):
.. code:: apache
<Location /searx >
# SetEnvIf Request_URI "/searx" dontlog
# CustomLog /dev/null combined env=dontlog
Require all granted
Order deny,allow
Deny from all
#Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass http://127.0.0.1:4004
RequestHeader set X-Script-Name /searx
</Location>
2. Configure reverse proxy for :ref:`morty <searx morty>`, listening on
*localhost 3000*
.. code:: apache
ProxyPreserveHost On
<Location /morty >
# SetEnvIf Request_URI "/morty" dontlog
# CustomLog /dev/null combined env=dontlog
Require all granted
Order deny,allow
Deny from all
#Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPass http://127.0.0.1:3000
RequestHeader set X-Script-Name /morty
</Location>
Note that reverse proxy advised to be used in case of single-user or
low-traffic instances. For a fully result proxification add :ref:`morty's
<searx morty>` **public URL** to your :origin:`searx/settings.yml`:
.. code:: yaml
result_proxy:
# replace example.org with your server's public name
url : https://example.org/morty
server:
image_proxy : True
uWSGI support
=============
Be warned, with this setup, your instance isn't :ref:`protected <searx
filtron>`, nevertheless it is good enough for intranet usage. In modern Linux
distributions, the `mod_proxy_uwsgi`_ is compiled into the *normal* apache
package and you need to install only the :ref:`uWSGI <searx uwsgi>` package:
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
sudo -H apt-get install uwsgi
# Ubuntu =< 18.04
sudo -H apt-get install libapache2-mod-proxy-uwsgi
.. group-tab:: Arch Linux
.. code:: sh
sudo -H pacman -S uwsgi
.. group-tab:: Fedora / RHEL
.. code:: sh
sudo -H dnf install uwsgi
The next example shows a configuration using the `uWSGI Apache support`_ via
unix sockets and `mod_proxy_uwsgi`_.
For socket communication, you have to activate ``socket =
/run/uwsgi/app/searx/socket`` and comment out the ``http = 127.0.0.1:8888``
configuration in your :ref:`uwsgi ini file <uwsgi configuration>`. If not
already exists, create a folder for the unix sockets, which can be used by the
searx account (see :ref:`create searx user`):
.. code:: bash
sudo -H mkdir -p /run/uwsgi/app/searx/
sudo -H chown -R searx:searx /run/uwsgi/app/searx/
If the server is public; to limit access to your intranet replace ``Allow from
all`` directive and replace ``192.168.0.0/16`` with your subnet IP/class.
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: apache
LoadModule headers_module /usr/lib/apache2/mod_headers.so
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so
# SetEnvIf Request_URI /searx dontlog
# CustomLog /dev/null combined env=dontlog
<Location /searx>
Require all granted
Order deny,allow
Deny from all
# Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass unix:/run/uwsgi/app/searx/socket|uwsgi://uwsgi-uds-searx/
</Location>
.. group-tab:: Arch Linux
.. code:: apache
FIXME needs test
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
# SetEnvIf Request_URI /searx dontlog
# CustomLog /dev/null combined env=dontlog
<Location /searx>
Require all granted
Order deny,allow
Deny from all
# Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass unix:/run/uwsgi/app/searx/socket|uwsgi://uwsgi-uds-searx/
</Location>
.. group-tab:: Fedora / RHEL
.. code:: apache
FIXME needs test
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
<IfModule proxy_uwsgi_module>
# SetEnvIf Request_URI /searx dontlog
# CustomLog /dev/null combined env=dontlog
<Location /searx>
Require all granted
Order deny,allow
Deny from all
# Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass unix:/run/uwsgi/app/searx/socket|uwsgi://uwsgi-uds-searx/
</Location>
</IfModule>
.. group-tab:: old mod_wsgi
We show this only for historical reasons, DON'T USE `mod_uwsgi
<https://uwsgi-docs.readthedocs.io/en/latest/Apache.html#mod-uwsgi>`_.
ANYMORE!
.. code:: apache
<IfModule mod_uwsgi.c>
# SetEnvIf Request_URI "/searx" dontlog
# CustomLog /dev/null combined env=dontlog
<Location /searx >
Require all granted
Options FollowSymLinks Indexes
SetHandler uwsgi-handler
uWSGISocket /run/uwsgi/app/searx/socket
Order deny,allow
Deny from all
# Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
</Location>
</IfModule>
.. _restart apache:
Restart service
===============
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
sudo -H systemctl restart apache2
sudo -H service uwsgi restart searx
.. group-tab:: Arch Linux
.. code:: sh
sudo -H systemctl restart httpd
sudo -H systemctl restart uwsgi@searx
.. group-tab:: Fedora / RHEL
.. code:: sh
sudo -H systemctl restart httpd
sudo -H touch /etc/uwsgi.d/searx.ini
disable logs
============
For better privacy you can disable Apache logs. In the examples above activate
one of the lines and `restart apache`_::
# SetEnvIf Request_URI "/searx" dontlog
# CustomLog /dev/null combined env=dontlog
The ``CustomLog`` directive disable logs for the whole (virtual) server, use it
when the URL of the service does not have a path component (``/searx``) / is
located at root (``/``).
.. _The Debian Layout:
The Debian Layout
=================
Be aware that the Debian layout is quite different from the standard Apache
configuration. For details look at the README.Debian_
(``/usr/share/doc/apache2/README.Debian.gz``). Some commands you should know on
Debian:
* :man:`apache2ctl`: Apache HTTP server control interface
* :man:`a2enmod`, :man:`a2dismod`: switch on/off modules
* :man:`a2enconf`, :man:`a2disconf`: switch on/off configurations
* :man:`a2ensite`, :man:`a2dissite`: switch on/off sites

View file

@ -0,0 +1,28 @@
.. _installation docker:
===================
Docker installation
===================
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
Make sure you have installed Docker. For instance, you can deploy searx like this:
.. code:: sh
docker pull wonderfall/searx
docker run -d --name searx -p $PORT:8888 wonderfall/searx
Go to ``http://localhost:$PORT``.
See https://hub.docker.com/r/wonderfall/searx/ for more informations. It's also
possible to build searx from the embedded Dockerfile.
.. code:: sh
git clone https://github.com/asciimoo/searx.git
cd searx
docker build -t whatever/searx .

View file

@ -0,0 +1,381 @@
.. _installation nginx:
==================
Install with nginx
==================
.. _nginx:
https://docs.nginx.com/nginx/admin-guide/
.. _nginx server configuration:
https://docs.nginx.com/nginx/admin-guide/web-server/web-server/#setting-up-virtual-servers
.. _nginx beginners guide:
http://nginx.org/en/docs/beginners_guide.html
.. _Getting Started wiki:
https://www.nginx.com/resources/wiki/start/
.. _uWSGI support from nginx:
https://uwsgi-docs.readthedocs.io/en/latest/Nginx.html
.. _uwsgi_params:
https://uwsgi-docs.readthedocs.io/en/latest/Nginx.html#configuring-nginx
.. _SCRIPT_NAME:
https://werkzeug.palletsprojects.com/en/1.0.x/wsgi/#werkzeug.wsgi.get_script_name
.. sidebar:: further reading
- nginx_
- `nginx beginners guide`_
- `nginx server configuration`_
- `Getting Started wiki`_
- `uWSGI support from nginx`_
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
----
**Install** :ref:`nginx searx site` using :ref:`filtron.sh <filtron.sh overview>`
.. code:: bash
$ sudo -H ./utils/filtron.sh nginx install
**Install** :ref:`nginx searx site` using :ref:`morty.sh <morty.sh overview>`
.. code:: bash
$ sudo -H ./utils/morty.sh nginx install
----
The nginx HTTP server
=====================
If nginx_ is not installed (uwsgi will not work with the package nginx-light),
install it now.
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
sudo -H apt-get install nginx
.. group-tab:: Arch Linux
.. code-block:: sh
sudo -H pacman -S nginx-mainline
sudo -H systemctl enable nginx
sudo -H systemctl start nginx
.. group-tab:: Fedora / RHEL
.. code-block:: sh
sudo -H dnf install nginx
sudo -H systemctl enable nginx
sudo -H systemctl start nginx
Now at http://localhost you should see a *Welcome to nginx!* page, on Fedora you
see a *Fedora Webserver - Test Page*. The test page comes from the default
`nginx server configuration`_. How this default intro site is configured,
depends on the linux distribution:
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
less /etc/nginx/nginx.conf
there is a line including site configurations from:
.. code:: nginx
include /etc/nginx/sites-enabled/*;
.. group-tab:: Arch Linux
.. code-block:: sh
less /etc/nginx/nginx.conf
in there is a configuration section named ``server``:
.. code-block:: nginx
server {
listen 80;
server_name localhost;
# ...
}
.. group-tab:: Fedora / RHEL
.. code-block:: sh
less /etc/nginx/nginx.conf
there is a line including site configurations from:
.. code:: nginx
include /etc/nginx/conf.d/*.conf;
.. _nginx searx site:
A nginx searx site
==================
.. sidebar:: public to the internet?
If your searx instance is public, stop here and first install :ref:`filtron
reverse proxy <filtron.sh>` and :ref:`result proxy morty <morty.sh>`, see
:ref:`installation scripts`. If already done, follow setup: *searx via
filtron plus morty*.
Now you have to create a configuration for the searx site. If nginx_ is new to
you, the `nginx beginners guide`_ is a good starting point and the `Getting
Started wiki`_ is always a good resource *to keep in the pocket*.
.. tabs::
.. group-tab:: Ubuntu / debian
Create configuration at ``/etc/nginx/sites-available/searx`` and place a
symlink to sites-enabled:
.. code:: sh
sudo -H ln -s /etc/nginx/sites-available/searx /etc/nginx/sites-enabled/searx
.. group-tab:: Arch Linux
In the ``/etc/nginx/nginx.conf`` file, replace the configuration section
named ``server``.
.. group-tab:: Fedora / RHEL
Create configuration at ``/etc/nginx/conf.d/searx`` and place a
symlink to sites-enabled:
.. tabs::
.. group-tab:: searx via filtron plus morty
Use this setup, if your instance is public to the internet, compare
figure: :ref:`architecture <arch public>` and :ref:`installation scripts`.
1. Configure a reverse proxy for :ref:`filtron <filtron.sh>`, listening on
*localhost 4004* (:ref:`filtron route request`):
.. code:: nginx
# https://example.org/searx
location /searx {
proxy_pass http://127.0.0.1:4004/;
proxy_set_header Host $http_host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /searx;
}
location /searx/static {
/usr/local/searx/searx-src/searx/static;
}
2. Configure reverse proxy for :ref:`morty <searx morty>`, listening on
*localhost 3000*:
.. code:: nginx
# https://example.org/morty
location /morty {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $http_host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
}
Note that reverse proxy advised to be used in case of single-user or
low-traffic instances. For a fully result proxification add :ref:`morty's
<searx morty>` **public URL** to your :origin:`searx/settings.yml`:
.. code:: yaml
result_proxy:
# replace example.org with your server's public name
url : https://example.org/morty
server:
image_proxy : True
.. group-tab:: proxy or uWSGI
Be warned, with this setup, your instance isn't :ref:`protected <searx
filtron>`. Nevertheless it is good enough for intranet usage and it is a
excellent example of; *how different services can be set up*. The next
example shows a reverse proxy configuration wrapping the :ref:`searx-uWSGI
application <uwsgi configuration>`, listening on ``http =
127.0.0.1:8888``.
.. code:: nginx
# https://hostname.local/
location / {
proxy_pass http://127.0.0.1:8888;
proxy_set_header Host $host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_buffering off;
}
Alternatively you can use the `uWSGI support from nginx`_ via unix
sockets. For socket communication, you have to activate ``socket =
/run/uwsgi/app/searx/socket`` and comment out the ``http =
127.0.0.1:8888`` configuration in your :ref:`uwsgi ini file <uwsgi
configuration>`.
The example shows a nginx virtual ``server`` configuration, listening on
port 80 (IPv4 and IPv6 http://[::]:80). The uWSGI app is configured at
location ``/`` by importing the `uwsgi_params`_ and passing requests to
the uWSGI socket (``uwsgi_pass``). The ``server``\'s root points to the
:ref:`searx-src clone <searx-src>` and wraps directly the
:origin:`searx/static/` content at ``location /static``.
.. code:: nginx
server {
# replace hostname.local with your server's name
server_name hostname.local;
listen 80;
listen [::]:80;
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/searx/socket;
}
root /usr/local/searx/searx-src/searx;
location /static { }
}
If not already exists, create a folder for the unix sockets, which can be
used by the searx account:
.. code:: bash
mkdir -p /run/uwsgi/app/searx/
sudo -H chown -R searx:searx /run/uwsgi/app/searx/
.. group-tab:: \.\. at subdir URL
Be warned, with these setups, your instance isn't :ref:`protected <searx
filtron>`. The examples are just here to demonstrate how to export the
searx application from a subdirectory URL ``https://example.org/searx/``.
.. code:: nginx
# https://hostname.local/searx
location /searx {
proxy_pass http://127.0.0.1:8888;
proxy_set_header Host $host;
proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /searx;
proxy_buffering off;
}
location /searx/static {
alias /usr/local/searx/searx-src/searx/static;
}
The ``X-Script-Name /searx`` is needed by the searx implementation to
calculate relative URLs correct. The next example shows a uWSGI
configuration. Since there are no HTTP headers in a (u)WSGI protocol, the
value is shipped via the SCRIPT_NAME_ in the WSGI environment.
.. code:: nginx
# https://hostname.local/searx
location /searx {
uwsgi_param SCRIPT_NAME /searx;
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/searx/socket;
}
location /searx/static {
alias /usr/local/searx/searx-src/searx;
}
For searx to work correctly the ``base_url`` must be set in the
:origin:`searx/settings.yml`.
.. code:: yaml
server:
# replace example.org with your server's public name
base_url : https://example.org/searx/
Restart service:
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
sudo -H systemctl restart nginx
sudo -H service uwsgi restart searx
.. group-tab:: Arch Linux
.. code:: sh
sudo -H systemctl restart nginx
sudo -H systemctl restart uwsgi@searx
.. group-tab:: Fedora
.. code:: sh
sudo -H systemctl restart nginx
sudo -H touch /etc/uwsgi.d/searx.ini
Disable logs
============
For better privacy you can disable nginx logs in ``/etc/nginx/nginx.conf``.
.. code:: nginx
http {
# ...
access_log /dev/null;
error_log /dev/null;
# ...
}

View file

@ -0,0 +1,92 @@
.. _installation basic:
=========================
Step by step installation
=========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
Step by step installation with virtualenv. For Ubuntu, be sure to have enable
universe repository.
.. _install packages:
Install packages
================
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START distro-packages
:end-before: END distro-packages
.. hint::
This installs also the packages needed by :ref:`searx uwsgi`
.. _create searx user:
Create user
===========
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START create user
:end-before: END create user
.. _searx-src:
install searx & dependencies
============================
Start a interactive shell from new created user and clone searx:
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START clone searx
:end-before: END clone searx
In the same shell create *virtualenv*:
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START create virtualenv
:end-before: END create virtualenv
To install searx's dependencies, exit the searx *bash* session you opened above
and restart a new. Before install, first check if your *virualenv* was sourced
from the login (*~/.profile*):
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START manage.sh update_packages
:end-before: END manage.sh update_packages
.. tip::
Open a second terminal for the configuration tasks and left the ``(searx)$``
terminal open for the tasks below.
Configuration
==============
Create a copy of the :origin:`searx/settings.yml` configuration file in system's
*/etc* folder. Configure like shown below -- replace ``searx@\$(uname -n)`` with
a name of your choice -- *and/or* edit ``/etc/searx/settings.yml`` if necessary.
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START searx config
:end-before: END searx config
Check
=====
To check your searx setup, optional enable debugging and start the *webapp*.
Searx looks at the exported environment ``$SEARX_SETTINGS_PATH`` for a
configuration file.
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START check searx installation
:end-before: END check searx installation
If everything works fine, hit ``[CTRL-C]`` to stop the *webapp* and disable the
debug option in ``settings.yml``. You can now exit searx user bash (enter exit
command twice). At this point searx is not demonized; uwsgi allows this.

View file

@ -0,0 +1,149 @@
.. _searx uwsgi:
=====
uwsgi
=====
.. sidebar:: further reading
- `systemd.unit`_
- `uWSGI Emperor`_
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. _systemd.unit: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
.. _One service per app in systemd:
https://uwsgi-docs.readthedocs.io/en/latest/Systemd.html#one-service-per-app-in-systemd
.. _uWSGI Emperor:
https://uwsgi-docs.readthedocs.io/en/latest/Emperor.html
.. _uwsgi ini file:
https://uwsgi-docs.readthedocs.io/en/latest/Configuration.html#ini-files
.. _systemd unit template:
http://0pointer.de/blog/projects/instances.html
Origin uWSGI
============
How uWSGI is implemented by distributors is different. uWSGI itself
recommend two methods
`systemd.unit`_ template files as described here `One service per app in systemd`_.
There is one `systemd unit template`_ and one `uwsgi ini file`_ per uWSGI-app
placed at dedicated locations. Take archlinux and a searx.ini as example::
unit template --> /usr/lib/systemd/system/uwsgi@.service
uwsgi ini files --> /etc/uwsgi/searx.ini
The searx app can be maintained as know from common systemd units::
systemctl enable uwsgi@searx
systemctl start uwsgi@searx
systemctl restart uwsgi@searx
systemctl stop uwsgi@searx
The `uWSGI Emperor`_ mode which fits for maintaining a large range of uwsgi apps.
The Emperor mode is a special uWSGI instance that will monitor specific
events. The Emperor mode (service) is started by a (common, not template)
systemd unit. The Emperor service will scan specific directories for `uwsgi
ini file`_\s (also know as *vassals*). If a *vassal* is added, removed or the
timestamp is modified, a corresponding action takes place: a new uWSGI
instance is started, reload or stopped. Take Fedora and a searx.ini as
example::
to start a new searx instance create --> /etc/uwsgi.d/searx.ini
to reload the instance edit timestamp --> touch /etc/uwsgi.d/searx.ini
to stop instance remove ini --> rm /etc/uwsgi.d/searx.ini
Distributors
============
The `uWSGI Emperor`_ mode and `systemd unit template`_ is what the distributors
mostly offer their users, even if they differ in the way they implement both
modes and their defaults. Another point they might differ is the packaging of
plugins (if so, compare :ref:`install packages`) and what the default python
interpreter is (python2 vs. python3).
Fedora starts a Emperor by default, while archlinux does not start any uwsgi
service by default. Worth to know; debian (ubuntu) follow a complete different
approach. *debian*: your are familiar with the apache infrastructure? .. they
do similar for the uWSGI infrastructure (with less comfort), the folders are::
/etc/uwsgi/apps-available/
/etc/uwsgi/apps-enabled/
The `uwsgi ini file`_ is enabled by a symbolic link::
ln -s /etc/uwsgi/apps-available/searx.ini /etc/uwsgi/apps-enabled/
From debian's documentation (``/usr/share/doc/uwsgi/README.Debian.gz``): You
could control specific instance(s) by issuing::
service uwsgi <command> <confname> <confname> ...
sudo -H service uwsgi start searx
sudo -H service uwsgi stop searx
My experience is, that this command is a bit buggy.
.. _uwsgi configuration:
Alltogether
===========
Create the configuration ini-file according to your distribution (see below) and
restart the uwsgi application.
.. tabs::
.. group-tab:: Ubuntu / debian
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START searx uwsgi-description ubuntu-20.04
:end-before: END searx uwsgi-description ubuntu-20.04
.. group-tab:: Arch Linux
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START searx uwsgi-description arch
:end-before: END searx uwsgi-description arch
.. group-tab:: Fedora / RHEL
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:start-after: START searx uwsgi-description fedora
:end-before: END searx uwsgi-description fedora
.. tabs::
.. group-tab:: Ubuntu / debian
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:code: ini
:start-after: START searx uwsgi-appini ubuntu-20.04
:end-before: END searx uwsgi-appini ubuntu-20.04
.. group-tab:: Arch Linux
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:code: ini
:start-after: START searx uwsgi-appini arch
:end-before: END searx uwsgi-appini arch
.. group-tab:: Fedora / RHEL
.. kernel-include:: $DOCS_BUILD/includes/searx.rst
:code: ini
:start-after: START searx uwsgi-appini fedora
:end-before: END searx uwsgi-appini fedora

View file

@ -4,346 +4,63 @@
Installation
============
.. contents::
:depth: 3
*You're spoilt for choice*, choose your preferred method of installation.
Basic installation
==================
- :ref:`installation docker`
- :ref:`installation scripts`
- :ref:`installation basic`
Step by step installation for Debian/Ubuntu with virtualenv. For Ubuntu, be sure
to have enable universe repository.
The :ref:`installation basic` is good enough for intranet usage and it is a
excellent illustration of *how a searx instance is build up*. If you place your
instance public to the internet you should really consider to install a
:ref:`filtron reverse proxy <filtron.sh>` and for privacy a :ref:`result proxy
<morty.sh>` is mandatory.
Install packages:
Therefore, if you do not have any special preferences, its recommend to use the
:ref:`installation docker` or the `Installation scripts`_ from our :ref:`tooling
box <toolboxing>` as described below.
.. code:: sh
.. _installation scripts:
$ sudo -H apt-get install \
git build-essential libxslt-dev \
python-dev python-virtualenv python-babel \
zlib1g-dev libffi-dev libssl-dev
Installation scripts
====================
Install searx:
.. sidebar:: Update OS first!
.. code:: sh
To avoid unwanted side effects, update your OS before installing searx.
cd /usr/local
sudo -H git clone https://github.com/asciimoo/searx.git
sudo -H useradd searx -d /usr/local/searx
sudo -H chown searx:searx -R /usr/local/searx
The following will install a setup as shown in :ref:`architecture`. First you
need to get a clone. The clone is only needed for the installation procedure
and some maintenance tasks (alternatively you can create your own fork).
Install dependencies in a virtualenv:
.. code:: bash
.. code:: sh
$ cd ~/Downloads
$ git clone https://github.com/asciimoo/searx searx
$ cd searx
cd /usr/local/searx
sudo -H -u searx -i
**Install** :ref:`searx service <searx.sh>`
.. code:: sh
This installs searx as described in :ref:`installation basic`.
(searx)$ virtualenv searx-ve
(searx)$ . ./searx-ve/bin/activate
(searx)$ ./manage.sh update_packages
.. code:: bash
Configuration
==============
$ sudo -H ./utils/searx.sh install all
.. code:: sh
**Install** :ref:`filtron reverse proxy <filtron.sh>`
sed -i -e "s/ultrasecretkey/`openssl rand -hex 16`/g" searx/settings.yml
.. code:: bash
Edit searx/settings.yml if necessary.
$ sudo -H ./utils/filtron.sh install all
Check
=====
**Install** :ref:`result proxy <morty.sh>`
Start searx:
.. code:: bash
.. code:: sh
$ sudo -H ./utils/morty.sh install all
python searx/webapp.py
If all services are running fine, you can add it to your HTTP server:
Go to http://localhost:8888
- :ref:`installation apache`
- :ref:`installation nginx`
If everything works fine, disable the debug option in settings.yml:
.. code:: sh
sed -i -e "s/debug : True/debug : False/g" searx/settings.yml
At this point searx is not demonized ; uwsgi allows this.
You can exit the virtualenv and the searx user bash (enter exit command
twice).
uwsgi
=====
Install packages:
.. code:: sh
sudo -H apt-get install \
uwsgi uwsgi-plugin-python
Create the configuration file ``/etc/uwsgi/apps-available/searx.ini`` with this
content:
.. code:: ini
[uwsgi]
# Who will run the code
uid = searx
gid = searx
# disable logging for privacy
disable-logging = true
# Number of workers (usually CPU count)
workers = 4
# The right granted on the created socket
chmod-socket = 666
# Plugin to use and interpretor config
single-interpreter = true
master = true
plugin = python
lazy-apps = true
enable-threads = true
# Module to import
module = searx.webapp
# Support running the module from a webserver subdirectory.
route-run = fixpathinfo:
# Virtualenv and python path
virtualenv = /usr/local/searx/searx-ve/
pythonpath = /usr/local/searx/
chdir = /usr/local/searx/searx/
Activate the uwsgi application and restart:
.. code:: sh
cd /etc/uwsgi/apps-enabled
ln -s ../apps-available/searx.ini
/etc/init.d/uwsgi restart
Web server
==========
with nginx
----------
If nginx is not installed (uwsgi will not work with the package
nginx-light):
.. code:: sh
sudo -H apt-get install nginx
Hosted at /
~~~~~~~~~~~
Create the configuration file ``/etc/nginx/sites-available/searx`` with this
content:
.. code:: nginx
server {
listen 80;
server_name searx.example.com;
root /usr/local/searx/searx;
location /static {
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/searx/socket;
}
}
Create a symlink to sites-enabled:
.. code:: sh
sudo -H ln -s /etc/nginx/sites-available/searx /etc/nginx/sites-enabled/searx
Restart service:
.. code:: sh
sudo -H service nginx restart
sudo -H service uwsgi restart
from subdirectory URL (/searx)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add this configuration in the server config file
``/etc/nginx/sites-enabled/default``:
.. code:: nginx
location /searx/static {
alias /usr/local/searx/searx/static;
}
location /searx {
uwsgi_param SCRIPT_NAME /searx;
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/searx/socket;
}
**OR** using reverse proxy (Please, note that reverse proxy advised to be used
in case of single-user or low-traffic instances.)
.. code:: nginx
location /searx/static {
alias /usr/local/searx/searx/static;
}
location /searx {
proxy_pass http://127.0.0.1:8888;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /searx;
proxy_buffering off;
}
Enable ``base_url`` in ``searx/settings.yml``
.. code:: yaml
base_url : http://your.domain.tld/searx/
Restart service:
.. code:: sh
sudo -H service nginx restart
sudo -H service uwsgi restart
disable logs
^^^^^^^^^^^^
for better privacy you can disable nginx logs about searx.
how to proceed: below ``uwsgi_pass`` in ``/etc/nginx/sites-available/default``
add:
.. code:: nginx
access_log /dev/null;
error_log /dev/null;
Restart service:
.. code:: sh
sudo -H service nginx restart
with apache
-----------
Add wsgi mod:
.. code:: sh
sudo -H apt-get install libapache2-mod-uwsgi
sudo -H a2enmod uwsgi
Add this configuration in the file ``/etc/apache2/apache2.conf``:
.. code:: apache
<Location />
Options FollowSymLinks Indexes
SetHandler uwsgi-handler
uWSGISocket /run/uwsgi/app/searx/socket
</Location>
Note that if your instance of searx is not at the root, you should change
``<Location />`` by the location of your instance, like ``<Location /searx>``.
Restart Apache:
.. code:: sh
sudo -H /etc/init.d/apache2 restart
disable logs
~~~~~~~~~~~~
For better privacy you can disable Apache logs.
.. warning::
You can only disable logs for the whole (virtual) server not for a specific
path.
Go back to ``/etc/apache2/apache2.conf`` and above ``<Location />`` add:
.. code:: apache
CustomLog /dev/null combined
Restart Apache:
.. code:: sh
sudo -H /etc/init.d/apache2 restart
How to update
=============
.. code:: sh
cd /usr/local/searx
sudo -H -u searx -i
.. code:: sh
(searx)$ . ./searx-ve/bin/activate
(searx)$ git stash
(searx)$ git pull origin master
(searx)$ git stash apply
(searx)$ ./manage.sh update_packages
.. code:: sh
sudo -H service uwsgi restart
Docker
======
Make sure you have installed Docker. For instance, you can deploy searx like this:
.. code:: sh
docker pull wonderfall/searx
docker run -d --name searx -p $PORT:8888 wonderfall/searx
Go to ``http://localhost:$PORT``.
See https://hub.docker.com/r/wonderfall/searx/ for more informations. It's also
possible to build searx from the embedded Dockerfile.
.. code:: sh
git clone https://github.com/asciimoo/searx.git
cd searx
docker build -t whatever/searx .
References
==========
* https://about.okhin.fr/posts/Searx/ with some additions
* How to: `Setup searx in a couple of hours with a free SSL certificate
<https://www.reddit.com/r/privacytoolsIO/comments/366kvn/how_to_setup_your_own_privacy_respecting_search/>`__

View file

@ -1,7 +1,14 @@
.. _searx morty:
=========================
How to setup result proxy
=========================
.. sidebar:: further reading
- :ref:`morty.sh`
.. _morty: https://github.com/asciimoo/morty
.. _morty's README: https://github.com/asciimoo/morty

View file

@ -4,11 +4,17 @@
``settings.yml``
================
This page describe the options possibilities of the :origin:`searx/settings.yml`
file.
.. sidebar:: Further reading ..
- :ref:`search API`
This page describe the options possibilities of the settings.yml file.
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. _settings global:

View file

@ -0,0 +1,23 @@
.. _update searx:
=============
How to update
=============
.. code:: sh
sudo -H -u searx -i
(searx)$ git stash
(searx)$ git pull origin master
(searx)$ git stash apply
(searx)$ ./manage.sh update_packages
Restart uwsgi:
.. tabs::
.. group-tab:: Ubuntu / debian
.. code:: sh
sudo -H systemctl restart uwsgi

View file

@ -3,7 +3,8 @@ Blog
====
.. toctree::
:maxdepth: 1
:maxdepth: 2
:caption: Contents
python3
admin

View file

@ -13,7 +13,7 @@ Private engines
To solve this issue private engines were introduced in :pull:`1823`.
A new option was added to engines named `tokens`. It expects a list
of strings. If the user making a request presents one of the tokens
of an engine, he/she is able to access information about the engine
of an engine, they can access information about the engine
and make search requests.
Example configuration to restrict access to the Arch Linux Wiki engine:

View file

@ -0,0 +1,52 @@
.. START create user
.. tabs::
.. group-tab:: bash
.. code-block:: sh
$ sudo -H useradd --shell /bin/bash --system \\
--home-dir "$SERVICE_HOME" \\
--comment "Privacy-respecting metasearch engine" $SERVICE_USER
$ sudo -H mkdir "$SERVICE_HOME"
$ sudo -H chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
.. END create user
.. START install go
.. tabs::
.. group-tab:: bash
.. code-block:: bash
$ cat > "$GO_ENV" <<EOF
export GOPATH=${SERVICE_HOME}/go-apps
export PATH=\$PATH:${SERVICE_HOME}/local/go/bin:\$GOPATH/bin
EOF
$ sudo -i -u "${SERVICE_USER}"
(${SERVICE_USER}) $ echo 'source $GO_ENV' >> ~/.profile
(${SERVICE_USER}) $ mkdir ${SERVICE_HOME}/local
(${SERVICE_USER}) $ wget --progress=bar -O "${GO_TAR}" \\
"${GO_PKG_URL}"
(${SERVICE_USER}) $ tar -C ${SERVICE_HOME}/local/go -xzf "${GO_TAR}"
(${SERVICE_USER}) $ which go
${SERVICE_HOME}/local/go/bin/go
.. END install go
.. START install filtron
.. tabs::
.. group-tab:: bash
.. code-block:: bash
$ sudo -i -u "${SERVICE_USER}"
(${SERVICE_USER}) $ go get -v -u github.com/asciimoo/filtron
.. END install filtron

View file

@ -0,0 +1,52 @@
.. START create user
.. tabs::
.. group-tab:: bash
.. code-block:: sh
$ sudo -H useradd --shell /bin/bash --system \\
--home-dir "$SERVICE_HOME" \\
--comment "Privacy-respecting metasearch engine" $SERVICE_USER
$ sudo -H mkdir "$SERVICE_HOME"
$ sudo -H chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
.. END create user
.. START install go
.. tabs::
.. group-tab:: bash
.. code-block:: bash
$ cat > "$GO_ENV" <<EOF
export GOPATH=${SERVICE_HOME}/go-apps
export PATH=\$PATH:${SERVICE_HOME}/local/go/bin:\$GOPATH/bin
EOF
$ sudo -i -u "${SERVICE_USER}"
(${SERVICE_USER}) $ echo 'source $GO_ENV' >> ~/.profile
(${SERVICE_USER}) $ mkdir ${SERVICE_HOME}/local
(${SERVICE_USER}) $ wget --progress=bar -O "${GO_TAR}" \\
"${GO_PKG_URL}"
(${SERVICE_USER}) $ tar -C ${SERVICE_HOME}/local/go -xzf "${GO_TAR}"
(${SERVICE_USER}) $ which go
${SERVICE_HOME}/local/go/bin/go
.. END install go
.. START install morty
.. tabs::
.. group-tab:: bash
.. code-block:: bash
$ sudo -i -u "${SERVICE_USER}"
(${SERVICE_USER}) $ go get -v -u github.com/asciimoo/morty
.. END install morty

View file

@ -0,0 +1,192 @@
.. template evaluated by: ./utils/searx.sh docs
.. hint: all dollar-names are variables, dollar sign itself is quoted by: \\$
.. START distro-packages
.. tabs::
.. group-tab:: Ubuntu / debian
.. code-block:: sh
$ sudo -H apt-get install -y \\
${debian}
.. group-tab:: Arch Linux
.. code-block:: sh
$ sudo -H pacman -S --noconfirm \\
${arch}
.. group-tab:: Fedora / RHEL
.. code-block:: sh
$ sudo -H dnf install -y \\
${fedora}
.. END distro-packages
.. START build-packages
.. tabs::
.. group-tab:: Ubuntu / debian
.. code-block:: sh
$ sudo -H apt-get install -y \\
${debian_build}
.. group-tab:: Arch Linux
.. code-block:: sh
$ sudo -H pacman -S --noconfirm \\
${arch_build}
.. group-tab:: Fedora / RHEL
.. code-block:: sh
$ sudo -H dnf install -y \\
${fedora_build}
.. END build-packages
.. START create user
.. tabs::
.. group-tab:: bash
.. code-block:: sh
$ sudo -H useradd --shell /bin/bash --system \\
--home-dir "$SERVICE_HOME" \\
--comment "Privacy-respecting metasearch engine" $SERVICE_USER
$ sudo -H mkdir "$SERVICE_HOME"
$ sudo -H chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
.. END create user
.. START clone searx
.. tabs::
.. group-tab:: bash
.. code-block:: sh
$ sudo -H -u ${SERVICE_USER} -i
(${SERVICE_USER})$ git clone "https://github.com/asciimoo/searx.git" "$SEARX_SRC"
.. END clone searx
.. START create virtualenv
.. tabs::
.. group-tab:: bash
.. code-block:: sh
(${SERVICE_USER})$ python3 -m venv "${SEARX_PYENV}"
(${SERVICE_USER})$ echo ". ${SEARX_PYENV}/bin/activate" >> "$SERVICE_HOME/.profile"
.. END create virtualenv
.. START manage.sh update_packages
.. tabs::
.. group-tab:: bash
.. code-block:: sh
$ sudo -H -u ${SERVICE_USER} -i
(${SERVICE_USER})$ command -v python && python --version
$SEARX_PYENV/bin/python
Python 3.8.1
# update pip's boilerplate ..
pip install -U pip
pip install -U setuptools
pip install -U wheel
# jump to searx's working tree and install searx into virtualenv
(${SERVICE_USER})$ cd "$SEARX_SRC"
(${SERVICE_USER})$ pip install -e .
.. END manage.sh update_packages
.. START searx config
.. tabs::
.. group-tab:: bash
.. code-block:: sh
$ sudo -H cp "$SEARX_SRC/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
$ sudo -H sed -i -e "s/ultrasecretkey/\\$(openssl rand -hex 16)/g" "$SEARX_SETTINGS_PATH"
$ sudo -H sed -i -e "s/{instance_name}/searx@\\$(uname -n)/g" "$SEARX_SETTINGS_PATH"
.. END searx config
.. START check searx installation
.. tabs::
.. group-tab:: bash
.. code-block:: sh
# enable debug ..
$ sudo -H sed -i -e "s/debug : False/debug : True/g" "$SEARX_SETTINGS_PATH"
# start webapp
$ sudo -H -u ${SERVICE_USER} -i
(${SERVICE_USER})$ cd ${SEARX_SRC}
(${SERVICE_USER})$ export SEARX_SETTINGS_PATH="${SEARX_SETTINGS_PATH}"
(${SERVICE_USER})$ python searx/webapp.py
# disable debug
$ sudo -H sed -i -e "s/debug : True/debug : False/g" "$SEARX_SETTINGS_PATH"
Open WEB browser and visit http://$SEARX_INTERNAL_URL . If you are inside a
container or in a script, test with curl:
.. tabs::
.. group-tab:: WEB browser
.. code-block:: sh
$ xgd-open http://$SEARX_INTERNAL_URL
.. group-tab:: curl
.. code-block:: none
$ curl --location --verbose --head --insecure $SEARX_INTERNAL_URL
* Trying 127.0.0.1:8888...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8888 (#0)
> HEAD / HTTP/1.1
> Host: 127.0.0.1:8888
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
HTTP/1.0 200 OK
...
.. END check searx installation

View file

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
import sys, os
from sphinx_build_tools import load_sphinx_config
from searx.version import VERSION_STRING
from pallets_sphinx_themes import ProjectLink
from searx.brand import GIT_URL
GIT_BRANCH = os.environ.get("GIT_BRANCH", "master")
from searx.brand import SEARX_URL
from searx.brand import DOCS_URL
@ -22,6 +24,8 @@ master_doc = "index"
source_suffix = '.rst'
numfig = True
exclude_patterns = ['build-templates/*.rst']
from searx import webapp
jinja_contexts = {
'webapp': dict(**webapp.__dict__)
@ -35,7 +39,7 @@ extlinks['wiki'] = ('https://github.com/asciimoo/searx/wiki/%s', ' ')
extlinks['pull'] = ('https://github.com/asciimoo/searx/pull/%s', 'PR ')
# links to custom brand
extlinks['origin'] = (GIT_URL + '/blob/master/%s', 'git://')
extlinks['origin'] = (GIT_URL + '/blob/' + GIT_BRANCH + '/%s', 'git://')
extlinks['patch'] = (GIT_URL + '/commit/%s', '#')
extlinks['search'] = (SEARX_URL + '/%s', '#')
extlinks['docs'] = (DOCS_URL + '/%s', 'docs: ')
@ -61,6 +65,8 @@ extensions = [
"pallets_sphinx_themes",
"sphinx_issues", # https://github.com/sloria/sphinx-issues/blob/master/README.rst
"sphinxcontrib.jinja", # https://github.com/tardyp/sphinx-jinja
"sphinxcontrib.programoutput", # https://github.com/NextThought/sphinxcontrib-programoutput
'linuxdoc.kernel_include', # Implementation of the 'kernel-include' reST-directive.
'linuxdoc.rstFlatTable', # Implementation of the 'flat-table' reST-directive.
'linuxdoc.kfigure', # Sphinx extension which implements scalable image handling.
"sphinx_tabs.tabs", # https://github.com/djungelorm/sphinx-tabs
@ -112,3 +118,9 @@ html_show_sourcelink = False
latex_documents = [
(master_doc, "searx-{}.tex".format(VERSION_STRING), html_title, author, "manual")
]
# ------------------------------------------------------------------------------
# Since loadConfig overwrites settings from the global namespace, it has to be
# the last statement in the conf.py file
# ------------------------------------------------------------------------------
load_sphinx_config(globals())

View file

@ -4,6 +4,11 @@
How to contribute
=================
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
Prime directives: Privacy, Hackability
======================================

View file

@ -3,7 +3,8 @@ Developer documentation
=======================
.. toctree::
:maxdepth: 1
:maxdepth: 2
:caption: Contents
quickstart
contribution_guide

View file

@ -11,23 +11,17 @@ Makefile Targets
Before looking deeper at the targets, first read about :ref:`makefile setup`
and :ref:`make pyenv`.
To install system requirements follow :ref:`buildhosts`.
With the aim to simplify development cycles, started with :pull:`1756` a
``Makefile`` based boilerplate was added. If you are not familiar with
Makefiles, we recommend to read gnu-make_ introduction.
The usage is simple, just type ``make {target-name}`` to *build* a target.
Calling the ``help`` target gives a first overview::
Calling the ``help`` target gives a first overview (``make help``):
.. program-output:: bash -c "cd ..; make --no-print-directory help"
$ make help
test - run developer tests
docs - build documentation
docs-live - autobuild HTML documentation while editing
run - run developer instance
install - developer install (./local)
uninstall - uninstall (./local)
gh-pages - build docs & deploy on gh-pages branch
clean - drop builds and environments
...
.. contents:: Contents
:depth: 2
@ -37,27 +31,33 @@ Calling the ``help`` target gives a first overview::
.. _makefile setup:
Setup
=====
Makefile setup
==============
.. _git stash: https://git-scm.com/docs/git-stash
The main setup is done in the :origin:`Makefile`::
export GIT_URL=https://github.com/asciimoo/searx
export SEARX_URL=https://searx.me
export DOCS_URL=https://asciimoo.github.io/searx
.. sidebar:: fork & upstream
Commit changes in your (local) branch, fork or whatever, but do not push them
upstream / `git stash`_ is your friend.
The main setup is done in the :origin:`Makefile`.
.. literalinclude:: ../../Makefile
:start-after: START Makefile setup
:end-before: END Makefile setup
:GIT_URL: Changes this, to point to your searx fork.
:GIT_BRANCH: Changes this, to point to your searx branch.
:SEARX_URL: Changes this, to point to your searx instance.
:DOCS_URL: If you host your own (*brand*) documentation, change this URL.
:DOCS_URL: If you host your own (branded) documentation, change this URL.
If you change any of this build environment variables, you have to run ``make
buildenv``::
$ make buildenv
build searx/brand.py
build utils/brand.env
.. _make pyenv:
@ -170,7 +170,7 @@ e.g.:
.. code:: sh
$ make test.pep8 test.unit
$ make test.pep8 test.unit test.sh
. ./local/py3/bin/activate; ./manage.sh pep8_check
[!] Running pep8 check
. ./local/py3/bin/activate; ./manage.sh unit_tests

View file

@ -27,7 +27,7 @@ searx-ve virtualenv and install the required packages using ``manage.sh``.
cd ~/myprojects
git clone https://github.com/asciimoo/searx.git
cd searx
virtualenv searx-ve
python3 -m venv searx-ve
. ./searx-ve/bin/activate
./manage.sh update_dev_packages

View file

@ -325,8 +325,9 @@ Literal blocks
The simplest form of :duref:`literal-blocks` is a indented block introduced by
two colons (``::``). For highlighting use :dudir:`highlight` or :ref:`reST
code` directive. To include literals from external files use directive
:dudir:`literalinclude`.
code` directive. To include literals from external files use
:rst:dir:`literalinclude` or :ref:`kernel-include <kernel-include-directive>`
directive (latter one expands environment variables in the path name).
.. _reST literal:
@ -1312,9 +1313,8 @@ others are basic-tabs_ and code-tabs_. Below a *group-tab* example from
.. literalinclude:: ../admin/buildhosts.rst
:language: reST
:start-after: .. _system requirements:
:end-before: .. _system requirements END:
:start-after: .. SNIP sh lint requirements
:end-before: .. SNAP sh lint requirements
.. _math:

View file

@ -81,7 +81,7 @@ Parameters
Theme of instance.
Please note, available themes depend on an instance. It is possible that an
instance administrator deleted, created or renamed themes on his/her instance.
instance administrator deleted, created or renamed themes on their instance.
See the available options in the preferences page of the instance.
``oscar-style`` : default ``logicodev``
@ -91,7 +91,7 @@ Parameters
``oscar``.
Please note, available styles depend on an instance. It is possible that an
instance administrator deleted, created or renamed styles on his/her
instance administrator deleted, created or renamed styles on their
instance. See the available options in the preferences page of the instance.
``enabled_plugins`` : optional

View file

@ -2,7 +2,14 @@
Welcome to searx
================
Search without being tracked.
*Search without being tracked.*
Searx is a free internet metasearch engine which aggregates results from more
than 70 search services. Users are neither tracked nor profiled. Additionally,
searx can be used over Tor for online anonymity.
Get started with searx by using one of the Searx-instances_. If you don't trust
anyone, you can set up your own, see :ref:`installation`.
.. sidebar:: Features
@ -16,19 +23,14 @@ Search without being tracked.
- Hosted by organizations, such as *La Quadrature du Net*, which promote
digital rights
Searx is a free internet metasearch engine which aggregates results from more
than 70 search services. Users are neither tracked nor profiled. Additionally,
searx can be used over Tor for online anonymity.
Get started with searx by using one of the Searx-instances_. If you don't trust
anyone, you can set up your own, see :ref:`installation`.
.. toctree::
:maxdepth: 2
:caption: Contents
user/index
admin/index
dev/index
utils/index
blog/index
.. _Searx-instances: https://searx.space

19
docs/user/conf.py Normal file
View file

@ -0,0 +1,19 @@
# -*- coding: utf-8; mode: python -*-
"""Configuration for the Searx user handbook
"""
project = 'Searx User-HB'
version = release = VERSION_STRING
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index' # startdocname
, 'searx-user-hb.tex' # targetname
, '' # take title from .rst
, author # author
, 'howto' # documentclass
, False # toctree_only
),
]

View file

@ -3,7 +3,8 @@ User documentation
==================
.. toctree::
:maxdepth: 1
:maxdepth: 2
:caption: Contents
search_syntax
own-instance

View file

@ -2,8 +2,10 @@
Why use a private instance?
===========================
"Is it worth to run my own instance?" is a common question among searx users.
Before answering this question, see what options a searx user has.
*"Is it worth to run my own instance?"*
\.\. is a common question among searx users. Before answering this question,
see what options a searx user has.
Public instances are open to everyone who has access to its URL. Usually, these
are operated by unknown parties (from the users' point of view). Private
@ -42,9 +44,9 @@ hidden from visited result pages.
What are the consequences of using public instances?
----------------------------------------------------
If someone uses a public instance, he/she has to trust the administrator of that
If someone uses a public instance, they have to trust the administrator of that
instance. This means that the user of the public instance does not know whether
his/her requests are logged, aggregated and sent or sold to a third party.
their requests are logged, aggregated and sent or sold to a third party.
Also, public instances without proper protection are more vulnerable to abusing
the search service, In this case the external service in exchange returns

View file

@ -1,3 +0,0 @@
:orphan:
This page page has been moved to `searx.space <https://searx.space/>`__

80
docs/utils/filtron.sh.rst Normal file
View file

@ -0,0 +1,80 @@
.. _filtron.sh:
====================
``utils/filtron.sh``
====================
.. sidebar:: further reading
- :ref:`searx filtron`
- :ref:`architecture`
- :ref:`installation` (:ref:`nginx <installation nginx>` & :ref:`apache
<installation apache>`)
.. _Go: https://golang.org/
.. _filtron: https://github.com/asciimoo/filtron
.. _filtron README: https://github.com/asciimoo/filtron/blob/master/README.md
To simplify installation and maintenance of a filtron instance you can use the
script :origin:`utils/filtron.sh`. In most cases you will install filtron_
simply by running the command:
.. code:: bash
sudo -H ./utils/filtron.sh install all
The script adds a ``${SERVICE_USER}`` (default:``filtron``) and installs filtron_
into this user account:
#. Create a separated user account (``filtron``).
#. Download and install Go_ binary in user's $HOME (``~filtron``).
#. Install filtron with the package management from Go_ (``go get -v -u
github.com/asciimoo/filtron``)
#. Setup a proper rule configuration :origin:`[ref]
<utils/templates/etc/filtron/rules.json>` (``/etc/filtron/rules.json``).
#. Setup a systemd service unit :origin:`[ref]
<utils/templates/lib/systemd/system/filtron.service>`
(``/lib/systemd/system/filtron.service``).
Create user
===========
.. kernel-include:: $DOCS_BUILD/includes/filtron.rst
:start-after: START create user
:end-before: END create user
Install go
==========
.. kernel-include:: $DOCS_BUILD/includes/filtron.rst
:start-after: START install go
:end-before: END install go
Install filtron
===============
Install :origin:`rules.json <utils/templates/etc/filtron/rules.json>` at
``/etc/filtron/rules.json`` (see :ref:`Sample configuration of filtron`) and
install filtron software and systemd unit:
.. kernel-include:: $DOCS_BUILD/includes/filtron.rst
:start-after: START install filtron
:end-before: END install filtron
.. kernel-include:: $DOCS_BUILD/includes/filtron.rst
:start-after: START install systemd unit
:end-before: END install systemd unit
.. _filtron.sh overview:
Overview
========
The ``--help`` output of the script is largely self-explanatory
(:ref:`toolboxing common`):
.. program-output:: ../utils/filtron.sh --help

53
docs/utils/index.rst Normal file
View file

@ -0,0 +1,53 @@
.. _searx_utils:
.. _toolboxing:
=======================
Tooling box ``utils/*``
=======================
In the folder :origin:`utils/` we maintain some tools useful for admins and
developers.
.. toctree::
:maxdepth: 2
:caption: Contents
searx.sh
filtron.sh
morty.sh
lxc.sh
.. _toolboxing common:
Common commands & environment
=============================
Scripts to maintain services often dispose of common commands and environments.
``shell`` : command
Opens a shell from the service user ``${SERVICE_USSR}``, very helpful for
troubleshooting.
``inspect service`` : command
Shows status and log of the service, most often you have a option to enable
more verbose debug logs. Very helpful for debugging, but be careful not to
enable debugging in a production environment!
``FORCE_TIMEOUT`` : environment
Sets timeout for interactive prompts. If you want to run a script in batch
job, with defaults choices, set ``FORCE_TIMEOUT=0``. By example; to install a
reverse proxy for filtron on all containers of the :ref:`searx suite
<lxc-searx.env>` use ::
sudo -H ./utils/lxc.sh cmd -- FORCE_TIMEOUT=0 ./utils/filtron.sh apache install
.. _toolboxing setup:
Tooling box setup
=================
The main setup is done in the :origin:`.config.sh` (read also :ref:`makefile
setup`).
.. literalinclude:: ../../.config.sh
:language: bash

148
docs/utils/lxc.sh.rst Normal file
View file

@ -0,0 +1,148 @@
.. _snap: https://snapcraft.io
.. _snapcraft LXD: https://snapcraft.io/lxd
.. _LXC/LXD Image Server: https://uk.images.linuxcontainers.org/
.. _LXC: https://linuxcontainers.org/lxc/introduction/
.. _LXD: https://linuxcontainers.org/lxd/introduction/
.. _`LXD@github`: https://github.com/lxc/lxd
.. _archlinux: https://www.archlinux.org/
.. _lxc.sh:
================
``utils/lxc.sh``
================
.. sidebar:: further reading
- snap_, `snapcraft LXD`_
- LXC_, LXD_
- `LXC/LXD Image Server`_
- `LXD@github`_
With the use of *Linux Containers* (LXC_) we can scale our tasks over a stack of
containers, what we call the: *lxc suite*. The *searx suite*
(:origin:`lxc-searx.env <utils/lxc-searx.env>`) is loaded by default, every time
you start the ``lxc.sh`` script (*you do not need to care about*).
Before you can start with containers, you need to install and initiate LXD_
once::
$ snap install lxd
$ lxd init --auto
To make use of the containers from the *searx suite*, you have to build the
:ref:`LXC suite containers <lxc.sh help>` initial. But be warned, **this might
take some time**::
$ sudo -H ./utils/lxc.sh build
A cup of coffee later, your LXC suite is build up and you can run whatever task
you want / in a selected or even in all :ref:`LXC suite containers <lxc.sh
help>`. If you do not want to build all containers, **you can build just
one**::
$ sudo -H ./utils/lxc.sh build searx-ubu1804
*Good to know ...*
Eeach container shares the root folder of the repository and the
command ``utils/lxc.sh cmd`` **handles relative path names transparent**,
compare output of::
$ sudo -H ./utils/lxc.sh cmd -- ls -la Makefile
...
In the containers, you can run what ever you want, e.g. to start a bash use::
$ sudo -H ./utils/lxc.sh cmd searx-ubu1804 bash
INFO: [searx-ubu1804] bash
root@searx-ubu1804:/share/searx#
If there comes the time you want to **get rid off all** the containers and
**clean up local images** just type::
$ sudo -H ./utils/lxc.sh remove
$ sudo -H ./utils/lxc.sh remove images
Install suite
=============
To install the complete :ref:`searx suite (includes searx, morty & filtron)
<lxc-searx.env>` into all LXC_ use::
$ sudo -H ./utils/lxc.sh install suite
The command above installs a searx suite (see :ref:`installation scripts`). To
get the IP (URL) of the filtron service in the containers use ``show suite``
command. To test instances from containers just open the URLs in your
WEB-Browser::
$ sudo ./utils/lxc.sh show suite | grep filtron
[searx-ubu1604] INFO: (eth0) filtron: http://n.n.n.246:4004/ http://n.n.n.246/searx
[searx-ubu1804] INFO: (eth0) filtron: http://n.n.n.147:4004/ http://n.n.n.147/searx
[searx-ubu1910] INFO: (eth0) filtron: http://n.n.n.140:4004/ http://n.n.n.140/searx
[searx-ubu2004] INFO: (eth0) filtron: http://n.n.n.18:4004/ http://n.n.n.18/searx
[searx-fedora31] INFO: (eth0) filtron: http://n.n.n.46:4004/ http://n.n.n.46/searx
[searx-archlinux] INFO: (eth0) filtron: http://n.n.n.32:4004/ http://n.n.n.32/searx
To :ref:`install a nginx <installation nginx>` reverse proxy for filtron and
morty use (or alternatively use :ref:`apache <installation apache>`)::
sudo -H ./utils/lxc.sh cmd -- FORCE_TIMEOUT=0 ./utils/filtron.sh nginx install
sudo -H ./utils/lxc.sh cmd -- FORCE_TIMEOUT=0 ./utils/morty.sh nginx install
Running commands
================
**Inside containers, you can use make or run scripts** from the
:ref:`toolboxing`. By example: to setup a :ref:`buildhosts` and run the
Makefile target ``test`` in the archlinux_ container::
sudo -H ./utils/lxc.sh cmd searx-archlinux ./utils/searx.sh install buildhost
sudo -H ./utils/lxc.sh cmd searx-archlinux make test
Setup searx buildhost
=====================
You can **install the searx buildhost environment** into one or all containers.
The installation procedure to set up a :ref:`build host<buildhosts>` takes its
time. Installation in all containers will take more time (time for another cup
of coffee).::
sudo -H ./utils/lxc.sh cmd -- ./utils/searx.sh install buildhost
To build (live) documentation inside a archlinux_ container::
sudo -H ./utils/lxc.sh cmd searx-archlinux make docs-clean docs-live
...
[I 200331 15:00:42 server:296] Serving on http://0.0.0.0:8080
To get IP of the container and the port number *live docs* is listening::
$ sudo ./utils/lxc.sh show suite | grep docs-live
...
[searx-archlinux] INFO: (eth0) docs-live: http://n.n.n.12:8080/
.. _lxc.sh help:
Overview
========
The ``--help`` output of the script is largely self-explanatory:
.. program-output:: ../utils/lxc.sh --help
.. _lxc-searx.env:
searx suite
===========
.. literalinclude:: ../../utils/lxc-searx.env
:language: bash

80
docs/utils/morty.sh.rst Normal file
View file

@ -0,0 +1,80 @@
.. _morty: https://github.com/asciimoo/morty
.. _morty's README: https://github.com/asciimoo/morty
.. _Go: https://golang.org/
.. _morty.sh:
==================
``utils/morty.sh``
==================
.. sidebar:: further reading
- :ref:`architecture`
- :ref:`installation` (:ref:`nginx <installation nginx>` & :ref:`apache
<installation apache>`)
- :ref:`searx morty`
To simplify installation and maintenance of a morty_ instance you can use the
script :origin:`utils/morty.sh`. In most cases you will install morty_ simply by
running the command:
.. code:: bash
sudo -H ./utils/morty.sh install all
The script adds a ``${SERVICE_USER}`` (default:``morty``) and installs morty_
into this user account:
#. Create a separated user account (``morty``).
#. Download and install Go_ binary in user's $HOME (``~morty``).
#. Install morty_ with the package management from Go_ (``go get -v -u
github.com/asciimoo/morty``)
#. Setup a systemd service unit :origin:`[ref]
<utils/templates/lib/systemd/system/morty.service>`
(``/lib/systemd/system/morty.service``).
.. hint::
To add morty to your searx instance read chapter :ref:`searx morty`.
Create user
===========
.. kernel-include:: $DOCS_BUILD/includes/morty.rst
:start-after: START create user
:end-before: END create user
Install go
==========
.. kernel-include:: $DOCS_BUILD/includes/morty.rst
:start-after: START install go
:end-before: END install go
Install morty
=============
Install morty software and systemd unit:
.. kernel-include:: $DOCS_BUILD/includes/morty.rst
:start-after: START install morty
:end-before: END install morty
.. kernel-include:: $DOCS_BUILD/includes/morty.rst
:start-after: START install systemd unit
:end-before: END install systemd unit
.. _morty.sh overview:
Overview
========
The ``--help`` output of the script is largely self-explanatory
(:ref:`toolboxing common`):
.. program-output:: ../utils/morty.sh --help

39
docs/utils/searx.sh.rst Normal file
View file

@ -0,0 +1,39 @@
.. _searx.sh:
==================
``utils/searx.sh``
==================
.. sidebar:: further reading
- :ref:`architecture`
- :ref:`installation`
- :ref:`installation nginx`
- :ref:`installation apache`
To simplify installation and maintenance of a searx instance you can use the
script :origin:`utils/searx.sh`.
Install
=======
In most cases you will install searx simply by running the command:
.. code:: bash
sudo -H ./utils/searx.sh install all
The script adds a ``${SERVICE_USER}`` (default:``searx``) and installs searx
into this user account. The installation is described in chapter
:ref:`installation basic`.
.. _intranet reverse proxy:
Overview
========
The ``--help`` output of the script is largely self-explanatory
(:ref:`toolboxing common`):
.. program-output:: ../utils/searx.sh --help

View file

@ -15,3 +15,5 @@ selenium==3.141.0
linuxdoc @ git+http://github.com/return42/linuxdoc.git
sphinx-jinja
sphinx-tabs
sphinxcontrib-programoutput
twine

View file

@ -1,4 +1,5 @@
GIT_URL = 'https://github.com/asciimoo/searx'
GIT_BRANCH = 'master'
ISSUE_URL = 'https://github.com/asciimoo/searx/issues'
SEARX_URL = 'https://searx.me'
DOCS_URL = 'https://asciimoo.github.io/searx'

View file

@ -117,14 +117,10 @@ def response(resp):
'img_format': img_format,
'template': 'images.html'
}
try:
result['author'] = author
result['title'] = title
result['content'] = content
except:
result['author'] = ''
result['title'] = ''
result['content'] = ''
result['author'] = author.encode('utf-8', 'ignore').decode('utf-8')
result['source'] = source.encode('utf-8', 'ignore').decode('utf-8')
result['title'] = title.encode('utf-8', 'ignore').decode('utf-8')
result['content'] = content.encode('utf-8', 'ignore').decode('utf-8')
results.append(result)
return results

View file

@ -33,7 +33,7 @@ supported_languages_url = 'https://search.yahoo.com/web/advanced'
results_xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' Sr ')]"
url_xpath = './/h3/a/@href'
title_xpath = './/h3/a'
content_xpath = './/div[@class="compText aAbs"]'
content_xpath = './/div[contains(@class, "compText")]'
suggestion_xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' AlsoTry ')]//a"
time_range_dict = {'day': ['1d', 'd'],

View file

@ -6,19 +6,37 @@ $(document).ready(function() {
});
$(document.getElementById($(this).attr("for"))).prop('checked', true);
if($('#q').val()) {
if (getHttpRequest() == "GET") {
$('#search_form').attr('action', $('#search_form').serialize());
}
$('#search_form').submit();
}
return false;
});
$('#time-range').change(function(e) {
if($('#q').val()) {
if (getHttpRequest() == "GET") {
$('#search_form').attr('action', $('#search_form').serialize());
}
$('#search_form').submit();
}
});
$('#language').change(function(e) {
if($('#q').val()) {
if (getHttpRequest() == "GET") {
$('#search_form').attr('action', $('#search_form').serialize());
}
$('#search_form').submit();
}
});
}
});
function getHttpRequest() {
httpRequest = "POST";
urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('method')) {
httpRequest = urlParams.get('method');
}
return httpRequest;
}

View file

@ -70,7 +70,21 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
opacity: 0;
position: absolute;
}
.onoffswitch-checkbox:before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
margin-right: 10px;
position: absolute;
left: 0;
bottom: 1px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 0px;
}
.onoffswitch-label {
display: block;
@ -104,7 +118,7 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
top: 0;
bottom: 0;
right: 0px;
border: 2px solid #FFFFFF !important;
border: 2px solid #FFFFFF;
border-radius: 50px !important;
transition: all 0.3s ease-in 0s;
}
@ -115,6 +129,9 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
right: 71px;
background-color: #A1A1A1;
}
.onoffswitch-checkbox:focus + .onoffswitch-label .onoffswitch-switch {
border: 3px solid #444444;
}
.result_header {
margin-top: 0px;
margin-bottom: 2px;
@ -377,6 +394,17 @@ Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
.search-margin {
margin-bottom: 0.6em;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
/* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
/* added line */
}
#advanced-search-container {
display: none;
text-align: left;
@ -407,8 +435,8 @@ Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
font-weight: bold;
border-bottom: #01d7d4 5px solid;
}
#check-advanced {
display: none;
#check-advanced:focus + label {
text-decoration: underline;
}
#check-advanced:checked ~ #advanced-search-container {
display: block;

File diff suppressed because one or more lines are too long

View file

@ -43,7 +43,21 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
opacity: 0;
position: absolute;
}
.onoffswitch-checkbox:before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
margin-right: 10px;
position: absolute;
left: 0;
bottom: 1px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 0px;
}
.onoffswitch-label {
display: block;
@ -77,7 +91,7 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
top: 0;
bottom: 0;
right: 0px;
border: 2px solid #FFFFFF !important;
border: 2px solid #FFFFFF;
border-radius: 50px !important;
transition: all 0.3s ease-in 0s;
}
@ -88,6 +102,9 @@ input[type=checkbox]:not(:checked) + .label_hide_if_checked + .label_hide_if_not
right: 71px;
background-color: #A1A1A1;
}
.onoffswitch-checkbox:focus + .onoffswitch-label .onoffswitch-switch {
border: 3px solid #444444;
}
.result_header {
margin-top: 0px;
margin-bottom: 2px;
@ -350,6 +367,17 @@ Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
.search-margin {
margin-bottom: 0.6em;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
/* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
/* added line */
}
#advanced-search-container {
display: none;
text-align: left;
@ -380,8 +408,8 @@ Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
font-weight: bold;
border-bottom: #01d7d4 5px solid;
}
#check-advanced {
display: none;
#check-advanced:focus + label {
text-decoration: underline;
}
#check-advanced:checked ~ #advanced-search-container {
display: block;

File diff suppressed because one or more lines are too long

View file

@ -291,7 +291,7 @@ $(document).ready(function(){
}
})
.fail(function() {
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">"+could_not_load+"</p>");
});
}
}

File diff suppressed because one or more lines are too long

View file

@ -90,7 +90,7 @@ $(document).ready(function(){
}
})
.fail(function() {
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">could not load data!</p>");
$(result_table_loadicon).html($(result_table_loadicon).html() + "<p class=\"text-muted\">"+could_not_load+"</p>");
});
}
}

View file

@ -31,8 +31,8 @@
}
}
#check-advanced {
display: none;
#check-advanced:focus + label {
text-decoration: underline;
}
#check-advanced:checked ~ #advanced-search-container {

View file

@ -9,7 +9,21 @@
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
opacity: 0;
position: absolute;
}
.onoffswitch-checkbox:before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
margin-right: 10px;
position: absolute;
left: 0;
bottom: 1px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 0px;
}
.onoffswitch-label {
display: block;
@ -44,7 +58,7 @@
top: 0;
bottom: 0;
right: 0px;
border: 2px solid #FFFFFF !important;
border: 2px solid #FFFFFF;
border-radius: 50px !important;
transition: all 0.3s ease-in 0s;
}
@ -55,3 +69,6 @@
right: 71px;
background-color: #A1A1A1;
}
.onoffswitch-checkbox:focus + .onoffswitch-label .onoffswitch-switch {
border: 3px solid #444444;
}

View file

@ -78,3 +78,13 @@ Ny0yNFQxMToxNTowMCswMjowMP7RDgQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb
.search-margin {
margin-bottom: 0.6em;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}

View file

@ -1,4 +1,4 @@
/*! simple/searx.min.js | 06-08-2019 | https://github.com/asciimoo/searx */
/*! simple/searx.min.js | 15-06-2020 | */
(function(t,e){"use strict";var a=e.currentScript||function(){var t=e.getElementsByTagName("script");return t[t.length-1]}();t.searx={touch:"ontouchstart"in t||t.DocumentTouch&&document instanceof DocumentTouch||false,method:a.getAttribute("data-method"),autocompleter:a.getAttribute("data-autocompleter")==="true",search_on_category_select:a.getAttribute("data-search-on-category-select")==="true",infinite_scroll:a.getAttribute("data-infinite-scroll")==="true",static_path:a.getAttribute("data-static-path"),no_item_found:a.getAttribute("data-no-item-found")};e.getElementsByTagName("html")[0].className=t.searx.touch?"js touch":"js"})(window,document);
//# sourceMappingURL=searx.head.min.js.map

View file

@ -1314,7 +1314,7 @@ module.exports = AutoComplete;
})
.catch(function() {
result_table_loadicon.classList.remove('invisible');
result_table_loadicon.innerHTML = "could not load data!";
result_table_loadicon.innerHTML = could_not_load;
});
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -97,7 +97,7 @@
})
.catch(function() {
result_table_loadicon.classList.remove('invisible');
result_table_loadicon.innerHTML = "could not load data!";
result_table_loadicon.innerHTML = could_not_load;
});
}
}

View file

@ -59,12 +59,16 @@
<h2 id='add to browser'>How to set as the default search engine?</h2>
<dt>Firefox</dt>
<p>
Searx supports <a href="https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md">OpenSearch</a>.
For more information on changing your default search engine, see your browser's documentation:
</p>
<dd>
<a href="#" onclick="window.external.AddSearchProvider(window.location.protocol + '//' + window.location.host + '{{ url_for('opensearch') }}');">Install</a>
searx as a search engine on any version of Firefox! (javascript required)
</dd>
<ul>
<li><a href="https://support.mozilla.org/en-US/kb/add-or-remove-search-engine-firefox">Firefox</a></li>
<li><a href="https://support.microsoft.com/en-us/help/4028574/microsoft-edge-change-the-default-search-engine" >Microsoft Egde</a></li>
<li>Chrome based browsers <a href="https://www.chromium.org/tab-to-search">only add websites that the user navigates to without a path.</a>
</ul>
<h2>Where to find anonymous usage statistics of this instance ?</h2>

View file

@ -6,23 +6,13 @@
<Image>{{ urljoin(host, url_for('static', filename='img/favicon.png')) }}</Image>
<LongName>searx metasearch</LongName>
{% if opensearch_method == 'get' %}
<Url type="text/html" method="get" template="{{ host }}search?q={searchTerms}"/>
{% if autocomplete %}
<Url type="application/x-suggestions+json" method="get" template="{{ host }}autocompleter">
<Param name="format" value="x-suggestions" />
<Param name="q" value="{searchTerms}" />
</Url>
{% endif %}
<Url rel="results" type="text/html" method="get" template="{{ host }}search?q={searchTerms}"/>
{% else %}
<Url type="text/html" method="post" template="{{ host }}">
<Param name="q" value="{searchTerms}" />
</Url>
{% if autocomplete %}
<!-- TODO, POST REQUEST doesn't work -->
<Url type="application/x-suggestions+json" method="get" template="{{ host }}autocompleter">
<Param name="format" value="x-suggestions" />
<Url rel="results" type="text/html" method="post" template="{{ host }}">
<Param name="q" value="{searchTerms}" />
</Url>
{% endif %}
{% if autocomplete %}
<Url rel="suggestions" type="application/json" template="{{ host }}autocompleter"/>
{% endif %}
</OpenSearchDescription>

View file

@ -0,0 +1 @@
var could_not_load = '{{ _('could not load data') }}!';

View file

@ -1,4 +1,4 @@
<input type="checkbox" name="advanced_search" id="check-advanced" {% if advanced_search %} checked="checked"{% endif %}>
<input type="checkbox" name="advanced_search" class="visually-hidden" id="check-advanced" {% if advanced_search %} checked="checked"{% endif %}>
<label for="check-advanced">{{- "" -}}
<span class="glyphicon glyphicon-cog"></span>
{{- _('Advanced settings') -}}

View file

@ -1,6 +1,6 @@
{% from 'oscar/macros.html' import icon %}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"{% if rtl %} dir="rtl"{% endif %}>
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ preferences.get_value('locale') }}" xml:lang="{{ preferences.get_value('locale') }}"{% if rtl %} dir="rtl"{% endif %}>
<head>
<meta charset="UTF-8" />
<meta name="description" content="searx - a privacy-respecting, hackable metasearch engine" />
@ -8,9 +8,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="generator" content="searx/{{ searx_version }}">
<meta name="referrer" content="no-referrer">
<meta name="viewport" content="width=device-width, initial-scale=1 , maximum-scale=1.0, user-scalable=1" />
<meta name="viewport" content="width=device-width, initial-scale=1 , maximum-scale=2.0, user-scalable=1" />
{% block meta %}{% endblock %}
<script src="{{ url_for('js_translations') }}"></script>
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" type="text/css" />
{% if preferences.get_value('oscar-style') -%}

View file

@ -6,10 +6,10 @@
{% if cookies['oscar-style'] == 'pointhi' %}
<h1 class="text-hide center-block"><img class="center-block img-responsive" src="{{ url_for('static', filename='img/searx_logo.png') }}" alt="searx logo"/>searx</h1>
{% else %}
<h1 class="text-hide center-block" id="main-logo">
<div class="text-hide center-block" id="main-logo">
<img class="center-block img-responsive" src="{{ url_for('static', filename='img/logo_searx_a.png') }}" alt="searx logo" />
searx
</h1>
</div>
{% endif %}
</div>
</div>

View file

@ -5,7 +5,7 @@
{% for u in infobox.urls %}{% if u.official %} <a href="{{ u.url }}">{{ u.domain }}</a>{% endif %}{% endfor %}
</div>
<div class="panel-body">
{% if infobox.img_src %}<img class="img-responsive center-block infobox_part" src="{{ image_proxify(infobox.img_src) }}" alt="{{ infobox.infobox }}" />{% endif %}
{% if infobox.img_src %}<img class="img-responsive center-block infobox_part" src="{{ image_proxify(infobox.img_src) }}" />{% endif %}
{% if infobox.content %}<bdi><p class="infobox_part">{{ infobox.content | safe }}</p></bdi>{% endif %}

View file

@ -1,3 +1,4 @@
<label class="visually-hidden" for="language">{{ _('Language') }}</label>
<select class="language custom-select form-control" id="language" name="language" accesskey="l">
<option value="all" {% if current_language == 'all' %}selected="selected"{% endif %}>{{ _('Default language') }}</option>
{%- for lang_id,lang_name,country_name,english_name in language_codes | sort(attribute=1) -%}

View file

@ -60,15 +60,15 @@
{%- endif %}
{%- endmacro %}
{% macro preferences_item_header(info, label, rtl) -%}
{% macro preferences_item_header(info, label, rtl, id) -%}
{% if rtl %}
<div class="row form-group">
<label class="col-sm-3 col-md-2 pull-right">{{ label }}</label>
<label class="col-sm-3 col-md-2 pull-right"{% if id %} for="{{id}}"{% endif %}>{{ label }}</label>
<span class="col-sm-5 col-md-6 help-block pull-left">{{ info }}</span>
<div class="col-sm-4 col-md-4">
{% else %}
<div class="row form-group">
<label class="col-sm-3 col-md-2">{{ label }}</label>
<label class="col-sm-3 col-md-2"{% if id %} for="{{id}}"{% endif %}>{{ label }}</label>
<div class="col-sm-4 col-md-4">
{% endif %}
{%- endmacro %}
@ -91,6 +91,7 @@
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
<label class="visually-hidden" for="{{ id }}">{{ _('Allow') }}</label>
</div>
{%- endmacro %}

View file

@ -30,9 +30,9 @@
<div class="col-sm-11 col-md-10">
{% include 'oscar/categories.html' %}
</div>
<label class="col-sm-3 col-md-2">{{ _('Default categories') }}</label>
<label class="col-sm-3 col-md-2" for="categories">{{ _('Default categories') }}</label>
{% else %}
<label class="col-sm-3 col-md-2">{{ _('Default categories') }}</label>
<label class="col-sm-3 col-md-2" for="categories">{{ _('Default categories') }}</label>
<div class="col-sm-11 col-md-10 search-categories">
{% include 'oscar/categories.html' %}
</div>
@ -40,14 +40,14 @@
</div>
{% set language_label = _('Search language') %}
{% set language_info = _('What language do you prefer for search?') %}
{{ preferences_item_header(language_info, language_label, rtl) }}
{{ preferences_item_header(language_info, language_label, rtl, 'language') }}
{% include 'oscar/languages.html' %}
{{ preferences_item_footer(language_info, language_label, rtl) }}
{% set locale_label = _('Interface language') %}
{% set locale_info = _('Change the language of the layout') %}
{{ preferences_item_header(locale_info, locale_label, rtl) }}
<select class="form-control" name='locale'>
{{ preferences_item_header(locale_info, locale_label, rtl, 'locale') }}
<select class="form-control" name="locale" id="locale">
{% for locale_id,locale_name in locales.items() | sort %}
<option value="{{ locale_id }}" {% if locale_id == current_locale %}selected="selected"{% endif %}>{{ locale_name }}</option>
{% endfor %}
@ -56,8 +56,8 @@
{% set autocomplete_label = _('Autocomplete') %}
{% set autocomplete_info = _('Find stuff as you type') %}
{{ preferences_item_header(autocomplete_info, autocomplete_label, rtl) }}
<select class="form-control" name="autocomplete">
{{ preferences_item_header(autocomplete_info, autocomplete_label, rtl, 'autocomplete') }}
<select class="form-control" name="autocomplete" id="autocomplete">
<option value=""> - </option>
{% for backend in autocomplete_backends %}
<option value="{{ backend }}" {% if backend == autocomplete %}selected="selected"{% endif %}>{{ backend }}</option>
@ -67,8 +67,8 @@
{% set image_proxy_label = _('Image proxy') %}
{% set image_proxy_info = _('Proxying image results through searx') %}
{{ preferences_item_header(image_proxy_info, image_proxy_label, rtl) }}
<select class="form-control" name='image_proxy'>
{{ preferences_item_header(image_proxy_info, image_proxy_label, rtl, 'image_proxy') }}
<select class="form-control" name="image_proxy" id="image_proxy">
<option value="1" {% if image_proxy %}selected="selected"{% endif %}>{{ _('Enabled') }}</option>
<option value="" {% if not image_proxy %}selected="selected"{% endif %}>{{ _('Disabled')}}</option>
</select>
@ -76,8 +76,8 @@
{% set method_label = _('Method') %}
{% set method_info = _('Change how forms are submited, <a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods" rel="external">learn more about request methods</a>') %}
{{ preferences_item_header(method_info, method_label, rtl) }}
<select class="form-control" name='method'>
{{ preferences_item_header(method_info, method_label, rtl, 'method') }}
<select class="form-control" name="method" id="method">
<option value="POST" {% if method == 'POST' %}selected="selected"{% endif %}>POST</option>
<option value="GET" {% if method == 'GET' %}selected="selected"{% endif %}>GET</option>
</select>
@ -85,8 +85,8 @@
{% set safesearch_label = _('SafeSearch') %}
{% set safesearch_info = _('Filter content') %}
{{ preferences_item_header(safesearch_info, safesearch_label, rtl) }}
<select class="form-control" name='safesearch'>
{{ preferences_item_header(safesearch_info, safesearch_label, rtl, 'safesearch') }}
<select class="form-control" name="safesearch" id="safesearch">
<option value="2" {% if safesearch == '2' %}selected="selected"{% endif %}>{{ _('Strict') }}</option>
<option value="1" {% if safesearch == '1' %}selected="selected"{% endif %}>{{ _('Moderate') }}</option>
<option value="0" {% if safesearch == '0' %}selected="selected"{% endif %}>{{ _('None') }}</option>
@ -95,16 +95,16 @@
{% set theme_label = _('Themes') %}
{% set theme_info = _('Change searx layout') %}
{{ preferences_item_header(theme_info, theme_label, rtl) }}
<select class="form-control" name="theme">
{{ preferences_item_header(theme_info, theme_label, rtl, 'theme') }}
<select class="form-control" name="theme" id="theme">
{% for name in themes %}
<option value="{{ name }}" {% if name == theme %}selected="selected"{% endif %}>{{ name }}</option>
{% endfor %}
</select>
{{ preferences_item_footer(theme_info, theme_label, rtl) }}
{{ preferences_item_header(_('Choose style for this theme'), _('Style'), rtl) }}
<select class="form-control" name='oscar-style'>
{{ preferences_item_header(_('Choose style for this theme'), _('Style'), rtl, 'oscar_style') }}
<select class="form-control" name="oscar-style" id="oscar_style">
<option value="logicodev" >Logicodev</option>
<option value="pointhi" {% if preferences.get_value('oscar-style') == 'pointhi' %}selected="selected"{% endif %}>Pointhi</option>
<option value="logicodev-dark" {% if preferences.get_value('oscar-style') == 'logicodev-dark' %}selected="selected"{% endif %}>Logicodev dark</option>
@ -113,8 +113,8 @@
{% set label = _('Results on new tabs') %}
{% set info = _('Open result links on new browser tabs') %}
{{ preferences_item_header(info, label, rtl) }}
<select class="form-control" name='results_on_new_tab'>
{{ preferences_item_header(info, label, rtl, 'results_on_new_tab') }}
<select class="form-control" name="results_on_new_tab" id="results_on_new_tab">
<option value="1" {% if results_on_new_tab %}selected="selected"{% endif %}>{{ _('On') }}</option>
<option value="0" {% if not results_on_new_tab %}selected="selected"{% endif %}>{{ _('Off')}}</option>
</select>
@ -122,8 +122,8 @@
{% set label = _('Open Access DOI resolver') %}
{% set info = _('Redirect to open-access versions of publications when available (plugin required)') %}
{{ preferences_item_header(info, label, rtl) }}
<select class="form-control" id='doi_resolver' name='doi_resolver'>
{{ preferences_item_header(info, label, rtl, 'doi_resolver') }}
<select class="form-control" name="doi_resolver" id="doi_resolver">
{% for doi_resolver_name,doi_resolver_url in doi_resolvers.items() %}
<option value="{{ doi_resolver_name }}" {% if doi_resolver_name == current_doi_resolver %}selected="selected"{% endif %}>
{{ doi_resolver_name }} - {{ doi_resolver_url }}
@ -134,8 +134,8 @@
{% set label = _('Engine tokens') %}
{% set info = _('Access tokens for private engines') %}
{{ preferences_item_header(info, label, rtl) }}
<input class="form-control" id='tokens' name='tokens' value='{{ preferences.tokens.get_value() }}'/>
{{ preferences_item_header(info, label, rtl, 'tokens') }}
<input class="form-control" id="tokens" name="tokens" value='{{ preferences.tokens.get_value() }}'/>
{{ preferences_item_footer(info, label, rtl) }}
</div>
</fieldset>
@ -173,23 +173,23 @@
<table class="table table-hover table-condensed table-striped">
<tr>
{% if not rtl %}
<th>{{ _("Allow") }}</th>
<th>{{ _("Engine name") }}</th>
<th>{{ _("Shortcut") }}</th>
<th>{{ _("Selected language") }}</th>
<th>{{ _("SafeSearch") }}</th>
<th>{{ _("Time range") }}</th>
<th>{{ _("Avg. time") }}</th>
<th>{{ _("Max time") }}</th>
<th scope="col">{{ _("Allow") }}</th>
<th scope="col">{{ _("Engine name") }}</th>
<th scope="col">{{ _("Shortcut") }}</th>
<th scope="col">{{ _("Selected language") }}</th>
<th scope="col">{{ _("SafeSearch") }}</th>
<th scope="col">{{ _("Time range") }}</th>
<th scope="col">{{ _("Avg. time") }}</th>
<th scope="col">{{ _("Max time") }}</th>
{% else %}
<th class="text-right">{{ _("Max time") }}</th>
<th class="text-right">{{ _("Avg. time") }}</th>
<th class="text-right">{{ _("Time range") }}</th>
<th class="text-right">{{ _("SafeSearch") }}</th>
<th class="text-right">{{ _("Selected language") }}</th>
<th class="text-right">{{ _("Shortcut") }}</th>
<th class="text-right">{{ _("Engine name") }}</th>
<th class="text-right">{{ _("Allow") }}</th>
<th scope="col" class="text-right">{{ _("Max time") }}</th>
<th scope="col" class="text-right">{{ _("Avg. time") }}</th>
<th scope="col" class="text-right">{{ _("Time range") }}</th>
<th scope="col" class="text-right">{{ _("SafeSearch") }}</th>
<th scope="col" class="text-right">{{ _("Selected language") }}</th>
<th scope="col" class="text-right">{{ _("Shortcut") }}</th>
<th scope="col" class="text-right">{{ _("Engine name") }}</th>
<th scope="col" class="text-right">{{ _("Allow") }}</th>
{% endif %}
</tr>
{% for search_engine in engines_by_category[categ] %}
@ -199,21 +199,21 @@
<td class="onoff-checkbox">
{{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
</td>
<th>{{ search_engine.name }}</th>
<th scope="row">{{ search_engine.name }}</th>
<td class="name">{{ shortcuts[search_engine.name] }}</td>
<td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{% if stats[search_engine.name]['warn_time'] %}{{ icon('exclamation-sign')}} {% endif %}{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{% if stats[search_engine.name]['warn_timeout'] %}{{ icon('exclamation-sign') }} {% endif %}{{ search_engine.timeout }}</td>
{% else %}
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_timeout'] else '' }}">{{ search_engine.timeout }}{% if stats[search_engine.name]['warn_time'] %} {{ icon('exclamation-sign')}}{% endif %}</td>
<td class="{{ 'danger' if stats[search_engine.name]['warn_time'] else '' }}">{{ 'N/A' if stats[search_engine.name].time==None else stats[search_engine.name].time }}{% if stats[search_engine.name]['warn_time'] %} {{ icon('exclamation-sign')}}{% endif %}</td>
<td>{{ support_toggle(search_engine.time_range_support==True) }}</td>
<td>{{ support_toggle(search_engine.safesearch==True) }}</td>
<td>{{ support_toggle(stats[search_engine.name].supports_selected_language) }}</td>
<td>{{ shortcuts[search_engine.name] }}</td>
<th>{{ search_engine.name }}</th>
<th scope="row">{{ search_engine.name }}</th>
<td class="onoff-checkbox">
{{ checkbox_toggle('engine_' + search_engine.name|replace(' ', '_') + '__' + categ|replace(' ', '_'), (search_engine.name, categ) in disabled_engines) }}
</td>
@ -241,7 +241,7 @@
<h3 class="panel-title">{{ _(plugin.name) }}</h3>
</div>
<div class="panel-body">
<div class="col-xs-6 col-sm-4 col-md-6">{{ _(plugin.description) }}</div>
<div class="col-xs-6 col-sm-4 col-md-6"><label for="{{'plugin_' + plugin.id}}">{{ _(plugin.description) }}</label></div>
<div class="col-xs-6 col-sm-4 col-md-6">
<div class="onoff-checkbox">
{{ checkbox_toggle('plugin_' + plugin.id, plugin.id not in allowed_plugins) }}

View file

@ -16,7 +16,7 @@
{%- if result.img_src -%}
<div class="container-fluid">
<div class="row">
<img src="{{ image_proxify(result.img_src) }}" alt="{{ result.title|striptags }}" title="{{ result.title|striptags }}" style="width: auto; max-height: 60px; min-height: 60px;" class="col-xs-2 col-sm-4 col-md-4 result-content">
<img src="{{ image_proxify(result.img_src) }}" title="{{ result.title|striptags }}" style="width: auto; max-height: 60px; min-height: 60px;" class="col-xs-2 col-sm-4 col-md-4 result-content">
{% if result.content %}<p class="result-content col-xs-8 col-sm-8 col-md-8">{{ result.content|safe }}</p>{% endif -%}
</div>
</div>

View file

@ -15,7 +15,7 @@
<div class="container-fluid">
<div class="row">
<a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}><img class="thumbnail col-xs-6 col-sm-4 col-md-4 result-content" src="{{ image_proxify(result.thumbnail) }}" alt="{{ result.title|striptags }} {{ result.engine }}" /></a>
<a href="{{ result.url }}" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %}><img class="thumbnail col-xs-6 col-sm-4 col-md-4 result-content" src="{{ image_proxify(result.thumbnail) }}" /></a>
{% if result.author %}<p class="col-xs-12 col-sm-8 col-md-8 result-content"><b>{{ _('Author') }}</b>: {{ result.author }}</p>{% endif %}
{% if result.length %}<p class="col-xs-12 col-sm-8 col-md-8 result-content"><b>{{ _('Length') }}</b>: {{ result.length }}</p>{% endif %}
{% if result.content %}<p class="col-xs-12 col-sm-8 col-md-8 result-content">{{ result.content|safe }}</p>{% endif %}

View file

@ -1,3 +1,4 @@
<label class="visually-hidden" for="time-range">{{ _('Time range') }}</label>
<select name="time_range" id="time-range" class="custom-select form-control" accesskey="t">{{- "" -}}
<option id="time-range-anytime" value="" {{ "selected" if time_range=="" or not time_range else ""}}>
{{- _('Anytime') -}}

View file

@ -12,6 +12,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
{% block meta %}{% endblock %}
<script src="{{ url_for('js_translations') }}"></script>
{% if rtl %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/searx-rtl.min.css') }}" type="text/css" media="screen" />
{% else %}

View file

@ -335,8 +335,15 @@ def image_proxify(url):
if not request.preferences.get_value('image_proxy'):
return url
if url.startswith('data:image/jpeg;base64,'):
if url.startswith('data:image/'):
# 50 is an arbitrary number to get only the beginning of the image.
partial_base64 = url[len('data:image/'):50].split(';')
if len(partial_base64) == 2 \
and partial_base64[0] in ['gif', 'png', 'jpeg', 'pjpeg', 'webp', 'tiff', 'bmp']\
and partial_base64[1].startswith('base64,'):
return url
else:
return None
if settings.get('result_proxy'):
return proxify(url)
@ -949,7 +956,7 @@ def opensearch():
resp = Response(response=ret,
status=200,
mimetype="text/xml")
mimetype="application/opensearchdescription+xml")
return resp
@ -1021,6 +1028,14 @@ def config():
})
@app.route('/translations.js')
def js_translations():
return render(
'translations.js.tpl',
override_theme='__common__',
), {'Content-Type': 'text/javascript; charset=UTF-8'}
@app.errorhandler(404)
def page_not_found(e):
return render('404.html'), 404

View file

@ -1,4 +1,5 @@
export GIT_URL='https://github.com/asciimoo/searx'
export GIT_BRANCH='master'
export ISSUE_URL='https://github.com/asciimoo/searx/issues'
export SEARX_URL='https://searx.me'
export DOCS_URL='https://asciimoo.github.io/searx'

561
utils/filtron.sh Executable file
View file

@ -0,0 +1,561 @@
#!/usr/bin/env bash
# -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck disable=SC2119,SC2001
# shellcheck source=utils/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
# shellcheck source=utils/brand.env
source "${REPO_ROOT}/utils/brand.env"
source_dot_config
source "${REPO_ROOT}/utils/lxc-searx.env"
in_container && lxc_set_suite_env
# ----------------------------------------------------------------------------
# config
# ----------------------------------------------------------------------------
PUBLIC_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
PUBLIC_HOST="${PUBLIC_HOST:-$(echo "$PUBLIC_URL" | sed -e 's/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/')}"
FILTRON_URL_PATH="${FILTRON_URL_PATH:-$(echo "${PUBLIC_URL}" \
| sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
[[ "${FILTRON_URL_PATH}" == "${PUBLIC_URL}" ]] && FILTRON_URL_PATH=/
FILTRON_ETC="/etc/filtron"
FILTRON_RULES="$FILTRON_ETC/rules.json"
FILTRON_API="${FILTRON_API:-127.0.0.1:4005}"
FILTRON_LISTEN="${FILTRON_LISTEN:-127.0.0.1:4004}"
FILTRON_TARGET="${FILTRON_TARGET:-127.0.0.1:8888}"
SERVICE_NAME="filtron"
SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
# shellcheck disable=SC2034
SERVICE_GROUP="${SERVICE_USER}"
# shellcheck disable=SC2034
SERVICE_GROUP="${SERVICE_USER}"
GO_ENV="${SERVICE_HOME}/.go_env"
GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
GO_TAR=$(basename "$GO_PKG_URL")
APACHE_FILTRON_SITE="searx.conf"
NGINX_FILTRON_SITE="searx.conf"
# shellcheck disable=SC2034
CONFIG_FILES=(
"${FILTRON_RULES}"
"${SERVICE_SYSTEMD_UNIT}"
)
# ----------------------------------------------------------------------------
usage() {
# ----------------------------------------------------------------------------
# shellcheck disable=SC1117
cat <<EOF
usage::
$(basename "$0") shell
$(basename "$0") install [all|user|rules]
$(basename "$0") update [filtron]
$(basename "$0") remove [all]
$(basename "$0") activate [service]
$(basename "$0") deactivate [service]
$(basename "$0") inspect [service]
$(basename "$0") option [debug-on|debug-off]
$(basename "$0") apache [install|remove]
$(basename "$0") nginx [install|remove]
shell
start interactive shell from user ${SERVICE_USER}
install / remove
:all: complete setup of filtron service
:user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
:rules: reinstall filtron rules $FILTRON_RULES
update filtron
Update filtron installation ($SERVICE_HOME)
activate service
activate and start service daemon (systemd unit)
deactivate service
stop and deactivate service daemon (systemd unit)
inspect service
show service status and log
option
set one of the available options
apache (${PUBLIC_URL})
:install: apache site with a reverse proxy (ProxyPass)
:remove: apache site ${APACHE_FILTRON_SITE}
nginx (${PUBLIC_URL})
:install: nginx site with a reverse proxy (ProxyPass)
:remove: nginx site ${NGINX_FILTRON_SITE}
filtron rules: ${FILTRON_RULES}
If needed, set PUBLIC_URL of your WEB service in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
PUBLIC_URL : ${PUBLIC_URL}
PUBLIC_HOST : ${PUBLIC_HOST}
SERVICE_USER : ${SERVICE_USER}
FILTRON_TARGET : ${FILTRON_TARGET}
FILTRON_API : ${FILTRON_API}
FILTRON_LISTEN : ${FILTRON_LISTEN}
EOF
if in_container; then
# in containers the service is listening on 0.0.0.0 (see lxc-searx.env)
for ip in $(global_IPs) ; do
if [[ $ip =~ .*:.* ]]; then
echo " container URL (IPv6): http://[${ip#*|}]:4005/"
else
# IPv4:
echo " container URL (IPv4): http://${ip#*|}:4005/"
fi
done
fi
[[ -n ${1} ]] && err_msg "$1"
}
main() {
required_commands \
sudo install git wget curl \
|| exit
local _usage="unknown or missing $1 command $2"
case $1 in
--getenv) var="$2"; echo "${!var}"; exit 0;;
-h|--help) usage; exit 0;;
shell)
sudo_or_exit
interactive_shell "${SERVICE_USER}"
;;
inspect)
case $2 in
service)
sudo_or_exit
inspect_service
;;
*) usage "$_usage"; exit 42;;
esac ;;
install)
rst_title "$SERVICE_NAME" part
sudo_or_exit
case $2 in
all) install_all ;;
user) assert_user ;;
rules)
rst_title "Re-Install filtron rules"
echo
install_template --no-eval "$FILTRON_RULES" root root 644
systemd_restart_service "${SERVICE_NAME}"
;;
*) usage "$_usage"; exit 42;;
esac ;;
update)
sudo_or_exit
case $2 in
filtron) update_filtron ;;
*) usage "$_usage"; exit 42;;
esac ;;
remove)
sudo_or_exit
case $2 in
all) remove_all;;
user) drop_service_account "${SERVICE_USER}" ;;
*) usage "$_usage"; exit 42;;
esac ;;
activate)
sudo_or_exit
case $2 in
service) systemd_activate_service "${SERVICE_NAME}" ;;
*) usage "$_usage"; exit 42;;
esac ;;
deactivate)
sudo_or_exit
case $2 in
service) systemd_deactivate_service "${SERVICE_NAME}" ;;
*) usage "$_usage"; exit 42;;
esac ;;
apache)
sudo_or_exit
case $2 in
install) install_apache_site ;;
remove) remove_apache_site ;;
*) usage "$_usage"; exit 42;;
esac ;;
nginx)
sudo_or_exit
case $2 in
install) install_nginx_site ;;
remove) remove_nginx_site ;;
*) usage "$_usage"; exit 42;;
esac ;;
option)
sudo_or_exit
case $2 in
debug-on) echo; enable_debug ;;
debug-off) echo; disable_debug ;;
*) usage "$_usage"; exit 42;;
esac ;;
doc) rst-doc ;;
*) usage "unknown or missing command $1"; exit 42;;
esac
}
install_all() {
rst_title "Install $SERVICE_NAME (service)"
assert_user
wait_key
install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
wait_key
install_filtron
wait_key
systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
wait_key
echo
if ! service_is_available "http://${FILTRON_LISTEN}" ; then
err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
fi
if apache_is_installed; then
info_msg "Apache is installed on this host."
if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
install_apache_site
fi
elif nginx_is_installed; then
info_msg "nginx is installed on this host."
if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
install_nginx_site
fi
fi
if ask_yn "Do you want to inspect the installation?" Ny; then
inspect_service
fi
}
remove_all() {
rst_title "De-Install $SERVICE_NAME (service)"
rst_para "\
It goes without saying that this script can only be used to remove
installations that were installed with this script."
if ! systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
return 42
fi
drop_service_account "${SERVICE_USER}"
rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
if service_is_available "${PUBLIC_URL}"; then
MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
fi
}
assert_user() {
rst_title "user $SERVICE_USER" section
echo
tee_stderr 1 <<EOF | bash | prefix_stdout
useradd --shell /bin/bash --system \
--home-dir "$SERVICE_HOME" \
--comment 'Reverse HTTP proxy to filter requests' $SERVICE_USER
mkdir "$SERVICE_HOME"
chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
groups $SERVICE_USER
EOF
SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
export SERVICE_HOME
echo "export SERVICE_HOME=$SERVICE_HOME"
cat > "$GO_ENV" <<EOF
export GOPATH=\$HOME/go-apps
export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
EOF
echo "Environment $GO_ENV has been setup."
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
EOF
}
filtron_is_installed() {
[[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
}
_svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
install_filtron() {
rst_title "Install filtron in user's ~/go-apps" section
echo
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
go get -v -u github.com/asciimoo/filtron
EOF
install_template --no-eval "$FILTRON_RULES" root root 644
}
update_filtron() {
rst_title "Update filtron" section
echo
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
go get -v -u github.com/asciimoo/filtron
EOF
}
inspect_service() {
rst_title "service status & log"
cat <<EOF
sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
PUBLIC_URL : ${PUBLIC_URL}
PUBLIC_HOST : ${PUBLIC_HOST}
FILTRON_URL_PATH : ${FILTRON_URL_PATH}
FILTRON_API : ${FILTRON_API}
FILTRON_LISTEN : ${FILTRON_LISTEN}
FILTRON_TARGET : ${FILTRON_TARGET}
EOF
if service_account_is_available "$SERVICE_USER"; then
info_msg "service account $SERVICE_USER available."
else
err_msg "service account $SERVICE_USER not available!"
fi
if go_is_available "$SERVICE_USER"; then
info_msg "~$SERVICE_USER: go is installed"
else
err_msg "~$SERVICE_USER: go is not installed"
fi
if filtron_is_installed; then
info_msg "~$SERVICE_USER: filtron app is installed"
else
err_msg "~$SERVICE_USER: filtron app is not installed!"
fi
if ! service_is_available "http://${FILTRON_API}"; then
err_msg "API not available at: http://${FILTRON_API}"
fi
if ! service_is_available "http://${FILTRON_LISTEN}" ; then
err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
fi
if service_is_available "http://${FILTRON_TARGET}" ; then
info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
fi
if ! service_is_available "${PUBLIC_URL}"; then
warn_msg "Public service at ${PUBLIC_URL} is not available!"
if ! in_container; then
warn_msg "Check if public name is correct and routed or use the public IP from above."
fi
fi
if in_container; then
lxc_suite_info
else
info_msg "public URL --> ${PUBLIC_URL}"
info_msg "internal URL --> http://${FILTRON_LISTEN}"
fi
local _debug_on
if ask_yn "Enable filtron debug mode?"; then
enable_debug
_debug_on=1
fi
echo
systemctl --no-pager -l status "${SERVICE_NAME}"
echo
info_msg "public URL --> ${PUBLIC_URL}"
# shellcheck disable=SC2059
printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
read -r -s -n1 -t 5
echo
while true; do
trap break 2
journalctl -f -u "${SERVICE_NAME}"
done
if [[ $_debug_on == 1 ]]; then
disable_debug
fi
return 0
}
enable_debug() {
info_msg "try to enable debug mode ..."
python <<EOF
import sys, json
debug = {
u'name': u'debug request'
, u'filters': []
, u'interval': 0
, u'limit': 0
, u'actions': [{u'name': u'log'}]
}
with open('$FILTRON_RULES') as rules:
j = json.load(rules)
pos = None
for i in range(len(j)):
if j[i].get('name') == 'debug request':
pos = i
break
if pos is not None:
j[pos] = debug
else:
j.append(debug)
with open('$FILTRON_RULES', 'w') as rules:
json.dump(j, rules, indent=2, sort_keys=True)
EOF
systemctl restart "${SERVICE_NAME}.service"
}
disable_debug() {
info_msg "try to disable debug mode ..."
python <<EOF
import sys, json
with open('$FILTRON_RULES') as rules:
j = json.load(rules)
pos = None
for i in range(len(j)):
if j[i].get('name') == 'debug request':
pos = i
break
if pos is not None:
del j[pos]
with open('$FILTRON_RULES', 'w') as rules:
json.dump(j, rules, indent=2, sort_keys=True)
EOF
systemctl restart "${SERVICE_NAME}.service"
}
install_apache_site() {
rst_title "Install Apache site $APACHE_FILTRON_SITE"
rst_para "\
This installs a reverse proxy (ProxyPass) into apache site (${APACHE_FILTRON_SITE})"
! apache_is_installed && info_msg "Apache is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
else
install_apache
fi
"${REPO_ROOT}/utils/searx.sh" install uwsgi
apache_install_site --variant=filtron "${APACHE_FILTRON_SITE}"
info_msg "testing public url .."
if ! service_is_available "${PUBLIC_URL}"; then
err_msg "Public service at ${PUBLIC_URL} is not available!"
fi
}
remove_apache_site() {
rst_title "Remove Apache site $APACHE_FILTRON_SITE"
rst_para "\
This removes apache site ${APACHE_FILTRON_SITE}."
! apache_is_installed && err_msg "Apache is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
fi
apache_remove_site "$APACHE_FILTRON_SITE"
}
install_nginx_site() {
rst_title "Install nginx site $NGINX_FILTRON_SITE"
rst_para "\
This installs a reverse proxy (ProxyPass) into nginx site (${NGINX_FILTRON_SITE})"
! nginx_is_installed && info_msg "nginx is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
else
install_nginx
fi
"${REPO_ROOT}/utils/searx.sh" install uwsgi
# shellcheck disable=SC2034
SEARX_SRC=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_SRC)
# shellcheck disable=SC2034
SEARX_URL_PATH=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_URL_PATH)
nginx_install_app --variant=filtron "${NGINX_FILTRON_SITE}"
info_msg "testing public url .."
if ! service_is_available "${PUBLIC_URL}"; then
err_msg "Public service at ${PUBLIC_URL} is not available!"
fi
}
remove_nginx_site() {
rst_title "Remove nginx site $NGINX_FILTRON_SITE"
rst_para "\
This removes nginx site ${NGINX_FILTRON_SITE}."
! nginx_is_installed && err_msg "nginx is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
fi
nginx_remove_site "$FILTRON_FILTRON_SITE"
}
rst-doc() {
eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/filtron.rst")\""
echo -e "\n.. START install systemd unit"
cat <<EOF
.. tabs::
.. group-tab:: systemd
.. code:: bash
EOF
eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
echo -e "\n.. END install systemd unit"
# for DIST_NAME in ubuntu-20.04 arch fedora; do
# (
# DIST_ID=${DIST_NAME%-*}
# DIST_VERS=${DIST_NAME#*-}
# [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
# # ...
# )
# done
}
# ----------------------------------------------------------------------------
main "$@"
# ----------------------------------------------------------------------------

1519
utils/lib.sh Executable file

File diff suppressed because it is too large Load diff

95
utils/lxc-searx.env Normal file
View file

@ -0,0 +1,95 @@
# -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck shell=bash
# This file is a setup of a LXC suite. It is sourced from different context, do
# not manipulate the environment directly, implement functions and manipulate
# environment only is subshells!
# ----------------------------------------------------------------------------
# config
# ----------------------------------------------------------------------------
# shellcheck disable=SC2034
LXC_SUITE_NAME="searx"
lxc_set_suite_env() {
# name of https://images.linuxcontainers.org
export LINUXCONTAINERS_ORG_NAME="${LINUXCONTAINERS_ORG_NAME:-images}"
export LXC_HOST_PREFIX="${LXC_SUITE_NAME:-searx}"
export LXC_SUITE=(
# to disable containers, comment out lines ..
# end of standard support see https://wiki.ubuntu.com/Releases
"$LINUXCONTAINERS_ORG_NAME:ubuntu/16.04" "ubu1604" # April 2021
"$LINUXCONTAINERS_ORG_NAME:ubuntu/18.04" "ubu1804" # April 2023
"$LINUXCONTAINERS_ORG_NAME:ubuntu/19.10" "ubu1910" # July 2020
"$LINUXCONTAINERS_ORG_NAME:ubuntu/20.04" "ubu2004" # future (EOL 2030)
# EOL see https://fedoraproject.org/wiki/Releases
"$LINUXCONTAINERS_ORG_NAME:fedora/31" "fedora31"
# rolling releases see https://www.archlinux.org/releng/releases/
"$LINUXCONTAINERS_ORG_NAME:archlinux" "archlinux"
)
PUBLIC_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
if in_container; then
# container hostnames do not have a DNS entry: use primary IP!
PUBLIC_URL="http://$(primary_ip)/searx"
# make GUEST's services public to the HOST
FILTRON_API="0.0.0.0:4005"
FILTRON_LISTEN="0.0.0.0:4004"
MORTY_LISTEN="0.0.0.0:3000"
# export LXC specific environment
export PUBLIC_URL FILTRON_API FILTRON_LISTEN MORTY_LISTEN
fi
}
lxc_suite_install_info() {
(
lxc_set_suite_env
cat <<EOF
LXC suite: ${LXC_SUITE_NAME} --> ${PUBLIC_URL}
suite includes searx, morty & filtron
suite images:
$(echo " ${LOCAL_IMAGES[*]}" | $FMT)
suite containers:
$(echo " ${CONTAINERS[*]}" | $FMT)
EOF
)
}
lxc_suite_install() {
(
lxc_set_suite_env
FORCE_TIMEOUT=0
export FORCE_TIMEOUT
"${LXC_REPO_ROOT}/utils/searx.sh" install all
"${LXC_REPO_ROOT}/utils/morty.sh" install all
"${LXC_REPO_ROOT}/utils/filtron.sh" install all
rst_title "suite installation finished ($(hostname))" part
lxc_suite_info
echo
)
}
lxc_suite_info() {
(
lxc_set_suite_env
for ip in $(global_IPs) ; do
if [[ $ip =~ .*:.* ]]; then
info_msg "(${ip%|*}) IPv6: http://[${ip#*|}]"
else
# IPv4:
# shellcheck disable=SC2034,SC2031
info_msg "(${ip%|*}) filtron: http://${ip#*|}:4004/ $PUBLIC_URL"
info_msg "(${ip%|*}) morty: http://${ip#*|}:3000/ $PUBLIC_URL_MORTY"
info_msg "(${ip%|*}) docs-live: http://${ip#*|}:8080/"
fi
done
)
}

552
utils/lxc.sh Executable file
View file

@ -0,0 +1,552 @@
#!/usr/bin/env bash
# -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck source=utils/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
source_dot_config
# load environment of the LXC suite
LXC_ENV="${LXC_ENV:-${REPO_ROOT}/utils/lxc-searx.env}"
source "$LXC_ENV"
lxc_set_suite_env
# ----------------------------------------------------------------------------
# config
# ----------------------------------------------------------------------------
#
# read also:
# - https://lxd.readthedocs.io/en/latest/
LXC_HOST_PREFIX="${LXC_HOST_PREFIX:-test}"
# where all folders from HOST are mounted
LXC_SHARE_FOLDER="/share"
LXC_REPO_ROOT="${LXC_SHARE_FOLDER}/$(basename "${REPO_ROOT}")"
ubu1604_boilerplate="
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get upgrade -y
apt-get install -y git curl wget
"
ubu1804_boilerplate="$ubu1604_boilerplate"
ubu1904_boilerplate="$ubu1804_boilerplate"
ubu1910_boilerplate="$ubu1904_boilerplate"
# shellcheck disable=SC2034
ubu2004_boilerplate="
$ubu1910_boilerplate
echo 'Set disable_coredump false' >> /etc/sudo.conf
"
# shellcheck disable=SC2034
archlinux_boilerplate="
pacman -Syu --noconfirm
pacman -S --noconfirm inetutils git curl wget sudo
echo 'Set disable_coredump false' >> /etc/sudo.conf
"
# shellcheck disable=SC2034
fedora31_boilerplate="
dnf update -y
dnf install -y git curl wget hostname
echo 'Set disable_coredump false' >> /etc/sudo.conf
"
REMOTE_IMAGES=()
CONTAINERS=()
LOCAL_IMAGES=()
for ((i=0; i<${#LXC_SUITE[@]}; i+=2)); do
REMOTE_IMAGES=("${REMOTE_IMAGES[@]}" "${LXC_SUITE[i]}")
CONTAINERS=("${CONTAINERS[@]}" "${LXC_HOST_PREFIX}-${LXC_SUITE[i+1]}")
LOCAL_IMAGES=("${LOCAL_IMAGES[@]}" "${LXC_SUITE[i+1]}")
done
HOST_USER="${SUDO_USER:-$USER}"
HOST_USER_ID=$(id -u "${HOST_USER}")
HOST_GROUP_ID=$(id -g "${HOST_USER}")
# ----------------------------------------------------------------------------
usage() {
# ----------------------------------------------------------------------------
_cmd="$(basename "$0")"
cat <<EOF
usage::
$_cmd build [containers|<name>]
$_cmd copy [images]
$_cmd remove [containers|<name>|images]
$_cmd [start|stop] [containers|<name>]
$_cmd show [images|suite|info|config [<name>]]
$_cmd cmd [--|<name>] '...'
$_cmd install [suite|base [<name>]]
build
:containers: build, launch all containers and 'install base' packages
:<name>: build, launch container <name> and 'install base' packages
copy:
:images: copy remote images of the suite into local storage
remove
:containers: delete all 'containers' or only <container-name>
:images: delete local images of the suite
start/stop
:containers: start/stop all 'containers' from the suite
:<name>: start/stop container <name> from suite
show
:info: show info of all (or <name>) containers from LXC suite
:config: show config of all (or <name>) containers from the LXC suite
:suite: show services of all (or <name>) containers from the LXC suite
:images: show information of local images
cmd
use single qoutes to evaluate in container's bash, e.g.: 'echo \$(hostname)'
-- run command '...' in all containers of the LXC suite
:<name>: run command '...' in container <name>
install
:base: prepare LXC; install basic packages
:suite: install LXC ${LXC_SUITE_NAME} suite into all (or <name>) containers
EOF
usage_containers
[ -n "${1+x}" ] && err_msg "$1"
}
usage_containers() {
lxc_suite_install_info
[ -n "${1+x}" ] && err_msg "$1"
}
lxd_info() {
cat <<EOF
LXD is needed, to install run::
snap install lxd
lxd init --auto
EOF
}
main() {
local exit_val
local _usage="unknown or missing $1 command $2"
# don't check prerequisite when in recursion
if [[ ! $1 == __* ]]; then
if ! in_container; then
! required_commands lxc && lxd_info && exit 42
fi
[[ -z $LXC_SUITE ]] && err_msg "missing LXC_SUITE" && exit 42
fi
case $1 in
--getenv) var="$2"; echo "${!var}"; exit 0;;
-h|--help) usage; exit 0;;
build)
sudo_or_exit
case $2 in
${LXC_HOST_PREFIX}-*) build_container "$2" ;;
''|--|containers) build_all_containers ;;
*) usage "$_usage"; exit 42;;
esac
;;
copy)
case $2 in
''|images) lxc_copy_images_localy;;
*) usage "$_usage"; exit 42;;
esac
;;
remove)
sudo_or_exit
case $2 in
''|--|containers) remove_containers ;;
images) lxc_delete_images_localy ;;
${LXC_HOST_PREFIX}-*)
! lxc_exists "$2" && warn_msg "container not yet exists: $2" && exit 0
if ask_yn "Do you really want to delete container $2"; then
lxc_delete_container "$2"
fi
;;
*) usage "uknown or missing container <name> $2"; exit 42;;
esac
;;
start|stop)
sudo_or_exit
case $2 in
''|--|containers) lxc_cmd "$1" ;;
${LXC_HOST_PREFIX}-*)
! lxc_exists "$2" && usage_containers "unknown container: $2" && exit 42
info_msg "lxc $1 $2"
lxc "$1" "$2" | prefix_stdout "[${_BBlue}${i}${_creset}] "
;;
*) usage "uknown or missing container <name> $2"; exit 42;;
esac
;;
show)
sudo_or_exit
case $2 in
suite)
case $3 in
${LXC_HOST_PREFIX}-*)
lxc exec -t "$3" -- "${LXC_REPO_ROOT}/utils/lxc.sh" __show suite \
| prefix_stdout "[${_BBlue}$3${_creset}] "
;;
*) show_suite;;
esac
;;
images) show_images ;;
config)
case $3 in
${LXC_HOST_PREFIX}-*)
! lxc_exists "$3" && usage_containers "unknown container: $3" && exit 42
lxc config show "$3" | prefix_stdout "[${_BBlue}${3}${_creset}] "
;;
*)
rst_title "container configurations"
echo
lxc list "$LXC_HOST_PREFIX-"
echo
lxc_cmd config show
;;
esac
;;
info)
case $3 in
${LXC_HOST_PREFIX}-*)
! lxc_exists "$3" && usage_containers "unknown container: $3" && exit 42
lxc info "$3" | prefix_stdout "[${_BBlue}${3}${_creset}] "
;;
*)
rst_title "container info"
echo
lxc_cmd info
;;
esac
;;
*) usage "$_usage"; exit 42;;
esac
;;
__show)
# wrapped show commands, called once in each container
case $2 in
suite) lxc_suite_info ;;
esac
;;
cmd)
sudo_or_exit
shift
case $1 in
--) shift; lxc_exec "$@" ;;
${LXC_HOST_PREFIX}-*)
! lxc_exists "$1" && usage_containers "unknown container: $1" && exit 42
local name=$1
shift
lxc_exec_cmd "${name}" "$@"
;;
*) usage_containers "unknown container: $1" && exit 42
esac
;;
install)
sudo_or_exit
case $2 in
suite|base)
case $3 in
${LXC_HOST_PREFIX}-*)
! lxc_exists "$3" && usage_containers "unknown container: $3" && exit 42
lxc_exec_cmd "$3" "${LXC_REPO_ROOT}/utils/lxc.sh" __install "$2"
;;
''|--) lxc_exec "${LXC_REPO_ROOT}/utils/lxc.sh" __install "$2" ;;
*) usage_containers "unknown container: $3" && exit 42
esac
;;
*) usage "$_usage"; exit 42 ;;
esac
;;
__install)
# wrapped install commands, called once in each container
# shellcheck disable=SC2119
case $2 in
suite) lxc_suite_install ;;
base) FORCE_TIMEOUT=0 lxc_install_base_packages ;;
esac
;;
doc)
echo
echo ".. generic utils/lxc.sh documentation"
;;
-*) usage "unknown option $1"; exit 42;;
*) usage "unknown or missing command $1"; exit 42;;
esac
}
build_all_containers() {
rst_title "Build all LXC containers of suite"
echo
usage_containers
lxc_copy_images_localy
lxc_init_all_containers
lxc_config_all_containers
lxc_boilerplate_all_containers
rst_title "install LXC base packages" section
echo
lxc_exec "${LXC_REPO_ROOT}/utils/lxc.sh" __install base
echo
lxc list "$LXC_HOST_PREFIX"
}
build_container() {
rst_title "Build container $1"
local remote_image
local container
local image
local boilerplate_script
for ((i=0; i<${#LXC_SUITE[@]}; i+=2)); do
if [ "${LXC_HOST_PREFIX}-${LXC_SUITE[i+1]}" = "$1" ]; then
remote_image="${LXC_SUITE[i]}"
container="${LXC_HOST_PREFIX}-${LXC_SUITE[i+1]}"
image="${LXC_SUITE[i+1]}"
boilerplate_script="${image}_boilerplate"
boilerplate_script="${!boilerplate_script}"
break
fi
done
echo
if [ -z "$container" ]; then
err_msg "container $1 unknown"
usage_containers
return 42
fi
lxc_image_copy "${remote_image}" "${image}"
rst_title "init container" section
lxc_init_container "${image}" "${container}"
rst_title "configure container" section
lxc_config_container "${container}"
rst_title "run LXC boilerplate scripts" section
lxc_install_boilerplate "${container}" "$boilerplate_script"
echo
rst_title "install LXC base packages" section
lxc_exec_cmd "${container}" "${LXC_REPO_ROOT}/utils/lxc.sh" __install base \
| prefix_stdout "[${_BBlue}${container}${_creset}] "
echo
lxc list "$container"
}
remove_containers() {
rst_title "Remove all LXC containers of suite"
rst_para "existing containers matching ${_BGreen}$LXC_HOST_PREFIX-*${_creset}"
echo
lxc list "$LXC_HOST_PREFIX-"
echo -en "\\n${_BRed}LXC containers to delete::${_creset}\\n\\n ${CONTAINERS[*]}\\n" | $FMT
local default=Ny
[[ $FORCE_TIMEOUT = 0 ]] && default=Yn
if ask_yn "Do you really want to delete these containers" $default; then
for i in "${CONTAINERS[@]}"; do
lxc_delete_container "$i"
done
fi
echo
lxc list "$LXC_HOST_PREFIX-"
}
# images
# ------
lxc_copy_images_localy() {
rst_title "copy images" section
for ((i=0; i<${#LXC_SUITE[@]}; i+=2)); do
lxc_image_copy "${LXC_SUITE[i]}" "${LXC_SUITE[i+1]}"
done
# lxc image list local: && wait_key
}
lxc_delete_images_localy() {
rst_title "Delete LXC images"
rst_para "local existing images"
echo
lxc image list local:
echo -en "\\n${_BRed}LXC images to delete::${_creset}\\n\\n ${LOCAL_IMAGES[*]}\\n"
if ask_yn "Do you really want to delete these images"; then
for i in "${LOCAL_IMAGES[@]}"; do
lxc_delete_local_image "$i"
done
fi
for i in $(lxc image list --format csv | grep '^,' | sed 's/,\([^,]*\).*$/\1/'); do
if ask_yn "Image $i has no alias, do you want to delete the image?" Yn; then
lxc_delete_local_image "$i"
fi
done
echo
lxc image list local:
}
show_images(){
rst_title "local images"
echo
lxc image list local:
echo -en "\\n${_Green}LXC suite images::${_creset}\\n\\n ${LOCAL_IMAGES[*]}\\n"
wait_key
for i in "${LOCAL_IMAGES[@]}"; do
if lxc_image_exists "$i"; then
info_msg "lxc image info ${_BBlue}${i}${_creset}"
lxc image info "$i" | prefix_stdout "[${_BBlue}${i}${_creset}] "
else
warn_msg "image ${_BBlue}$i${_creset} does not yet exists"
fi
done
}
# container
# ---------
show_suite(){
rst_title "LXC suite ($LXC_HOST_PREFIX-*)"
echo
lxc list "$LXC_HOST_PREFIX-"
echo
for i in "${CONTAINERS[@]}"; do
if ! lxc_exists "$i"; then
warn_msg "container ${_BBlue}$i${_creset} does not yet exists"
else
lxc exec -t "${i}" -- "${LXC_REPO_ROOT}/utils/lxc.sh" __show suite \
| prefix_stdout "[${_BBlue}${i}${_creset}] "
echo
fi
done
}
lxc_cmd() {
for i in "${CONTAINERS[@]}"; do
if ! lxc_exists "$i"; then
warn_msg "container ${_BBlue}$i${_creset} does not yet exists"
else
info_msg "lxc $* $i"
lxc "$@" "$i" | prefix_stdout "[${_BBlue}${i}${_creset}] "
fi
done
}
lxc_exec_cmd() {
local name="$1"
shift
exit_val=
info_msg "[${_BBlue}${name}${_creset}] ${_BGreen}${*}${_creset}"
lxc exec -t --cwd "${LXC_REPO_ROOT}" "${name}" -- bash -c "$*"
exit_val=$?
if [[ $exit_val -ne 0 ]]; then
warn_msg "[${_BBlue}${name}${_creset}] exit code (${_BRed}${exit_val}${_creset}) from ${_BGreen}${*}${_creset}"
else
info_msg "[${_BBlue}${name}${_creset}] exit code (${exit_val}) from ${_BGreen}${*}${_creset}"
fi
}
lxc_exec() {
for i in "${CONTAINERS[@]}"; do
if ! lxc_exists "$i"; then
warn_msg "container ${_BBlue}$i${_creset} does not yet exists"
else
lxc_exec_cmd "${i}" "$@" | prefix_stdout "[${_BBlue}${i}${_creset}] "
fi
done
}
lxc_init_all_containers() {
rst_title "init all containers" section
local image_name
local container_name
for ((i=0; i<${#LXC_SUITE[@]}; i+=2)); do
lxc_init_container "${LXC_SUITE[i+1]}" "${LXC_HOST_PREFIX}-${LXC_SUITE[i+1]}"
done
}
lxc_config_all_containers() {
rst_title "configure all containers" section
for i in "${CONTAINERS[@]}"; do
lxc_config_container "${i}"
done
}
lxc_config_container() {
info_msg "[${_BBlue}$1${_creset}] configure container ..."
info_msg "[${_BBlue}$1${_creset}] map uid/gid from host to container"
# https://lxd.readthedocs.io/en/latest/userns-idmap/#custom-idmaps
echo -e -n "uid $HOST_USER_ID 0\\ngid $HOST_GROUP_ID 0"\
| lxc config set "$1" raw.idmap -
info_msg "[${_BBlue}$1${_creset}] share ${REPO_ROOT} (repo_share) from HOST into container"
# https://lxd.readthedocs.io/en/latest/instances/#type-disk
lxc config device add "$1" repo_share disk \
source="${REPO_ROOT}" \
path="${LXC_REPO_ROOT}" &>/dev/null
# lxc config show "$1" && wait_key
}
lxc_boilerplate_all_containers() {
rst_title "run LXC boilerplate scripts" section
local boilerplate_script
local image_name
for ((i=0; i<${#LXC_SUITE[@]}; i+=2)); do
image_name="${LXC_SUITE[i+1]}"
boilerplate_script="${image_name}_boilerplate"
boilerplate_script="${!boilerplate_script}"
lxc_install_boilerplate "${LXC_HOST_PREFIX}-${image_name}" "$boilerplate_script"
if [[ -z "${boilerplate_script}" ]]; then
err_msg "[${_BBlue}${container_name}${_creset}] no boilerplate for image '${image_name}'"
fi
done
}
lxc_install_boilerplate() {
# usage: lxc_install_boilerplate <container-name> <string: shell commands ..>
#
# usage: lxc_install_boilerplate searx-archlinux "${archlinux_boilerplate}"
local container_name="$1"
local boilerplate_script="$2"
info_msg "[${_BBlue}${container_name}${_creset}] init .."
if lxc start -q "${container_name}" &>/dev/null; then
sleep 5 # guest needs some time to come up and get an IP
fi
lxc_init_container_env "${container_name}"
info_msg "[${_BBlue}${container_name}${_creset}] install /.lxcenv.mk .."
cat <<EOF | lxc exec "${container_name}" -- bash | prefix_stdout "[${_BBlue}${container_name}${_creset}] "
rm -f "/.lxcenv.mk"
ln -s "${LXC_REPO_ROOT}/utils/makefile.lxc" "/.lxcenv.mk"
ls -l "/.lxcenv.mk"
EOF
info_msg "[${_BBlue}${container_name}${_creset}] run LXC boilerplate scripts .."
if lxc start -q "${container_name}" &>/dev/null; then
sleep 5 # guest needs some time to come up and get an IP
fi
if [[ -n "${boilerplate_script}" ]]; then
echo "${boilerplate_script}" \
| lxc exec "${container_name}" -- bash \
| prefix_stdout "[${_BBlue}${container_name}${_creset}] "
fi
}
# ----------------------------------------------------------------------------
main "$@"
# ----------------------------------------------------------------------------

View file

@ -1,12 +1,25 @@
# -*- coding: utf-8; mode: makefile-gmake -*-
ifeq (,$(wildcard /.lxcenv.mk))
PHONY += lxc-activate lxc-purge
lxc-activate:
@$(MAKE) -s -f /share/searx/utils/makefile.lxc lxc-activate
lxc-purge:
$(Q)rm -rf ./lxc
else
include /.lxcenv.mk
endif
ifeq (,$(wildcard /.lxcenv.mk))
make-help:
else
make-help: lxc-help
endif
@echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
@echo ' make V=2 [targets] 2 => give reason for rebuild of target'
quiet_cmd_common_clean = CLEAN $@
cmd_common_clean = \
rm -rf tests/build ;\
find . -name '*.orig' -exec rm -f {} + ;\
find . -name '*.rej' -exec rm -f {} + ;\
find . -name '*~' -exec rm -f {} + ;\
@ -126,3 +139,4 @@ echo-cmd = $(if $($(quiet)cmd_$(1)),echo '$(call escsq,$($(quiet)cmd_$(1)))$(ech
# printing commands
cmd = @$(echo-cmd) $(cmd_$(1))
.PHONY: $(PHONY)

29
utils/makefile.lxc Normal file
View file

@ -0,0 +1,29 @@
# -*- coding: utf-8; mode: makefile-gmake -*-
#
# LXC environment
# ===============
#
# To activate/deactivate LXC makefile environment in a container, set/unset link
# from root '/.lxcenv.mk' to *this* file::
#
# sudo make ./utils/makefile.lxc lxc-activate
# sudo make ./utils/makefile.lxc lxc-deactivate
LXC_ENV_FOLDER=lxc/$(shell hostname)/
lxc-help::
@echo 'LXC: running in container LXC_ENV_FOLDER=$(LXC_ENV_FOLDER)'
# If not activated, serve target 'lxc-activate' ..
ifeq (,$(wildcard /.lxcenv.mk))
PHONY += lxc-activate
lxc-activate:
ln -s "$(abspath $(lastword $(MAKEFILE_LIST)))" "/.lxcenv.mk"
else
# .. and if activated, serve target 'lxc-deactivate'.
PHONY += lxc-deactivate
lxc-deactivate:
rm /.lxcenv.mk
endif
.PHONY: $(PHONY)

View file

@ -8,9 +8,9 @@ export PYTHONPATH := $(SITE_PYTHON):$$PYTHONPATH
export PY_ENV PYDIST PYBUILD
# folder where the python distribution takes place
PYDIST ?= ./py_dist
PYDIST = ./$(LXC_ENV_FOLDER)dist
# folder where the python intermediate build files take place
PYBUILD ?= ./py_build
PYBUILD = ./$(LXC_ENV_FOLDER)build
# python version to use
PY ?=3
# $(PYTHON) points to the python interpreter from the OS! The python from the
@ -30,8 +30,7 @@ PYLINT_RC ?= .pylintrc
TEST_FOLDER ?= ./tests
TEST ?= .
VTENV_OPTS = "--no-site-packages"
PY_ENV = ./local/py$(PY)
PY_ENV = ./$(LXC_ENV_FOLDER)local/py$(PY)
PY_ENV_BIN = $(PY_ENV)/bin
PY_ENV_ACT = . $(PY_ENV_BIN)/activate
@ -41,6 +40,7 @@ ifeq ($(OS),Windows_NT)
PY_ENV_ACT = $(PY_ENV_BIN)/activate
endif
VTENV_OPTS ?=
ifeq ($(PYTHON),python)
VIRTUALENV = virtualenv
else

View file

@ -1,17 +1,19 @@
# -*- coding: utf-8; mode: makefile-gmake -*-
export DOCS_FOLDER DOCS_BUILD DOCS_DIST BOOKS_FOLDER BOOKS_DIST
# You can set these variables from the command line.
SPHINXOPTS ?=
SPHINXBUILD ?= $(PY_ENV_BIN)/sphinx-build
SPHINX_CONF ?= conf.py
DOCS_FOLDER ?= docs
DOCS_BUILD ?= build/docs
DOCS_DIST ?= dist/docs
DOCS_FOLDER = ./docs
DOCS_BUILD = ./$(LXC_ENV_FOLDER)build/docs
DOCS_DIST = ./$(LXC_ENV_FOLDER)dist/docs
GH_PAGES ?= gh-pages
BOOKS_FOLDER ?= docs
BOOKS_DIST ?= dist/books
BOOKS_FOLDER = ./docs
BOOKS_DIST = ./$(LXC_ENV_FOLDER)dist/books
ifeq ($(KBUILD_VERBOSE),1)
SPHINX_VERBOSE = "-v"
@ -54,11 +56,13 @@ docs-help:
# requirements
# ------------------------------------------------------------------------------
sphinx-doc: $(PY_ENV)
sphinx-doc-prebuilds:: $(PY_ENV)
sphinx-doc: sphinx-doc-prebuilds
@echo "PYENV installing Sphinx$(SPHINXVERS)"
$(Q)$(PY_ENV_BIN)/pip install $(PIP_VERBOSE) 'Sphinx$(SPHINXVERS)'
sphinx-live: $(PY_ENV)
sphinx-live: sphinx-doc-prebuilds
@echo "PYENV installing Sphinx$(SPHINXVERS)"
$(Q)$(PY_ENV_BIN)/pip install $(PIP_VERBOSE) 'Sphinx$(SPHINXVERS)' sphinx-autobuild
@ -154,7 +158,7 @@ $(BOOKS_HTML): sphinx-doc | $(BOOKS_DIST)
-b html \
-c $(DOCS_FOLDER) \
-d $(DOCS_BUILD)/books/$(patsubst books/%.html,%,$@)/.doctrees \
$(patsubst books/%.html,%,$@) \
$(BOOKS_FOLDER)/$(patsubst books/%.html,%,$@) \
$(BOOKS_DIST)/$(patsubst books/%.html,%,$@)
@echo "SPHINX $@ --> file://$(abspath $(BOOKS_DIST)/$(patsubst books/%.html,%,$@))"
@ -166,7 +170,7 @@ $(BOOKS_LIVE): sphinx-live | $(BOOKS_DIST)
-b html \
-c $(DOCS_FOLDER) \
-d $(DOCS_BUILD)/books/$(patsubst books/%.live,%,$@)/.doctrees \
$(patsubst books/%.live,%,$@) \
$(BOOKS_FOLDER)/$(patsubst books/%.live,%,$@) \
$(BOOKS_DIST)/$(patsubst books/%.live,%,$@)
$(BOOKS_PDF): %.pdf : %.latex
@ -182,7 +186,7 @@ $(BOOKS_LATEX): sphinx-doc | $(BOOKS_DIST)
-b latex \
-c $(DOCS_FOLDER) \
-d $(DOCS_BUILD)/books/$(patsubst books/%.latex,%,$@)/.doctrees \
$(patsubst books/%.latex,%,$@) \
$(BOOKS_FOLDER)/$(patsubst books/%.latex,%,$@) \
$(DOCS_BUILD)/latex/$(patsubst books/%.latex,%,$@)
@echo "SPHINX $@ --> file://$(abspath $(DOCS_BUILD)/latex/$(patsubst books/%.latex,%,$@))"

546
utils/morty.sh Executable file
View file

@ -0,0 +1,546 @@
#!/usr/bin/env bash
# -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck source=utils/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
# shellcheck source=utils/brand.env
source "${REPO_ROOT}/utils/brand.env"
source_dot_config
SEARX_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
source "${REPO_ROOT}/utils/lxc-searx.env"
in_container && lxc_set_suite_env
# ----------------------------------------------------------------------------
# config
# ----------------------------------------------------------------------------
MORTY_LISTEN="${MORTY_LISTEN:-127.0.0.1:3000}"
PUBLIC_URL_PATH_MORTY="${PUBLIC_URL_PATH_MORTY:-/morty/}"
PUBLIC_URL_MORTY="${PUBLIC_URL_MORTY:-$(echo "$SEARX_URL" | sed -e's,^\(.*://[^/]*\).*,\1,g')${PUBLIC_URL_PATH_MORTY}}"
# shellcheck disable=SC2034
MORTY_TIMEOUT=5
SERVICE_NAME="morty"
SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
# shellcheck disable=SC2034
SERVICE_GROUP="${SERVICE_USER}"
# shellcheck disable=SC2034
SERVICE_ENV_DEBUG=false
GO_ENV="${SERVICE_HOME}/.go_env"
GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
GO_TAR=$(basename "$GO_PKG_URL")
# shellcheck disable=SC2034
CONFIG_FILES=()
# Apache Settings
APACHE_MORTY_SITE="morty.conf"
NGINX_MORTY_SITE="morty.conf"
# ----------------------------------------------------------------------------
usage() {
# ----------------------------------------------------------------------------
# shellcheck disable=SC1117
cat <<EOF
usage::
$(basename "$0") shell
$(basename "$0") install [all|user]
$(basename "$0") update [morty]
$(basename "$0") remove [all]
$(basename "$0") activate [service]
$(basename "$0") deactivate [service]
$(basename "$0") inspect [service]
$(basename "$0") option [debug-on|debug-off|new-key]
$(basename "$0") apache [install|remove]
$(basename "$0") nginx [install|remove]
$(basename "$0") info [searx]
shell
start interactive shell from user ${SERVICE_USER}
install / remove
all: complete setup of morty service
user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
update morty
Update morty installation ($SERVICE_HOME)
activate service
activate and start service daemon (systemd unit)
deactivate service
stop and deactivate service daemon (systemd unit)
inspect service
show service status and log
option
set one of the available options
:new-key: set new morty key
apache : ${PUBLIC_URL_MORTY}
:install: apache site with a reverse proxy (ProxyPass)
:remove: apache site ${APACHE_MORTY_SITE}
nginx (${PUBLIC_URL_MORTY})
:install: nginx site with a reverse proxy (ProxyPass)
:remove: nginx site ${NGINX_MORTY_SITE}
If needed, set the environment variables in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
PUBLIC_URL_MORTY: ${PUBLIC_URL_MORTY}
MORTY_LISTEN: ${MORTY_LISTEN}
SERVICE_USER: ${SERVICE_USER}
EOF
if in_container; then
# in containers the service is listening on 0.0.0.0 (see lxc-searx.env)
for ip in $(global_IPs) ; do
if [[ $ip =~ .*:.* ]]; then
echo " container URL (IPv6): http://[${ip#*|}]:3000/"
else
# IPv4:
echo " container URL (IPv4): http://${ip#*|}:3000/"
fi
done
fi
echo
info_searx
[[ -n ${1} ]] && err_msg "$1"
}
info_searx() {
# shellcheck disable=SC1117
cat <<EOF
To activate result and image proxy in searx, edit settings.yml (read:
${DOCS_URL}/admin/morty.html)::
result_proxy:
url : ${PUBLIC_URL_MORTY}
server:
image_proxy : True
EOF
}
main() {
required_commands \
sudo install git wget curl \
|| exit
local _usage="ERROR: unknown or missing $1 command $2"
case $1 in
--getenv) var="$2"; echo "${!var}"; exit 0;;
-h|--help) usage; exit 0;;
shell)
sudo_or_exit
interactive_shell "${SERVICE_USER}"
;;
inspect)
case $2 in
service)
sudo_or_exit
inspect_service
;;
*) usage "$_usage"; exit 42;;
esac ;;
install)
rst_title "$SERVICE_NAME" part
sudo_or_exit
case $2 in
all) install_all ;;
user) assert_user ;;
*) usage "$_usage"; exit 42;;
esac ;;
update)
sudo_or_exit
case $2 in
morty) update_morty ;;
*) usage "$_usage"; exit 42;;
esac ;;
remove)
sudo_or_exit
case $2 in
all) remove_all;;
user) drop_service_account "${SERVICE_USER}" ;;
*) usage "$_usage"; exit 42;;
esac ;;
activate)
sudo_or_exit
case $2 in
service) systemd_activate_service "${SERVICE_NAME}" ;;
*) usage "$_usage"; exit 42;;
esac ;;
deactivate)
sudo_or_exit
case $2 in
service) systemd_deactivate_service "${SERVICE_NAME}" ;;
*) usage "$_usage"; exit 42;;
esac ;;
apache)
sudo_or_exit
case $2 in
install) install_apache_site ;;
remove) remove_apache_site ;;
*) usage "$_usage"; exit 42;;
esac ;;
nginx)
sudo_or_exit
case $2 in
install) install_nginx_site ;;
remove) remove_nginx_site ;;
*) usage "$_usage"; exit 42;;
esac ;;
info)
case $2 in
searx) info_searx ;;
*) usage "$_usage"; exit 42;;
esac ;;
option)
sudo_or_exit
case $2 in
new-key) set_new_key ;;
debug-on) enable_debug ;;
debug-off) disable_debug ;;
*) usage "$_usage"; exit 42;;
esac ;;
doc) rst-doc ;;
*) usage "ERROR: unknown or missing command $1"; exit 42;;
esac
}
install_all() {
MORTY_KEY="$(head -c 32 /dev/urandom | base64)"
rst_title "Install $SERVICE_NAME (service)"
assert_user
wait_key
install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
wait_key
install_morty
wait_key
systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
wait_key
if ! service_is_available "http://${MORTY_LISTEN}" ; then
err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
fi
if apache_is_installed; then
info_msg "Apache is installed on this host."
if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
install_apache_site
fi
elif nginx_is_installed; then
info_msg "nginx is installed on this host."
if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
install_nginx_site
fi
fi
info_searx
if ask_yn "Add image and result proxy to searx settings.yml?" Yn; then
"${REPO_ROOT}/utils/searx.sh" option result-proxy "${PUBLIC_URL_MORTY}" "${MORTY_KEY}"
"${REPO_ROOT}/utils/searx.sh" option image-proxy-on
fi
if ask_yn "Do you want to inspect the installation?" Ny; then
inspect_service
fi
}
remove_all() {
rst_title "De-Install $SERVICE_NAME (service)"
rst_para "\
It goes without saying that this script can only be used to remove
installations that were installed with this script."
if systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
drop_service_account "${SERVICE_USER}"
fi
}
assert_user() {
rst_title "user $SERVICE_USER" section
echo
tee_stderr 1 <<EOF | bash | prefix_stdout
useradd --shell /bin/bash --system \
--home-dir "$SERVICE_HOME" \
--comment 'Web content sanitizer proxy' $SERVICE_USER
mkdir "$SERVICE_HOME"
chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
groups $SERVICE_USER
EOF
SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
export SERVICE_HOME
echo "export SERVICE_HOME=$SERVICE_HOME"
cat > "$GO_ENV" <<EOF
export GOPATH=\$HOME/go-apps
export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
EOF
echo "Environment $GO_ENV has been setup."
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
EOF
}
morty_is_installed() {
[[ -f $SERVICE_HOME/go-apps/bin/morty ]]
}
_svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
install_morty() {
rst_title "Install morty in user's ~/go-apps" section
echo
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
go get -v -u github.com/asciimoo/morty
EOF
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
cd \$GOPATH/src/github.com/asciimoo/morty
go test
go test -benchmem -bench .
EOF
}
update_morty() {
rst_title "Update morty" section
echo
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
go get -v -u github.com/asciimoo/morty
EOF
tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
cd \$GOPATH/src/github.com/asciimoo/morty
go test
go test -benchmem -bench .
EOF
}
set_service_env_debug() {
# usage: set_service_env_debug [false|true]
# shellcheck disable=SC2034
local SERVICE_ENV_DEBUG="${1:-false}"
if systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
fi
}
inspect_service() {
rst_title "service status & log"
cat <<EOF
sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
MORTY_LISTEN : ${MORTY_LISTEN}
EOF
if service_account_is_available "$SERVICE_USER"; then
info_msg "service account $SERVICE_USER available."
else
err_msg "service account $SERVICE_USER not available!"
fi
if go_is_available "$SERVICE_USER"; then
info_msg "~$SERVICE_USER: go is installed"
else
err_msg "~$SERVICE_USER: go is not installed"
fi
if morty_is_installed; then
info_msg "~$SERVICE_USER: morty app is installed"
else
err_msg "~$SERVICE_USER: morty app is not installed!"
fi
if ! service_is_available "http://${MORTY_LISTEN}" ; then
err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
echo -e "${_Green}stop with [${_BCyan}CTRL-C${_Green}] or .."
wait_key
fi
if ! service_is_available "${PUBLIC_URL_MORTY}"; then
warn_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
if ! in_container; then
warn_msg "Check if public name is correct and routed or use the public IP from above."
fi
fi
if in_container; then
lxc_suite_info
else
info_msg "public URL --> ${PUBLIC_URL_MORTY}"
info_msg "morty URL --> http://${MORTY_LISTEN}"
fi
local _debug_on
if ask_yn "Enable morty debug mode (needs reinstall of systemd service)?"; then
enable_debug
_debug_on=1
else
systemctl --no-pager -l status "${SERVICE_NAME}"
fi
echo
# shellcheck disable=SC2059
printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
read -r -s -n1 -t 5
echo
while true; do
trap break 2
journalctl -f -u "${SERVICE_NAME}"
done
if [[ $_debug_on == 1 ]]; then
FORCE_SELECTION=Y disable_debug
fi
return 0
}
enable_debug() {
warn_msg "Do not enable debug in production enviroments!!"
info_msg "Enabling debug option needs to reinstall systemd service!"
set_service_env_debug true
}
disable_debug() {
info_msg "Disabling debug option needs to reinstall systemd service!"
set_service_env_debug false
}
set_new_key() {
rst_title "Set morty key"
echo
MORTY_KEY="$(head -c 32 /dev/urandom | base64)"
info_msg "morty key: '${MORTY_KEY}'"
warn_msg "this will need to reinstall services .."
MSG="${_Green}press any [${_BCyan}KEY${_Green}] to continue // stop with [${_BCyan}CTRL-C${_creset}]" wait_key
systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
"${REPO_ROOT}/utils/searx.sh" option result-proxy "${PUBLIC_URL_MORTY}" "${MORTY_KEY}"
"${REPO_ROOT}/utils/searx.sh" option image-proxy-on
}
install_apache_site() {
rst_title "Install Apache site $APACHE_MORTY_SITE"
rst_para "\
This installs a reverse proxy (ProxyPass) into apache site (${APACHE_MORTY_SITE})"
! apache_is_installed && err_msg "Apache is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
else
install_apache
fi
apache_install_site "${APACHE_MORTY_SITE}"
info_msg "testing public url .."
if ! service_is_available "${PUBLIC_URL_MORTY}"; then
err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
fi
}
remove_apache_site() {
rst_title "Remove Apache site $APACHE_MORTY_SITE"
rst_para "\
This removes apache site ${APACHE_MORTY_SITE}."
! apache_is_installed && err_msg "Apache is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
fi
apache_remove_site "$APACHE_MORTY_SITE"
}
install_nginx_site() {
rst_title "Install nginx site $NGINX_MORTY_SITE"
rst_para "\
This installs a reverse proxy (ProxyPass) into nginx site (${NGINX_MORTY_SITE})"
! nginx_is_installed && err_msg "nginx is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
else
install_nginx
fi
"${REPO_ROOT}/utils/searx.sh" install uwsgi
# shellcheck disable=SC2034
SEARX_SRC=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_SRC)
# shellcheck disable=SC2034
SEARX_URL_PATH=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_URL_PATH)
nginx_install_app "${NGINX_MORTY_SITE}"
info_msg "testing public url .."
if ! service_is_available "${PUBLIC_URL_MORTY}"; then
err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
fi
}
remove_nginx_site() {
rst_title "Remove nginx site $NGINX_MORTY_SITE"
rst_para "\
This removes nginx site ${NGINX_MORTY_SITE}."
! nginx_is_installed && err_msg "nginx is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
fi
nginx_remove_site "$NGINX_MORTY_SITE"
}
rst-doc() {
eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/morty.rst")\""
echo -e "\n.. START install systemd unit"
cat <<EOF
.. tabs::
.. group-tab:: systemd
.. code:: bash
EOF
eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
echo -e "\n.. END install systemd unit"
# for DIST_NAME in ubuntu-20.04 arch fedora; do
# (
# DIST_ID=${DIST_NAME%-*}
# DIST_VERS=${DIST_NAME#*-}
# [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
# # ...
# )
# done
}
# ----------------------------------------------------------------------------
main "$@"
# ----------------------------------------------------------------------------

869
utils/searx.sh Executable file
View file

@ -0,0 +1,869 @@
#!/usr/bin/env bash
# -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# shellcheck disable=SC2001
# shellcheck source=utils/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
# shellcheck source=utils/brand.env
source "${REPO_ROOT}/utils/brand.env"
source_dot_config
source "${REPO_ROOT}/utils/lxc-searx.env"
in_container && lxc_set_suite_env
# ----------------------------------------------------------------------------
# config
# ----------------------------------------------------------------------------
PUBLIC_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
SEARX_INTERNAL_HTTP="${SEARX_INTERNAL_HTTP:-127.0.0.1:8888}"
SEARX_URL_PATH="${SEARX_URL_PATH:-$(echo "${PUBLIC_URL}" \
| sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
[[ "${SEARX_URL_PATH}" == "${PUBLIC_URL}" ]] && SEARX_URL_PATH=/
SEARX_INSTANCE_NAME="${SEARX_INSTANCE_NAME:-searx@$(echo "$PUBLIC_URL" \
| sed -e 's,^.*://\([^\:/]*\).*,\1,g') }"
SERVICE_NAME="searx"
SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
# shellcheck disable=SC2034
SERVICE_GROUP="${SERVICE_USER}"
GIT_BRANCH="${GIT_BRANCH:-master}"
SEARX_PYENV="${SERVICE_HOME}/searx-pyenv"
SEARX_SRC="${SERVICE_HOME}/searx-src"
SEARX_SETTINGS_PATH="/etc/searx/settings.yml"
SEARX_UWSGI_APP="searx.ini"
# shellcheck disable=SC2034
SEARX_UWSGI_SOCKET="/run/uwsgi/app/searx/socket"
# apt packages
SEARX_PACKAGES_debian="\
virtualenv python3-dev python3-babel python3-venv
uwsgi uwsgi-plugin-python3
git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev
shellcheck"
BUILD_PACKAGES_debian="\
firefox graphviz imagemagick texlive-xetex librsvg2-bin
texlive-latex-recommended texlive-extra-utils ttf-dejavu
latexmk"
# pacman packages
SEARX_PACKAGES_arch="\
python-virtualenv python python-pip python-lxml python-babel
uwsgi uwsgi-plugin-python
git base-devel libxml2
shellcheck"
BUILD_PACKAGES_arch="\
firefox graphviz imagemagick texlive-bin extra/librsvg
texlive-core texlive-latexextra ttf-dejavu"
# dnf packages
SEARX_PACKAGES_fedora="\
virtualenv python python-pip python-lxml python-babel
uwsgi uwsgi-plugin-python3
git @development-tools libxml2
ShellCheck"
BUILD_PACKAGES_fedora="\
firefox graphviz graphviz-gd ImageMagick librsvg2-tools
texlive-xetex-bin texlive-collection-fontsrecommended
texlive-collection-latex dejavu-sans-fonts dejavu-serif-fonts
dejavu-sans-mono-fonts"
case $DIST_ID-$DIST_VERS in
ubuntu-16.04|ubuntu-18.04)
SEARX_PACKAGES="${SEARX_PACKAGES_debian}"
BUILD_PACKAGES="${BUILD_PACKAGES_debian}"
APACHE_PACKAGES="$APACHE_PACKAGES libapache2-mod-proxy-uwsgi"
;;
ubuntu-20.04)
# https://askubuntu.com/a/1224710
SEARX_PACKAGES="${SEARX_PACKAGES_debian} python-is-python3"
BUILD_PACKAGES="${BUILD_PACKAGES_debian}"
;;
ubuntu-*|debian-*)
SEARX_PACKAGES="${SEARX_PACKAGES_debian}"
BUILD_PACKAGES="${BUILD_PACKAGES_debian}"
;;
arch-*)
SEARX_PACKAGES="${SEARX_PACKAGES_arch}"
BUILD_PACKAGES="${BUILD_PACKAGES_arch}"
;;
fedora-*)
SEARX_PACKAGES="${SEARX_PACKAGES_fedora}"
BUILD_PACKAGES="${BUILD_PACKAGES_fedora}"
;;
esac
# Apache Settings
APACHE_SEARX_SITE="searx.conf"
# shellcheck disable=SC2034
CONFIG_FILES=(
"${uWSGI_APPS_AVAILABLE}/${SEARX_UWSGI_APP}"
)
# shellcheck disable=SC2034
CONFIG_BACKUP_ENCRYPTED=(
"${SEARX_SETTINGS_PATH}"
)
# ----------------------------------------------------------------------------
usage() {
# ----------------------------------------------------------------------------
# shellcheck disable=SC1117
cat <<EOF
usage::
$(basename "$0") shell
$(basename "$0") install [all|user|searx-src|pyenv|uwsgi|packages|buildhost]
$(basename "$0") update [searx]
$(basename "$0") remove [all|user|pyenv|searx-src]
$(basename "$0") activate [service]
$(basename "$0") deactivate [service]
$(basename "$0") inspect [service]
$(basename "$0") option [debug-[on|off]|image-proxy-[on|off]|result-proxy <url> <key>]
$(basename "$0") apache [install|remove]
shell
start interactive shell from user ${SERVICE_USER}
install / remove
:all: complete (de-) installation of searx service
:user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
:searx-src: clone $GIT_URL
:pyenv: create/remove virtualenv (python) in $SEARX_PYENV
:uwsgi: install searx uWSGI application
:settings: reinstall settings from ${REPO_ROOT}/searx/settings.yml
:packages: install needed packages from OS package manager
:buildhost: install packages from OS package manager needed by buildhosts
update searx
Update searx installation ($SERVICE_HOME)
activate service
activate and start service daemon (systemd unit)
deactivate service
stop and deactivate service daemon (systemd unit)
inspect service
run some small tests and inspect service's status and log
option
set one of the available options
apache
:install: apache site with the searx uwsgi app
:remove: apache site ${APACHE_FILTRON_SITE}
searx settings: ${SEARX_SETTINGS_PATH}
If needed, set PUBLIC_URL of your WEB service in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
PUBLIC_URL : ${PUBLIC_URL}
SEARX_INSTANCE_NAME : ${SEARX_INSTANCE_NAME}
SERVICE_USER : ${SERVICE_USER}
SEARX_INTERNAL_HTTP : http://${SEARX_INTERNAL_HTTP}
EOF
if in_container; then
# searx is listening on 127.0.0.1 and not available from outside container
# in containers the service is listening on 0.0.0.0 (see lxc-searx.env)
echo -e "${_BBlack}HINT:${_creset} searx only listen on loopback device" \
"${_BBlack}inside${_creset} the container."
for ip in $(global_IPs) ; do
if [[ $ip =~ .*:.* ]]; then
echo " container (IPv6): [${ip#*|}]"
else
# IPv4:
echo " container (IPv4): ${ip#*|}"
fi
done
fi
[[ -n ${1} ]] && err_msg "$1"
}
main() {
required_commands \
sudo systemctl install git wget curl \
|| exit
local _usage="unknown or missing $1 command $2"
case $1 in
--getenv) var="$2"; echo "${!var}"; exit 0;;
-h|--help) usage; exit 0;;
shell)
sudo_or_exit
interactive_shell "${SERVICE_USER}"
;;
inspect)
case $2 in
service)
sudo_or_exit
inspect_service
;;
*) usage "$_usage"; exit 42;;
esac ;;
install)
rst_title "$SEARX_INSTANCE_NAME" part
sudo_or_exit
case $2 in
all) install_all ;;
user) assert_user ;;
pyenv) create_pyenv ;;
searx-src) clone_searx ;;
settings) install_settings ;;
uwsgi)
install_searx_uwsgi
if ! service_is_available "http://${SEARX_INTERNAL_HTTP}"; then
err_msg "URL http://${SEARX_INTERNAL_HTTP} not available, check searx & uwsgi setup!"
fi
;;
packages)
pkg_install "$SEARX_PACKAGES"
;;
buildhost)
pkg_install "$SEARX_PACKAGES"
pkg_install "$BUILD_PACKAGES"
;;
*) usage "$_usage"; exit 42;;
esac ;;
update)
sudo_or_exit
case $2 in
searx) update_searx;;
*) usage "$_usage"; exit 42;;
esac ;;
remove)
sudo_or_exit
case $2 in
all) remove_all;;
user) drop_service_account "${SERVICE_USER}";;
pyenv) remove_pyenv ;;
searx-src) remove_searx ;;
*) usage "$_usage"; exit 42;;
esac ;;
activate)
sudo_or_exit
case $2 in
service)
activate_service ;;
*) usage "$_usage"; exit 42;;
esac ;;
deactivate)
sudo_or_exit
case $2 in
service) deactivate_service ;;
*) usage "$_usage"; exit 42;;
esac ;;
option)
sudo_or_exit
case $2 in
debug-on) echo; enable_debug ;;
debug-off) echo; disable_debug ;;
result-proxy) set_result_proxy "$3" "$4" ;;
image-proxy-on) enable_image_proxy ;;
image-proxy-off) disable_image_proxy ;;
*) usage "$_usage"; exit 42;;
esac ;;
apache)
sudo_or_exit
case $2 in
install) install_apache_site ;;
remove) remove_apache_site ;;
*) usage "$_usage"; exit 42;;
esac ;;
doc) rst-doc;;
*) usage "unknown or missing command $1"; exit 42;;
esac
}
_service_prefix=" ${_Yellow}|$SERVICE_USER|${_creset} "
install_all() {
rst_title "Install $SEARX_INSTANCE_NAME (service)"
pkg_install "$SEARX_PACKAGES"
wait_key
assert_user
wait_key
clone_searx
wait_key
create_pyenv
wait_key
install_settings
wait_key
test_local_searx
wait_key
install_searx_uwsgi
if ! service_is_available "http://${SEARX_INTERNAL_HTTP}"; then
err_msg "URL http://${SEARX_INTERNAL_HTTP} not available, check searx & uwsgi setup!"
fi
if ask_yn "Do you want to inspect the installation?" Ny; then
inspect_service
fi
}
update_searx() {
rst_title "Update searx instance"
echo
tee_stderr 0.3 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
cd ${SEARX_SRC}
git checkout -B "$GIT_BRANCH"
git pull
pip install -U pip
pip install -U setuptools
pip install -U wheel
pip install -U -e .
EOF
install_settings
uWSGI_restart "$SEARX_UWSGI_APP"
}
remove_all() {
rst_title "De-Install $SEARX_INSTANCE_NAME (service)"
rst_para "\
It goes without saying that this script can only be used to remove
installations that were installed with this script."
if ! ask_yn "Do you really want to deinstall $SEARX_INSTANCE_NAME?"; then
return
fi
remove_searx_uwsgi
drop_service_account "${SERVICE_USER}"
remove_settings
wait_key
if service_is_available "${PUBLIC_URL}"; then
MSG="** Don't forgett to remove your public site! (${PUBLIC_URL}) **" wait_key 10
fi
}
assert_user() {
rst_title "user $SERVICE_USER" section
echo
tee_stderr 1 <<EOF | bash | prefix_stdout
useradd --shell /bin/bash --system \
--home-dir "$SERVICE_HOME" \
--comment 'Privacy-respecting metasearch engine' $SERVICE_USER
mkdir "$SERVICE_HOME"
chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
groups $SERVICE_USER
EOF
#SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
#export SERVICE_HOME
#echo "export SERVICE_HOME=$SERVICE_HOME"
}
clone_is_available() {
[[ -f "$SEARX_SRC/.git/config" ]]
}
# shellcheck disable=SC2164
clone_searx() {
rst_title "Clone searx sources" section
echo
if ! sudo -i -u "$SERVICE_USER" ls -d "$REPO_ROOT" > /dev/null; then
die 42 "user '$SERVICE_USER' missed read permission: $REPO_ROOT"
fi
SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME 2>/dev/null)"
if [[ ! "${SERVICE_HOME}" ]]; then
err_msg "to clone searx sources, user $SERVICE_USER hast to be created first"
return 42
fi
export SERVICE_HOME
git_clone "$REPO_ROOT" "$SEARX_SRC" \
"$GIT_BRANCH" "$SERVICE_USER"
pushd "${SEARX_SRC}" > /dev/null
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
cd "${SEARX_SRC}"
git remote set-url origin ${GIT_URL}
git config user.email "$ADMIN_EMAIL"
git config user.name "$ADMIN_NAME"
git config --list
EOF
popd > /dev/null
}
install_settings() {
rst_title "${SEARX_SETTINGS_PATH}" section
if ! clone_is_available; then
err_msg "you have to install searx first"
exit 42
fi
mkdir -p "$(dirname ${SEARX_SETTINGS_PATH})"
if [[ ! -f ${SEARX_SETTINGS_PATH} ]]; then
info_msg "install settings ${REPO_ROOT}/searx/settings.yml"
info_msg " --> ${SEARX_SETTINGS_PATH}"
cp "${REPO_ROOT}/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
configure_searx
return
fi
rst_para "Diff between origin's setting file (+) and current (-):"
echo
$DIFF_CMD "${SEARX_SETTINGS_PATH}" "${SEARX_SRC}/searx/settings.yml"
local action
choose_one action "What should happen to the settings file? " \
"keep configuration unchanged" \
"use origin settings" \
"start interactiv shell"
case $action in
"keep configuration unchanged")
info_msg "leave settings file unchanged"
;;
"use origin settings")
backup_file "${SEARX_SETTINGS_PATH}"
info_msg "install origin settings"
cp "${SEARX_SRC}/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
;;
"start interactiv shell")
backup_file "${SEARX_SETTINGS_PATH}"
echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
sudo -H -i
rst_para 'Diff between new setting file (-) and current (+):'
echo
$DIFF_CMD "${SEARX_SRC}/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
wait_key
;;
esac
}
remove_settings() {
rst_title "remove searx settings" section
echo
info_msg "delete ${SEARX_SETTINGS_PATH}"
rm -f "${SEARX_SETTINGS_PATH}"
}
remove_searx() {
rst_title "Drop searx sources" section
if ask_yn "Do you really want to drop searx sources ($SEARX_SRC)?"; then
rm -rf "$SEARX_SRC"
else
rst_para "Leave searx sources unchanged."
fi
}
pyenv_is_available() {
[[ -f "${SEARX_PYENV}/bin/activate" ]]
}
create_pyenv() {
rst_title "Create virtualenv (python)" section
echo
if [[ ! -f "${SEARX_SRC}/manage.sh" ]]; then
err_msg "to create pyenv for searx, searx has to be cloned first"
return 42
fi
info_msg "create pyenv in ${SEARX_PYENV}"
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
rm -rf "${SEARX_PYENV}"
python3 -m venv "${SEARX_PYENV}"
grep -qFs -- 'source ${SEARX_PYENV}/bin/activate' ~/.profile \
|| echo 'source ${SEARX_PYENV}/bin/activate' >> ~/.profile
EOF
info_msg "inspect python's virtual environment"
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
command -v python && python --version
EOF
wait_key
info_msg "install needed python packages"
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
pip install -U pip
pip install -U setuptools
pip install -U wheel
pip install -U -e .
cd ${SEARX_SRC}
pip install -e .
EOF
}
remove_pyenv() {
rst_title "Remove virtualenv (python)" section
if ! ask_yn "Do you really want to drop ${SEARX_PYENV} ?"; then
return
fi
info_msg "remove pyenv activation from ~/.profile"
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
grep -v 'source ${SEARX_PYENV}/bin/activate' ~/.profile > ~/.profile.##
mv ~/.profile.## ~/.profile
EOF
rm -rf "${SEARX_PYENV}"
}
configure_searx() {
rst_title "Configure searx" section
rst_para "Setup searx config located at $SEARX_SETTINGS_PATH"
echo
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
cd ${SEARX_SRC}
sed -i -e "s/ultrasecretkey/$(openssl rand -hex 16)/g" "$SEARX_SETTINGS_PATH"
sed -i -e "s/{instance_name}/${SEARX_INSTANCE_NAME}/g" "$SEARX_SETTINGS_PATH"
EOF
}
test_local_searx() {
rst_title "Testing searx instance localy" section
echo
if service_is_available "http://${SEARX_INTERNAL_HTTP}" &>/dev/null; then
err_msg "URL/port http://${SEARX_INTERNAL_HTTP} is already in use, you"
err_msg "should stop that service before starting local tests!"
if ! ask_yn "Continue with local tests?"; then
return
fi
fi
sed -i -e "s/debug : False/debug : True/g" "$SEARX_SETTINGS_PATH"
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
export SEARX_SETTINGS_PATH="${SEARX_SETTINGS_PATH}"
cd ${SEARX_SRC}
timeout 10 python searx/webapp.py &
sleep 3
curl --location --verbose --head --insecure $SEARX_INTERNAL_HTTP
EOF
sed -i -e "s/debug : True/debug : False/g" "$SEARX_SETTINGS_PATH"
}
install_searx_uwsgi() {
rst_title "Install searx's uWSGI app (searx.ini)" section
echo
install_uwsgi
uWSGI_install_app "$SEARX_UWSGI_APP"
}
remove_searx_uwsgi() {
rst_title "Remove searx's uWSGI app (searx.ini)" section
echo
uWSGI_remove_app "$SEARX_UWSGI_APP"
}
activate_service() {
rst_title "Activate $SEARX_INSTANCE_NAME (service)" section
echo
uWSGI_enable_app "$SEARX_UWSGI_APP"
uWSGI_restart "$SEARX_UWSGI_APP"
}
deactivate_service() {
rst_title "De-Activate $SEARX_INSTANCE_NAME (service)" section
echo
uWSGI_disable_app "$SEARX_UWSGI_APP"
uWSGI_restart "$SEARX_UWSGI_APP"
}
enable_image_proxy() {
info_msg "try to enable image_proxy ..."
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
cd ${SEARX_SRC}
sed -i -e "s/image_proxy : False/image_proxy : True/g" "$SEARX_SETTINGS_PATH"
EOF
uWSGI_restart "$SEARX_UWSGI_APP"
}
disable_image_proxy() {
info_msg "try to enable image_proxy ..."
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
cd ${SEARX_SRC}
sed -i -e "s/image_proxy : True/image_proxy : False/g" "$SEARX_SETTINGS_PATH"
EOF
uWSGI_restart "$SEARX_UWSGI_APP"
}
enable_debug() {
warn_msg "Do not enable debug in production enviroments!!"
info_msg "try to enable debug mode ..."
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
cd ${SEARX_SRC}
sed -i -e "s/debug : False/debug : True/g" "$SEARX_SETTINGS_PATH"
EOF
uWSGI_restart "$SEARX_UWSGI_APP"
}
disable_debug() {
info_msg "try to disable debug mode ..."
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
cd ${SEARX_SRC}
sed -i -e "s/debug : True/debug : False/g" "$SEARX_SETTINGS_PATH"
EOF
uWSGI_restart "$SEARX_UWSGI_APP"
}
set_result_proxy() {
# usage: set_result_proxy <URL> [<key>]
info_msg "try to set result proxy: '$1' ($2)"
cp "${SEARX_SETTINGS_PATH}" "${SEARX_SETTINGS_PATH}.bak"
_set_result_proxy "$1" "$2" > "${SEARX_SETTINGS_PATH}"
}
_set_result_proxy() {
local line
local stage=0
local url=" url: $1"
local key=" key: !!binary \"$2\""
if [[ -z $2 ]]; then
key=
fi
while IFS= read -r line
do
if [[ $stage = 0 ]] || [[ $stage = 2 ]] ; then
if [[ $line =~ ^[[:space:]]*#*[[:space:]]*result_proxy[[:space:]]*:[[:space:]]*$ ]]; then
if [[ $stage = 0 ]]; then
stage=1
echo "result_proxy:"
continue
elif [[ $stage = 2 ]]; then
continue
fi
fi
fi
if [[ $stage = 1 ]] || [[ $stage = 2 ]] ; then
if [[ $line =~ ^[[:space:]]*#*[[:space:]]*url[[:space:]]*:[[:space:]] ]]; then
[[ $stage = 1 ]] && echo "$url"
continue
elif [[ $line =~ ^[[:space:]]*#*[[:space:]]*key[[:space:]]*:[[:space:]] ]]; then
[[ $stage = 1 ]] && [[ -n $key ]] && echo "$key"
continue
elif [[ $line =~ ^[[:space:]]*$ ]]; then
stage=2
fi
fi
echo "$line"
done < "${SEARX_SETTINGS_PATH}.bak"
}
function has_substring() {
[[ "$1" != "${2/$1/}" ]]
}
inspect_service() {
rst_title "service status & log"
cat <<EOF
sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
PUBLIC_URL : ${PUBLIC_URL}
SEARX_URL_PATH : ${SEARX_URL_PATH}
SEARX_INSTANCE_NAME : ${SEARX_INSTANCE_NAME}
SEARX_INTERNAL_HTTP : ${SEARX_INTERNAL_HTTP}
EOF
if service_account_is_available "$SERVICE_USER"; then
info_msg "Service account $SERVICE_USER exists."
else
err_msg "Service account $SERVICE_USER does not exists!"
fi
if pyenv_is_available; then
info_msg "~$SERVICE_USER: python environment is available."
else
err_msg "~$SERVICE_USER: python environment is not available!"
fi
if clone_is_available; then
info_msg "~$SERVICE_USER: Searx software is installed."
else
err_msg "~$SERVICE_USER: Missing searx software!"
fi
if uWSGI_app_enabled "$SEARX_UWSGI_APP"; then
info_msg "uWSGI app $SEARX_UWSGI_APP is enabled."
else
err_msg "uWSGI app $SEARX_UWSGI_APP not enabled!"
fi
uWSGI_app_available "$SEARX_UWSGI_APP" \
|| err_msg "uWSGI app $SEARX_UWSGI_APP not available!"
if in_container; then
lxc_suite_info
else
info_msg "public URL --> ${PUBLIC_URL}"
info_msg "internal URL --> http://${SEARX_INTERNAL_HTTP}"
fi
if ! service_is_available "http://${SEARX_INTERNAL_HTTP}"; then
err_msg "uWSGI app (service) at http://${SEARX_INTERNAL_HTTP} is not available!"
MSG="${_Green}[${_BCyan}CTRL-C${_Green}] to stop or [${_BCyan}KEY${_Green}] to continue"\
wait_key
fi
if ! service_is_available "${PUBLIC_URL}"; then
warn_msg "Public service at ${PUBLIC_URL} is not available!"
if ! in_container; then
warn_msg "Check if public name is correct and routed or use the public IP from above."
fi
fi
local _debug_on
if ask_yn "Enable searx debug mode?"; then
enable_debug
_debug_on=1
fi
echo
case $DIST_ID-$DIST_VERS in
ubuntu-*|debian-*)
systemctl --no-pager -l status "${SERVICE_NAME}"
;;
arch-*)
systemctl --no-pager -l status "uwsgi@${SERVICE_NAME%.*}"
;;
fedora-*)
systemctl --no-pager -l status uwsgi
;;
esac
# shellcheck disable=SC2059
printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
read -r -s -n1 -t 5
echo
while true; do
trap break 2
case $DIST_ID-$DIST_VERS in
ubuntu-*|debian-*) tail -f /var/log/uwsgi/app/searx.log ;;
arch-*) journalctl -f -u "uwsgi@${SERVICE_NAME%.*}" ;;
fedora-*) journalctl -f -u uwsgi ;;
esac
done
if [[ $_debug_on == 1 ]]; then
disable_debug
fi
return 0
}
install_apache_site() {
rst_title "Install Apache site $APACHE_SEARX_SITE"
rst_para "\
This installs the searx uwsgi app as apache site. If your server is public to
the internet, you should instead use a reverse proxy (filtron) to block
excessively bot queries."
! apache_is_installed && err_msg "Apache is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
else
install_apache
fi
apache_install_site --variant=uwsgi "${APACHE_SEARX_SITE}"
rst_title "Install searx's uWSGI app (searx.ini)" section
echo
uWSGI_install_app --variant=socket "$SEARX_UWSGI_APP"
if ! service_is_available "${PUBLIC_URL}"; then
err_msg "Public service at ${PUBLIC_URL} is not available!"
fi
}
remove_apache_site() {
rst_title "Remove Apache site ${APACHE_SEARX_SITE}"
rst_para "\
This removes apache site ${APACHE_SEARX_SITE}."
! apache_is_installed && err_msg "Apache is not installed."
if ! ask_yn "Do you really want to continue?" Yn; then
return
fi
apache_remove_site "${APACHE_SEARX_SITE}"
rst_title "Remove searx's uWSGI app (searx.ini)" section
echo
uWSGI_remove_app "$SEARX_UWSGI_APP"
}
rst-doc() {
local debian="${SEARX_PACKAGES_debian}"
local arch="${SEARX_PACKAGES_arch}"
local fedora="${SEARX_PACKAGES_fedora}"
local debian_build="${BUILD_PACKAGES_debian}"
local arch_build="${BUILD_PACKAGES_arch}"
local fedora_build="${BUILD_PACKAGES_fedora}"
debian="$(echo "${debian}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
arch="$(echo "${arch}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
fedora="$(echo "${fedora}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
debian_build="$(echo "${debian_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
arch_build="$(echo "${arch_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
fedora_build="$(echo "${fedora_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/searx.rst")\""
# I use ubuntu-20.04 here to demonstrate that versions are also suported,
# normaly debian-* and ubuntu-* are most the same.
for DIST_NAME in ubuntu-20.04 arch fedora; do
(
DIST_ID=${DIST_NAME%-*}
DIST_VERS=${DIST_NAME#*-}
[[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
uWSGI_distro_setup
echo -e "\n.. START searx uwsgi-description $DIST_NAME"
case $DIST_ID-$DIST_VERS in
ubuntu-*|debian-*) cat <<EOF
# init.d --> /usr/share/doc/uwsgi/README.Debian.gz
# For uWSGI debian uses the LSB init process, this might be changed
# one day, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=833067
create ${uWSGI_APPS_AVAILABLE}/${SEARX_UWSGI_APP}
enable: sudo -H ln -s ${uWSGI_APPS_AVAILABLE}/${SEARX_UWSGI_APP} ${uWSGI_APPS_ENABLED}/
start: sudo -H service uwsgi start ${SEARX_UWSGI_APP%.*}
restart: sudo -H service uwsgi restart ${SEARX_UWSGI_APP%.*}
stop: sudo -H service uwsgi stop ${SEARX_UWSGI_APP%.*}
disable: sudo -H rm ${uWSGI_APPS_ENABLED}/${SEARX_UWSGI_APP}
EOF
;;
arch-*) cat <<EOF
# systemd --> /usr/lib/systemd/system/uwsgi@.service
# For uWSGI archlinux uses systemd template units, see
# - http://0pointer.de/blog/projects/instances.html
# - https://uwsgi-docs.readthedocs.io/en/latest/Systemd.html#one-service-per-app-in-systemd
create: ${uWSGI_APPS_ENABLED}/${SEARX_UWSGI_APP}
enable: sudo -H systemctl enable uwsgi@${SEARX_UWSGI_APP%.*}
start: sudo -H systemctl start uwsgi@${SEARX_UWSGI_APP%.*}
restart: sudo -H systemctl restart uwsgi@${SEARX_UWSGI_APP%.*}
stop: sudo -H systemctl stop uwsgi@${SEARX_UWSGI_APP%.*}
disable: sudo -H systemctl disable uwsgi@${SEARX_UWSGI_APP%.*}
EOF
;;
fedora-*) cat <<EOF
# systemd --> /usr/lib/systemd/system/uwsgi.service
# The unit file starts uWSGI in emperor mode (/etc/uwsgi.ini), see
# - https://uwsgi-docs.readthedocs.io/en/latest/Emperor.html
create: ${uWSGI_APPS_ENABLED}/${SEARX_UWSGI_APP}
restart: sudo -H touch ${uWSGI_APPS_ENABLED}/${SEARX_UWSGI_APP}
disable: sudo -H rm ${uWSGI_APPS_ENABLED}/${SEARX_UWSGI_APP}
EOF
;;
esac
echo -e ".. END searx uwsgi-description $DIST_NAME"
echo -e "\n.. START searx uwsgi-appini $DIST_NAME"
eval "echo \"$(< "${TEMPLATES}/${uWSGI_APPS_AVAILABLE}/${SEARX_UWSGI_APP}")\""
echo -e "\n.. END searx uwsgi-appini $DIST_NAME"
)
done
}
# ----------------------------------------------------------------------------
main "$@"
# ----------------------------------------------------------------------------

View file

@ -0,0 +1,48 @@
# -*- coding: utf-8; mode: python -*-
"""Implement some sphinx-build tools.
"""
import os
import sys
from sphinx.util.pycompat import execfile_
# ------------------------------------------------------------------------------
def load_sphinx_config(namespace):
# ------------------------------------------------------------------------------
u"""Load an additional configuration file into *namespace*.
The name of the configuration file is taken from the environment
``SPHINX_CONF``. The external configuration file extends (or overwrites) the
configuration values from the origin ``conf.py``. With this you are able to
maintain *build themes*. To your docs/conf.py add::
from sphinx_build_tools import load_sphinx_config
...
# Since loadConfig overwrites settings from the global namespace, it has to be
# the last statement in the conf.py file
load_sphinx_config(globals())
"""
config_file = os.environ.get("SPHINX_CONF", None)
if (config_file is not None
and os.path.normpath(namespace["__file__"]) != os.path.normpath(config_file) ):
config_file = os.path.abspath(config_file)
if os.path.isfile(config_file):
sys.stdout.write(
"load additional sphinx-config: %s\n"
% config_file)
config = namespace.copy()
config['__file__'] = config_file
execfile_(config_file, config)
del config['__file__']
namespace.update(config)
else:
sys.stderr.write(
"WARNING: additional sphinx-config not found: %s\n"
% config_file)

1
utils/templates/etc/apache2 Symbolic link
View file

@ -0,0 +1 @@
httpd

View file

@ -0,0 +1,129 @@
[
{
"name": "roboagent limit",
"filters": [
"Header:User-Agent=(curl|cURL|Wget|python-requests|Scrapy|FeedFetcher|Go-http-client|Ruby|UniversalFeedParser)"
],
"limit": 0,
"stop": true,
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
},
{
"name": "botlimit",
"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)"
],
"limit": 0,
"stop": true,
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
},
{
"name": "suspiciously frequent IP",
"filters": [],
"interval": 600,
"limit": 30,
"aggregations": [
"Header:X-Forwarded-For"
],
"actions":[
{"name":"log"}
]
},
{
"name": "search request",
"filters": [
"Param:q",
"Path=^(/|/search)$"
],
"interval": 61,
"limit": 999,
"subrules": [
{
"name": "missing Accept-Language",
"filters": ["!Header:Accept-Language"],
"limit": 0,
"stop": true,
"actions": [
{"name":"log"},
{"name": "block",
"params": {"message": "Rate limit exceeded"}}
]
},
{
"name": "suspiciously Connection=close header",
"filters": ["Header:Connection=close"],
"limit": 0,
"stop": true,
"actions": [
{"name":"log"},
{"name": "block",
"params": {"message": "Rate limit exceeded"}}
]
},
{
"name": "IP limit",
"interval": 61,
"limit": 9,
"stop": true,
"aggregations": [
"Header:X-Forwarded-For"
],
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
},
{
"name": "rss/json limit",
"filters": [
"Param:format=(csv|json|rss)"
],
"interval": 121,
"limit": 2,
"stop": true,
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
},
{
"name": "useragent limit",
"interval": 61,
"limit": 199,
"aggregations": [
"Header:User-Agent"
],
"actions": [
{ "name": "log"},
{ "name": "block",
"params": {
"message": "Rate limit exceeded"
}
}
]
}
]
}
]

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8; mode: apache -*-
LoadModule headers_module ${APACHE_MODULES}/mod_headers.so
LoadModule proxy_module ${APACHE_MODULES}/mod_proxy.so
LoadModule proxy_http_module ${APACHE_MODULES}/mod_proxy_http.so
#LoadModule setenvif_module ${APACHE_MODULES}/mod_setenvif.so
# SetEnvIf Request_URI "${PUBLIC_URL_PATH_MORTY}" dontlog
# CustomLog /dev/null combined env=dontlog
<Location ${PUBLIC_URL_PATH_MORTY} >
<IfModule mod_security2.c>
SecRuleEngine Off
</IfModule>
Require all granted
Order deny,allow
Deny from all
#Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass http://${MORTY_LISTEN}
RequestHeader set X-Script-Name ${PUBLIC_URL_PATH_MORTY}
</Location>

View file

@ -0,0 +1,33 @@
# -*- coding: utf-8; mode: apache -*-
LoadModule headers_module ${APACHE_MODULES}/mod_headers.so
LoadModule proxy_module ${APACHE_MODULES}/mod_proxy.so
LoadModule proxy_http_module ${APACHE_MODULES}/mod_proxy_http.so
#LoadModule setenvif_module ${APACHE_MODULES}/mod_setenvif.so
# SetEnvIf Request_URI "${FILTRON_URL_PATH}" dontlog
# CustomLog /dev/null combined env=dontlog
# SecRuleRemoveById 981054
# SecRuleRemoveById 981059
# SecRuleRemoveById 981060
# SecRuleRemoveById 950907
<Location ${FILTRON_URL_PATH} >
<IfModule mod_security2.c>
SecRuleEngine Off
</IfModule>
Require all granted
Order deny,allow
Deny from all
#Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass http://${FILTRON_LISTEN}
RequestHeader set X-Script-Name ${FILTRON_URL_PATH}
</Location>

View file

@ -0,0 +1,27 @@
# -*- coding: utf-8; mode: apache -*-
LoadModule headers_module ${APACHE_MODULES}/mod_headers.so
LoadModule proxy_module ${APACHE_MODULES}/mod_proxy.so
LoadModule proxy_uwsgi_module ${APACHE_MODULES}/mod_proxy_uwsgi.so
# LoadModule setenvif_module ${APACHE_MODULES}/mod_setenvif.so
# SetEnvIf Request_URI "${SEARX_URL_PATH}" dontlog
# CustomLog /dev/null combined env=dontlog
<Location ${SEARX_URL_PATH}>
<IfModule mod_security2.c>
SecRuleEngine Off
</IfModule>
Require all granted
Order deny,allow
Deny from all
# Allow from fd00::/8 192.168.0.0/16 fe80::/10 127.0.0.0/8 ::1
Allow from all
ProxyPreserveHost On
ProxyPass unix:${SEARX_UWSGI_SOCKET}|uwsgi://uwsgi-uds-searx/
</Location>

View file

@ -0,0 +1,11 @@
# https://example.org/morty
location /morty {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host \$http_host;
proxy_set_header Connection \$http_connection;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Scheme \$scheme;
}

View file

@ -0,0 +1,16 @@
# https://example.org/searx
location ${SEARX_URL_PATH} {
proxy_pass http://127.0.0.1:4004/;
proxy_set_header Host \$http_host;
proxy_set_header Connection \$http_connection;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Scheme \$scheme;
proxy_set_header X-Script-Name ${SEARX_URL_PATH};
}
location ${SEARX_URL_PATH}/static {
alias ${SEARX_SRC}/searx/static;
}

View file

@ -0,0 +1,80 @@
[uwsgi]
# uWSGI core
# ----------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#uwsgi-core
# Who will run the code
uid = ${SERVICE_USER}
gid = ${SERVICE_GROUP}
# chdir to specified directory before apps loading
chdir = ${SEARX_SRC}/searx
# searx configuration (settings.yml)
env = SEARX_SETTINGS_PATH=${SEARX_SETTINGS_PATH}
# disable logging for privacy
logger = systemd
disable-logging = true
# The right granted on the created socket
chmod-socket = 666
# Plugin to use and interpretor config
single-interpreter = true
# enable master process
master = true
# load apps in each worker instead of the master
lazy-apps = true
# load uWSGI plugins
plugin = python
# By default the Python plugin does not initialize the GIL. This means your
# app-generated threads will not run. If you need threads, remember to enable
# them with enable-threads. Running uWSGI in multithreading mode (with the
# threads options) will automatically enable threading support. This *strange*
# default behaviour is for performance reasons.
enable-threads = true
# plugin: python
# --------------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-python
# load a WSGI module
module = searx.webapp
# set PYTHONHOME/virtualenv
virtualenv = ${SEARX_PYENV}
# add directory (or glob) to pythonpath
pythonpath = ${SEARX_SRC}
# speak to upstream
# -----------------
#
# Activate the 'http' configuration for filtron or activate the 'socket'
# configuration if you setup your HTTP server to use uWSGI protocol via sockets.
# using IP:
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-http
# Native HTTP support: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
http = ${SEARX_INTERNAL_HTTP}
# using unix-sockets:
#
# On some distributions you need to create the app folder for the sockets::
#
# mkdir -p /run/uwsgi/app/searx
# chown -R ${SERVICE_USER}:${SERVICE_GROUP} /run/uwsgi/app/searx
#
# socket = /run/uwsgi/app/searx/socket

View file

@ -0,0 +1,80 @@
[uwsgi]
# uWSGI core
# ----------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#uwsgi-core
# Who will run the code
uid = ${SERVICE_USER}
gid = ${SERVICE_GROUP}
# chdir to specified directory before apps loading
chdir = ${SEARX_SRC}/searx
# searx configuration (settings.yml)
env = SEARX_SETTINGS_PATH=${SEARX_SETTINGS_PATH}
# disable logging for privacy
logger = systemd
disable-logging = true
# The right granted on the created socket
chmod-socket = 666
# Plugin to use and interpretor config
single-interpreter = true
# enable master process
master = true
# load apps in each worker instead of the master
lazy-apps = true
# load uWSGI plugins
plugin = python
# By default the Python plugin does not initialize the GIL. This means your
# app-generated threads will not run. If you need threads, remember to enable
# them with enable-threads. Running uWSGI in multithreading mode (with the
# threads options) will automatically enable threading support. This *strange*
# default behaviour is for performance reasons.
enable-threads = true
# plugin: python
# --------------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-python
# load a WSGI module
module = searx.webapp
# set PYTHONHOME/virtualenv
virtualenv = ${SEARX_PYENV}
# add directory (or glob) to pythonpath
pythonpath = ${SEARX_SRC}
# speak to upstream
# -----------------
#
# Activate the 'http' configuration for filtron or activate the 'socket'
# configuration if you setup your HTTP server to use uWSGI protocol via sockets.
# using IP:
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-http
# Native HTTP support: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
# http = ${SEARX_INTERNAL_HTTP}
# using unix-sockets:
#
# On some distributions you need to create the app folder for the sockets::
#
# mkdir -p /run/uwsgi/app/searx
# chown -R ${SERVICE_USER}:${SERVICE_GROUP} /run/uwsgi/app/searx
#
socket = /run/uwsgi/app/searx/socket

View file

@ -0,0 +1,79 @@
[uwsgi]
# uWSGI core
# ----------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#uwsgi-core
# Who will run the code
uid = ${SERVICE_USER}
gid = ${SERVICE_GROUP}
# chdir to specified directory before apps loading
chdir = ${SEARX_SRC}/searx
# searx configuration (settings.yml)
env = SEARX_SETTINGS_PATH=${SEARX_SETTINGS_PATH}
# disable logging for privacy
disable-logging = true
# The right granted on the created socket
chmod-socket = 666
# Plugin to use and interpretor config
single-interpreter = true
# enable master process
master = true
# load apps in each worker instead of the master
lazy-apps = true
# load uWSGI plugins
plugin = python3,http
# By default the Python plugin does not initialize the GIL. This means your
# app-generated threads will not run. If you need threads, remember to enable
# them with enable-threads. Running uWSGI in multithreading mode (with the
# threads options) will automatically enable threading support. This *strange*
# default behaviour is for performance reasons.
enable-threads = true
# plugin: python
# --------------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-python
# load a WSGI module
module = searx.webapp
# set PYTHONHOME/virtualenv
virtualenv = ${SEARX_PYENV}
# add directory (or glob) to pythonpath
pythonpath = ${SEARX_SRC}
# speak to upstream
# -----------------
#
# Activate the 'http' configuration for filtron or activate the 'socket'
# configuration if you setup your HTTP server to use uWSGI protocol via sockets.
# using IP:
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-http
# Native HTTP support: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
http = ${SEARX_INTERNAL_HTTP}
# using unix-sockets:
#
# On some distributions you need to create the app folder for the sockets::
#
# mkdir -p /run/uwsgi/app/searx
# chmod -R ${SERVICE_USER}:${SERVICE_GROUP} /run/uwsgi/app/searx
#
# socket = /run/uwsgi/app/searx/socket

View file

@ -0,0 +1,79 @@
[uwsgi]
# uWSGI core
# ----------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#uwsgi-core
# Who will run the code
uid = ${SERVICE_USER}
gid = ${SERVICE_GROUP}
# chdir to specified directory before apps loading
chdir = ${SEARX_SRC}/searx
# searx configuration (settings.yml)
env = SEARX_SETTINGS_PATH=${SEARX_SETTINGS_PATH}
# disable logging for privacy
disable-logging = true
# The right granted on the created socket
chmod-socket = 666
# Plugin to use and interpretor config
single-interpreter = true
# enable master process
master = true
# load apps in each worker instead of the master
lazy-apps = true
# load uWSGI plugins
plugin = python3,http
# By default the Python plugin does not initialize the GIL. This means your
# app-generated threads will not run. If you need threads, remember to enable
# them with enable-threads. Running uWSGI in multithreading mode (with the
# threads options) will automatically enable threading support. This *strange*
# default behaviour is for performance reasons.
enable-threads = true
# plugin: python
# --------------
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-python
# load a WSGI module
module = searx.webapp
# set PYTHONHOME/virtualenv
virtualenv = ${SEARX_PYENV}
# add directory (or glob) to pythonpath
pythonpath = ${SEARX_SRC}
# speak to upstream
# -----------------
#
# Activate the 'http' configuration for filtron or activate the 'socket'
# configuration if you setup your HTTP server to use uWSGI protocol via sockets.
# using IP:
#
# https://uwsgi-docs.readthedocs.io/en/latest/Options.html#plugin-http
# Native HTTP support: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
# http = ${SEARX_INTERNAL_HTTP}
# using unix-sockets:
#
# On some distributions you need to create the app folder for the sockets::
#
# mkdir -p /run/uwsgi/app/searx
# chown -R ${SERVICE_USER}:${SERVICE_GROUP} /run/uwsgi/app/searx
#
socket = /run/uwsgi/app/searx/socket

View file

@ -0,0 +1,29 @@
[Unit]
Description=${SERVICE_NAME}
After=syslog.target
After=network.target
[Service]
Type=simple
User=${SERVICE_USER}
Group=${SERVICE_GROUP}
WorkingDirectory=${SERVICE_HOME}
ExecStart=${SERVICE_HOME}/go-apps/bin/filtron -api '${FILTRON_API}' -listen '${FILTRON_LISTEN}' -rules '${FILTRON_RULES}' -target '${FILTRON_TARGET}'
Restart=always
Environment=USER=${SERVICE_USER} HOME=${SERVICE_HOME}
# Some distributions may not support these hardening directives. If you cannot
# start the service due to an unknown option, comment out the ones not supported
# by your version of systemd.
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,29 @@
[Unit]
Description=${SERVICE_NAME}
After=syslog.target
After=network.target
[Service]
Type=simple
User=${SERVICE_USER}
Group=${SERVICE_GROUP}
WorkingDirectory=${SERVICE_HOME}
ExecStart=${SERVICE_HOME}/go-apps/bin/morty -key '${MORTY_KEY}' -listen '${MORTY_LISTEN}' -timeout ${MORTY_TIMEOUT}
Restart=always
Environment=USER=${SERVICE_USER} HOME=${SERVICE_HOME} DEBUG=${SERVICE_ENV_DEBUG}
# Some distributions may not support these hardening directives. If you cannot
# start the service due to an unknown option, comment out the ones not supported
# by your version of systemd.
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target