mirror of
https://github.com/searxng/searxng.git
synced 2025-11-15 02:53:09 -05:00
Since #5280 has been merged, msgspec, like yaml, is a fixed part of the SearXNG *settings framework* and therefore, like yaml, must be installed in the virtual environment before installing SearXNG (``searx``). The actual reason is that in SearXNG we store settings in the configuration that are required for the installation of the ``searx`` package. This means that these settings (from settings.yml) are read in during the installation, and all the necessary tools for this (pyyaml, msgspec, setuptools, etc.) must be installed beforehand (chicken or the egg dilemma). Related: - https://github.com/searxng/searxng/pull/5353 - https://github.com/searxng/searxng/pull/5346 - https://github.com/searxng/searxng/pull/5280 - https://github.com/searxng/searxng/pull/5254 Closes: https://github.com/searxng/searxng/issues/5357 Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
1010 lines
32 KiB
Bash
Executable File
1010 lines
32 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
# shellcheck disable=SC2001
|
|
|
|
# Script options from the environment:
|
|
SEARXNG_UWSGI_USE_SOCKET="${SEARXNG_UWSGI_USE_SOCKET:-true}"
|
|
|
|
# shellcheck source=utils/lib.sh
|
|
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
# shellcheck source=utils/lib_redis.sh
|
|
source "$(dirname "${BASH_SOURCE[0]}")/lib_redis.sh"
|
|
# shellcheck source=utils/lib_valkey.sh
|
|
source "$(dirname "${BASH_SOURCE[0]}")/lib_valkey.sh"
|
|
# shellcheck source=utils/brand.sh
|
|
source "${REPO_ROOT}/utils/brand.sh"
|
|
|
|
SERVICE_NAME="searxng"
|
|
SERVICE_USER="searxng"
|
|
SERVICE_HOME="/usr/local/searxng"
|
|
SERVICE_GROUP="searxng"
|
|
|
|
SEARXNG_SRC="${SERVICE_HOME}/searxng-src"
|
|
# shellcheck disable=SC2034
|
|
SEARXNG_STATIC="${SEARXNG_SRC}/searx/static"
|
|
|
|
SEARXNG_PYENV="${SERVICE_HOME}/searx-pyenv"
|
|
SEARXNG_SETTINGS_PATH="/etc/searxng/settings.yml"
|
|
SEARXNG_UWSGI_APP="searxng.ini"
|
|
|
|
SEARXNG_INTERNAL_HTTP="${SEARXNG_BIND_ADDRESS}:${SEARXNG_PORT}"
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
SEARXNG_UWSGI_SOCKET="${SERVICE_HOME}/run/socket"
|
|
else
|
|
SEARXNG_UWSGI_SOCKET=
|
|
fi
|
|
|
|
# SEARXNG_URL: the public URL of the instance (https://example.org/searxng). The
|
|
# value is taken from environment ${SEARXNG_URL} in ./utils/brand.env. This
|
|
# variable is an empty string if server.base_url in the settings.yml is set to
|
|
# 'false'.
|
|
|
|
SEARXNG_URL="${SEARXNG_URL:-http://$(uname -n)/searxng}"
|
|
SEARXNG_URL="${SEARXNG_URL%/}" # if exists, remove trailing slash
|
|
SEARXNG_URL_PATH="$(echo "${SEARXNG_URL}" | sed -e 's,^.*://[^/]*\(/.*\),\1,g')"
|
|
[[ "${SEARXNG_URL_PATH}" == "${SEARXNG_URL}" ]] && SEARXNG_URL_PATH=/
|
|
|
|
# Apache settings
|
|
|
|
APACHE_SEARXNG_SITE="searxng.conf"
|
|
|
|
# nginx settings
|
|
|
|
NGINX_SEARXNG_SITE="searxng.conf"
|
|
|
|
# apt packages
|
|
|
|
SEARXNG_PACKAGES_debian="\
|
|
python3-dev python3-babel python3-venv python-is-python3
|
|
uwsgi uwsgi-plugin-python3
|
|
git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev"
|
|
|
|
SEARXNG_BUILD_PACKAGES_debian="\
|
|
graphviz imagemagick texlive-xetex librsvg2-bin
|
|
texlive-latex-recommended texlive-extra-utils fonts-dejavu
|
|
latexmk shellcheck"
|
|
|
|
# pacman packages
|
|
|
|
SEARXNG_PACKAGES_arch="\
|
|
python python-pip python-lxml python-babel
|
|
uwsgi uwsgi-plugin-python
|
|
git base-devel libxml2"
|
|
|
|
SEARXNG_BUILD_PACKAGES_arch="\
|
|
graphviz imagemagick texlive-bin extra/librsvg
|
|
texlive-core texlive-latexextra ttf-dejavu shellcheck"
|
|
|
|
# dnf packages
|
|
|
|
SEARXNG_PACKAGES_fedora="\
|
|
python python-pip python-lxml python-babel python3-devel
|
|
uwsgi uwsgi-plugin-python3
|
|
git @development-tools libxml2 openssl"
|
|
|
|
SEARXNG_BUILD_PACKAGES_fedora="\
|
|
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 ShellCheck"
|
|
|
|
case $DIST_ID-$DIST_VERS in
|
|
ubuntu-18.04)
|
|
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian}"
|
|
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
|
|
APACHE_PACKAGES="$APACHE_PACKAGES libapache2-mod-proxy-uwsgi"
|
|
;;
|
|
ubuntu-* | debian-*)
|
|
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian} python-is-python3"
|
|
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
|
|
;;
|
|
arch-*)
|
|
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_arch}"
|
|
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_arch}"
|
|
;;
|
|
fedora-*)
|
|
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_fedora}"
|
|
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_fedora}"
|
|
;;
|
|
esac
|
|
|
|
_service_prefix=" ${_Yellow}|${SERVICE_USER}|${_creset} "
|
|
|
|
usage() {
|
|
|
|
# shellcheck disable=SC1117
|
|
cat <<EOF
|
|
usage:
|
|
$(basename "$0") install [all|user|pyenv|settings|uwsgi|valkey|nginx|apache|searxng-src|packages|buildhost]
|
|
$(basename "$0") remove [all|user|pyenv|settings|uwsgi|valkey|nginx|apache]
|
|
$(basename "$0") instance [cmd|update|check|localtest|inspect]
|
|
install|remove:
|
|
all : complete (de-) installation of the SearXNG service
|
|
user : service user '${SERVICE_USER}' (${SERVICE_HOME})
|
|
pyenv : virtualenv (python) in ${SEARXNG_PYENV}
|
|
settings : settings from ${SEARXNG_SETTINGS_PATH}
|
|
uwsgi : SearXNG's uWSGI app ${SEARXNG_UWSGI_APP}
|
|
nginx : HTTP site ${NGINX_APPS_AVAILABLE}/${NGINX_SEARXNG_SITE}
|
|
apache : HTTP site ${APACHE_SITES_AVAILABLE}/${APACHE_SEARXNG_SITE}
|
|
install:
|
|
valkey : install a local valkey server
|
|
remove:
|
|
redis : remove a local redis server ${REDIS_HOME}/run/redis.sock
|
|
install:
|
|
searxng-src : clone ${GIT_URL} into ${SEARXNG_SRC}
|
|
packages : installs packages from OS package manager required by SearXNG
|
|
buildhost : installs packages from OS package manager required by a SearXNG buildhost
|
|
instance:
|
|
update : update SearXNG instance (git fetch + reset & update settings.yml)
|
|
check : run checks from utils/searxng_check.py in the active installation
|
|
inspect : run some small tests and inspect SearXNG's server status and log
|
|
get_setting : get settings value from running SearXNG instance
|
|
cmd : run command in SearXNG instance's environment (e.g. bash)
|
|
EOF
|
|
searxng.instance.env
|
|
[[ -n ${1} ]] && err_msg "$1"
|
|
}
|
|
|
|
searxng.instance.env() {
|
|
echo "uWSGI:"
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
echo " SEARXNG_UWSGI_SOCKET : ${SEARXNG_UWSGI_SOCKET}"
|
|
else
|
|
echo " SEARXNG_INTERNAL_HTTP: ${SEARXNG_INTERNAL_HTTP}"
|
|
fi
|
|
cat <<EOF
|
|
environment:
|
|
GIT_URL : ${GIT_URL}
|
|
GIT_BRANCH : ${GIT_BRANCH}
|
|
SEARXNG_URL : ${SEARXNG_URL}
|
|
SEARXNG_PORT : ${SEARXNG_PORT}
|
|
SEARXNG_BIND_ADDRESS : ${SEARXNG_BIND_ADDRESS}
|
|
EOF
|
|
}
|
|
|
|
main() {
|
|
case $1 in
|
|
install | remove | instance)
|
|
nginx_distro_setup
|
|
apache_distro_setup
|
|
uWSGI_distro_setup
|
|
required_commands \
|
|
sudo systemctl install git wget curl ||
|
|
exit
|
|
;;
|
|
esac
|
|
|
|
local _usage="unknown or missing $1 command $2"
|
|
|
|
case $1 in
|
|
--getenv)
|
|
var="$2"
|
|
echo "${!var}"
|
|
exit 0
|
|
;;
|
|
--cmd)
|
|
shift
|
|
"$@"
|
|
;;
|
|
-h | --help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
install)
|
|
sudo_or_exit
|
|
case $2 in
|
|
all) searxng.install.all ;;
|
|
user) searxng.install.user ;;
|
|
pyenv) searxng.install.pyenv ;;
|
|
searxng-src) searxng.install.clone ;;
|
|
settings) searxng.install.settings ;;
|
|
uwsgi) searxng.install.uwsgi ;;
|
|
packages) searxng.install.packages ;;
|
|
buildhost) searxng.install.buildhost ;;
|
|
nginx) searxng.nginx.install ;;
|
|
apache) searxng.apache.install ;;
|
|
valkey) searxng.install.valkey ;;
|
|
*)
|
|
usage "$_usage"
|
|
exit 42
|
|
;;
|
|
esac
|
|
;;
|
|
remove)
|
|
sudo_or_exit
|
|
case $2 in
|
|
all) searxng.remove.all ;;
|
|
user) drop_service_account "${SERVICE_USER}" ;;
|
|
pyenv) searxng.remove.pyenv ;;
|
|
settings) searxng.remove.settings ;;
|
|
uwsgi) searxng.remove.uwsgi ;;
|
|
apache) searxng.apache.remove ;;
|
|
remove) searxng.nginx.remove ;;
|
|
valkey) searxng.remove.valkey ;;
|
|
redis) searxng.remove.redis ;;
|
|
*)
|
|
usage "$_usage"
|
|
exit 42
|
|
;;
|
|
esac
|
|
;;
|
|
instance)
|
|
case $2 in
|
|
update)
|
|
sudo_or_exit
|
|
searxng.instance.update
|
|
;;
|
|
check)
|
|
sudo_or_exit
|
|
searxng.instance.self.call searxng.check
|
|
;;
|
|
inspect)
|
|
sudo_or_exit
|
|
searxng.instance.inspect
|
|
;;
|
|
cmd)
|
|
sudo_or_exit
|
|
shift
|
|
shift
|
|
searxng.instance.exec "$@"
|
|
;;
|
|
get_setting)
|
|
shift
|
|
shift
|
|
searxng.instance.get_setting "$@"
|
|
;;
|
|
call)
|
|
# call a function in instance's environment
|
|
shift
|
|
shift
|
|
searxng.instance.self.call "$@"
|
|
;;
|
|
_call)
|
|
shift
|
|
shift
|
|
"$@"
|
|
;;
|
|
*)
|
|
usage "$_usage"
|
|
exit 42
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
local cmd="$1"
|
|
_type="$(type -t "$cmd")"
|
|
if [ "$_type" != 'function' ]; then
|
|
usage "unknown or missing command $1"
|
|
exit 42
|
|
else
|
|
"$cmd" "$@"
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
searxng.install.all() {
|
|
rst_title "SearXNG installation" part
|
|
|
|
local valkey_url
|
|
|
|
rst_title "SearXNG"
|
|
searxng.install.packages
|
|
wait_key 10
|
|
searxng.install.user
|
|
wait_key 10
|
|
searxng.install.clone
|
|
wait_key
|
|
searxng.install.pyenv
|
|
wait_key
|
|
searxng.install.settings
|
|
wait_key
|
|
searxng.instance.localtest
|
|
wait_key
|
|
searxng.install.uwsgi
|
|
wait_key
|
|
|
|
rst_title "Valkey DB"
|
|
searxng.install.valkey.db
|
|
|
|
rst_title "HTTP Server"
|
|
searxng.install.http.site
|
|
|
|
rst_title "Finalize installation"
|
|
if ask_yn "Do you want to run some checks?" Yn; then
|
|
searxng.instance.self.call searxng.check
|
|
fi
|
|
}
|
|
|
|
searxng.install.valkey.db() {
|
|
local valkey_url
|
|
|
|
valkey_url=$(searxng.instance.get_setting valkey.url)
|
|
|
|
if [ "${valkey_url}" = "False" ]; then
|
|
rst_para "valkey DB connector is not configured in your instance"
|
|
else
|
|
rst_para "\
|
|
In your instance, valkey DB connector is configured at:
|
|
|
|
${valkey_url}
|
|
"
|
|
if searxng.instance.exec python -c "from searx import valkeydb; valkeydb.initialize() or exit(42)"; then
|
|
info_msg "SearXNG instance is able to connect valkey DB."
|
|
return
|
|
fi
|
|
fi
|
|
|
|
if ! [[ ${valkey_url} = valkey://localhost:6379/* ]]; then
|
|
err_msg "SearXNG instance can't connect valkey DB / check valkey & your settings"
|
|
return
|
|
fi
|
|
rst_para ".. but this valkey DB is not installed yet."
|
|
|
|
if ask_yn "Do you want to install the valkey DB now?" Yn; then
|
|
searxng.install.valkey
|
|
uWSGI_restart "$SEARXNG_UWSGI_APP"
|
|
fi
|
|
}
|
|
|
|
searxng.install.http.site() {
|
|
|
|
if apache_is_installed; then
|
|
info_msg "Apache is installed on this host."
|
|
if ask_yn "Do you want to install a reverse proxy" Yn; then
|
|
searxng.apache.install
|
|
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" Yn; then
|
|
searxng.nginx.install
|
|
fi
|
|
else
|
|
info_msg "Don't forget to install HTTP site."
|
|
fi
|
|
}
|
|
|
|
searxng.remove.all() {
|
|
local valkey_url
|
|
|
|
rst_title "De-Install SearXNG (service)"
|
|
if ! ask_yn "Do you really want to deinstall SearXNG?"; then
|
|
return
|
|
fi
|
|
|
|
valkey_url=$(searxng.instance.get_setting valkey.url)
|
|
if ! [[ ${valkey_url} = unix://${VALKEY_HOME}/run/valkey.sock* ]]; then
|
|
searxng.remove.valkey
|
|
fi
|
|
|
|
searxng.remove.uwsgi
|
|
drop_service_account "${SERVICE_USER}"
|
|
searxng.remove.settings
|
|
wait_key
|
|
|
|
if service_is_available "${SEARXNG_URL}"; then
|
|
MSG="** Don't forget to remove your public site! (${SEARXNG_URL}) **" wait_key 10
|
|
fi
|
|
}
|
|
|
|
searxng.install.user() {
|
|
rst_title "SearXNG -- install user" section
|
|
echo
|
|
if getent passwd "${SERVICE_USER}" >/dev/null; then
|
|
echo "user already exists"
|
|
return 0
|
|
fi
|
|
|
|
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
|
|
}
|
|
|
|
searxng.install.packages() {
|
|
TITLE="SearXNG -- install packages" pkg_install "${SEARXNG_PACKAGES}"
|
|
}
|
|
|
|
searxng.install.buildhost() {
|
|
TITLE="SearXNG -- install buildhost packages" pkg_install \
|
|
"${SEARXNG_PACKAGES} ${SEARXNG_BUILD_PACKAGES}"
|
|
}
|
|
|
|
searxng.install.clone() {
|
|
rst_title "Clone SearXNG sources" section
|
|
if ! service_account_is_available "${SERVICE_USER}"; then
|
|
die 42 "To clone SearXNG, first install user ${SERVICE_USER}."
|
|
fi
|
|
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 SearXNG sources, user ${SERVICE_USER} hast to be created first"
|
|
return 42
|
|
fi
|
|
if [[ ! $(git show-ref "refs/heads/${GIT_BRANCH}") ]]; then
|
|
warn_msg "missing local branch ${GIT_BRANCH}"
|
|
info_msg "create local branch ${GIT_BRANCH} from start point: origin/${GIT_BRANCH}"
|
|
git branch "${GIT_BRANCH}" "origin/${GIT_BRANCH}"
|
|
fi
|
|
if [[ ! $(git rev-parse --abbrev-ref HEAD) == "${GIT_BRANCH}" ]]; then
|
|
warn_msg "take into account, installing branch $GIT_BRANCH while current branch is $(git rev-parse --abbrev-ref HEAD)"
|
|
fi
|
|
# export SERVICE_HOME
|
|
|
|
# clone repo and add a safe.directory entry to git's system config / see
|
|
# https://github.com/searxng/searxng/issues/1251
|
|
git config --system --add safe.directory "${REPO_ROOT}/.git"
|
|
git_clone "$REPO_ROOT" "${SEARXNG_SRC}" \
|
|
"$GIT_BRANCH" "${SERVICE_USER}"
|
|
git config --system --add safe.directory "${SEARXNG_SRC}"
|
|
|
|
pushd "${SEARXNG_SRC}" >/dev/null
|
|
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
cd "${SEARXNG_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
|
|
}
|
|
|
|
searxng.install.link_src() {
|
|
rst_title "link SearXNG's sources to: $2" chapter
|
|
echo
|
|
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
mv -f "${SEARXNG_SRC}" "${SEARXNG_SRC}.backup"
|
|
ln -s "${2}" "${SEARXNG_SRC}"
|
|
ls -ld /usr/local/searxng/searxng-src
|
|
EOF
|
|
echo
|
|
uWSGI_restart "$SEARXNG_UWSGI_APP"
|
|
}
|
|
|
|
searxng.install.pyenv() {
|
|
rst_title "Create virtualenv (python)" section
|
|
echo
|
|
if [[ ! -f "${SEARXNG_SRC}/manage" ]]; then
|
|
die 42 "To create pyenv for SearXNG, first install searxng-src."
|
|
fi
|
|
info_msg "create pyenv in ${SEARXNG_PYENV}"
|
|
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
rm -rf "${SEARXNG_PYENV}"
|
|
python -m venv "${SEARXNG_PYENV}"
|
|
grep -qFs -- 'source ${SEARXNG_PYENV}/bin/activate' ~/.profile \
|
|
|| echo 'source ${SEARXNG_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 pyyaml
|
|
pip install -U msgspec
|
|
cd ${SEARXNG_SRC}
|
|
pip install --use-pep517 --no-build-isolation -e .
|
|
EOF
|
|
}
|
|
|
|
searxng.remove.pyenv() {
|
|
rst_title "Remove virtualenv (python)" section
|
|
if ! ask_yn "Do you really want to drop ${SEARXNG_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 ${SEARXNG_PYENV}/bin/activate' ~/.profile > ~/.profile.##
|
|
mv ~/.profile.## ~/.profile
|
|
EOF
|
|
rm -rf "${SEARXNG_PYENV}"
|
|
}
|
|
|
|
searxng.install.settings() {
|
|
rst_title "install ${SEARXNG_SETTINGS_PATH}" section
|
|
|
|
if ! [[ -f "${SEARXNG_SRC}/.git/config" ]]; then
|
|
die "Before install settings, first install SearXNG."
|
|
fi
|
|
|
|
mkdir -p "$(dirname "${SEARXNG_SETTINGS_PATH}")"
|
|
|
|
DEFAULT_SELECT=1 \
|
|
install_template --no-eval \
|
|
"${SEARXNG_SETTINGS_PATH}" \
|
|
"${SERVICE_USER}" "${SERVICE_GROUP}"
|
|
|
|
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "root"
|
|
sed -i -e "s/ultrasecretkey/$(openssl rand -hex 16)/g" "${SEARXNG_SETTINGS_PATH}"
|
|
EOF
|
|
}
|
|
|
|
searxng.remove.settings() {
|
|
rst_title "remove ${SEARXNG_SETTINGS_PATH}" section
|
|
if ask_yn "Do you want to delete the SearXNG settings?" Yn; then
|
|
rm -f "${SEARXNG_SETTINGS_PATH}"
|
|
fi
|
|
}
|
|
|
|
searxng.check() {
|
|
rst_title "SearXNG checks" section
|
|
"${SEARXNG_PYENV}/bin/python" "${SEARXNG_SRC}/utils/searxng_check.py"
|
|
}
|
|
|
|
searxng.instance.update() {
|
|
rst_title "Update SearXNG instance"
|
|
rst_para "fetch from $GIT_URL and reset to origin/$GIT_BRANCH"
|
|
tee_stderr 0.3 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
cd ${SEARXNG_SRC}
|
|
git fetch origin "$GIT_BRANCH"
|
|
git reset --hard "origin/$GIT_BRANCH"
|
|
pip install -U pip
|
|
pip install -U setuptools
|
|
pip install -U wheel
|
|
pip install -U pyyaml
|
|
pip install -U msgspec
|
|
pip install -U --use-pep517 --no-build-isolation -e .
|
|
EOF
|
|
rst_para "update instance's settings.yml from ${SEARXNG_SETTINGS_PATH}"
|
|
DEFAULT_SELECT=2 \
|
|
install_template --no-eval \
|
|
"${SEARXNG_SETTINGS_PATH}" \
|
|
"${SERVICE_USER}" "${SERVICE_GROUP}"
|
|
|
|
sudo -H -i <<EOF
|
|
sed -i -e "s/ultrasecretkey/$(openssl rand -hex 16)/g" "${SEARXNG_SETTINGS_PATH}"
|
|
EOF
|
|
uWSGI_restart "${SEARXNG_UWSGI_APP}"
|
|
}
|
|
|
|
searxng.install.uwsgi() {
|
|
rst_title "SearXNG (install uwsgi)"
|
|
install_uwsgi
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
searxng.install.uwsgi.socket
|
|
else
|
|
searxng.install.uwsgi.http
|
|
fi
|
|
}
|
|
|
|
searxng.install.uwsgi.http() {
|
|
rst_para "Install ${SEARXNG_UWSGI_APP} at: http://${SEARXNG_INTERNAL_HTTP}"
|
|
uWSGI_install_app "${SEARXNG_UWSGI_APP}"
|
|
if ! searxng.uwsgi.available; then
|
|
err_msg "URL http://${SEARXNG_INTERNAL_HTTP} not available, check SearXNG & uwsgi setup!"
|
|
fi
|
|
}
|
|
|
|
searxng.install.uwsgi.socket() {
|
|
rst_para "Install ${SEARXNG_UWSGI_APP} using socket at: ${SEARXNG_UWSGI_SOCKET}"
|
|
mkdir -p "$(dirname "${SEARXNG_UWSGI_SOCKET}")"
|
|
chown -R "${SERVICE_USER}:${SERVICE_GROUP}" "$(dirname "${SEARXNG_UWSGI_SOCKET}")"
|
|
|
|
case $DIST_ID-$DIST_VERS in
|
|
fedora-*)
|
|
# Fedora runs uWSGI in emperor-tyrant mode: in Tyrant mode the
|
|
# Emperor will run the vassal using the UID/GID of the vassal
|
|
# configuration file [1] (user and group of the app .ini file).
|
|
# [1] https://uwsgi-docs.readthedocs.io/en/latest/Emperor.html#tyrant-mode-secure-multi-user-hosting
|
|
uWSGI_install_app --variant=socket "${SEARXNG_UWSGI_APP}" "${SERVICE_USER}" "${SERVICE_GROUP}"
|
|
;;
|
|
*)
|
|
uWSGI_install_app --variant=socket "${SEARXNG_UWSGI_APP}"
|
|
;;
|
|
esac
|
|
sleep 5
|
|
if ! searxng.uwsgi.available; then
|
|
err_msg "uWSGI socket not available at: ${SEARXNG_UWSGI_SOCKET}"
|
|
fi
|
|
}
|
|
|
|
searxng.uwsgi.available() {
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
[[ -S "${SEARXNG_UWSGI_SOCKET}" ]]
|
|
exit_val=$?
|
|
if [[ $exit_val = 0 ]]; then
|
|
info_msg "uWSGI socket is located at: ${SEARXNG_UWSGI_SOCKET}"
|
|
fi
|
|
else
|
|
service_is_available "http://${SEARXNG_INTERNAL_HTTP}"
|
|
exit_val=$?
|
|
fi
|
|
return "$exit_val"
|
|
}
|
|
|
|
searxng.remove.uwsgi() {
|
|
rst_title "Remove SearXNG's uWSGI app (${SEARXNG_UWSGI_APP})" section
|
|
echo
|
|
uWSGI_remove_app "${SEARXNG_UWSGI_APP}"
|
|
}
|
|
|
|
searxng.remove.redis() {
|
|
rst_title "SearXNG (remove redis)"
|
|
redis.rmgrp "${SERVICE_USER}"
|
|
redis.remove
|
|
}
|
|
|
|
searxng.install.valkey() {
|
|
rst_title "SearXNG (install valkey)"
|
|
valkey.install
|
|
}
|
|
|
|
searxng.instance.localtest() {
|
|
rst_title "Test SearXNG instance locally" section
|
|
rst_para "Activate debug mode, start a minimal SearXNG " \
|
|
"service and debug a HTTP request/response cycle."
|
|
|
|
if service_is_available "http://${SEARXNG_INTERNAL_HTTP}" &>/dev/null; then
|
|
err_msg "URL/port http://${SEARXNG_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
|
|
echo
|
|
searxng.instance.debug.on
|
|
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
export SEARXNG_SETTINGS_PATH="${SEARXNG_SETTINGS_PATH}"
|
|
cd ${SEARXNG_SRC}
|
|
timeout 10 python searx/webapp.py &
|
|
sleep 3
|
|
curl --location --verbose --head --insecure ${SEARXNG_INTERNAL_HTTP}
|
|
EOF
|
|
echo
|
|
searxng.instance.debug.off
|
|
}
|
|
|
|
searxng.install.http.pre() {
|
|
if ! searxng.uwsgi.available; then
|
|
rst_para "\
|
|
To install uWSGI use::
|
|
|
|
$(basename "$0") install uwsgi
|
|
"
|
|
die 42 "SearXNG's uWSGI app not available"
|
|
fi
|
|
|
|
if ! searxng.instance.exec python -c "from searx import valkeydb; valkeydb.initialize() or exit(42)"; then
|
|
rst_para "\
|
|
The configured valkey DB is not available: If your server is public to the
|
|
internet, you should setup a bot protection to block excessively bot queries.
|
|
Bot protection requires a valkey DB. About bot protection visit the official
|
|
SearXNG documentation and query for the word 'limiter'.
|
|
"
|
|
fi
|
|
}
|
|
|
|
searxng.apache.install() {
|
|
rst_title "Install Apache site ${APACHE_SEARXNG_SITE}"
|
|
rst_para "\
|
|
This installs SearXNG's uWSGI app as apache site. The apache site is located at:
|
|
${APACHE_SITES_AVAILABLE}/${APACHE_SEARXNG_SITE}."
|
|
searxng.install.http.pre
|
|
|
|
if ! apache_is_installed; then
|
|
err_msg "Apache packages are not installed"
|
|
if ! ask_yn "Do you really want to continue and install apache packages?" Yn; then
|
|
return
|
|
else
|
|
FORCE_SELECTION=Y install_apache
|
|
fi
|
|
else
|
|
info_msg "Apache packages are installed [OK]"
|
|
fi
|
|
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
apache_install_site --variant=socket "${APACHE_SEARXNG_SITE}"
|
|
else
|
|
apache_install_site "${APACHE_SEARXNG_SITE}"
|
|
fi
|
|
|
|
if ! service_is_available "${SEARXNG_URL}"; then
|
|
err_msg "Public service at ${SEARXNG_URL} is not available!"
|
|
fi
|
|
}
|
|
|
|
searxng.apache.remove() {
|
|
rst_title "Remove Apache site ${APACHE_SEARXNG_SITE}"
|
|
rst_para "\
|
|
This removes apache site ${APACHE_SEARXNG_SITE}::
|
|
|
|
${APACHE_SITES_AVAILABLE}/${APACHE_SEARXNG_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_SEARXNG_SITE}"
|
|
}
|
|
|
|
searxng.nginx.install() {
|
|
|
|
rst_title "Install nginx site ${NGINX_SEARXNG_SITE}"
|
|
rst_para "\
|
|
This installs SearXNG's uWSGI app as Nginx site. The Nginx site is located at:
|
|
${NGINX_APPS_AVAILABLE}/${NGINX_SEARXNG_SITE} and requires a uWSGI."
|
|
searxng.install.http.pre
|
|
|
|
if ! nginx_is_installed; then
|
|
err_msg "Nginx packages are not installed"
|
|
if ! ask_yn "Do you really want to continue and install Nginx packages?" Yn; then
|
|
return
|
|
else
|
|
FORCE_SELECTION=Y install_nginx
|
|
fi
|
|
else
|
|
info_msg "Nginx packages are installed [OK]"
|
|
fi
|
|
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
nginx_install_app --variant=socket "${NGINX_SEARXNG_SITE}"
|
|
else
|
|
nginx_install_app "${NGINX_SEARXNG_SITE}"
|
|
fi
|
|
|
|
if ! service_is_available "${SEARXNG_URL}"; then
|
|
err_msg "Public service at ${SEARXNG_URL} is not available!"
|
|
fi
|
|
}
|
|
|
|
searxng.nginx.remove() {
|
|
rst_title "Remove Nginx site ${NGINX_SEARXNG_SITE}"
|
|
rst_para "\
|
|
This removes Nginx site ${NGINX_SEARXNG_SITE}::
|
|
|
|
${NGINX_APPS_AVAILABLE}/${NGINX_SEARXNG_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_app "${NGINX_SEARXNG_SITE}"
|
|
}
|
|
|
|
searxng.instance.exec() {
|
|
if ! service_account_is_available "${SERVICE_USER}"; then
|
|
die 42 "can't execute: instance does not exist (missed account ${SERVICE_USER})"
|
|
fi
|
|
sudo -H -i -u "${SERVICE_USER}" \
|
|
SEARXNG_UWSGI_USE_SOCKET="${SEARXNG_UWSGI_USE_SOCKET}" \
|
|
"$@"
|
|
}
|
|
|
|
searxng.instance.self.call() {
|
|
# wrapper to call a function in instance's environment
|
|
info_msg "wrapper: utils/searxng.sh instance _call $*"
|
|
searxng.instance.exec "${SEARXNG_SRC}/utils/searxng.sh" instance _call "$@"
|
|
}
|
|
|
|
searxng.instance.get_setting() {
|
|
searxng.instance.exec python <<EOF
|
|
from searx import get_setting
|
|
print(get_setting('$1'))
|
|
EOF
|
|
}
|
|
|
|
searxng.instance.debug.on() {
|
|
warn_msg "Do not enable debug in a production environment!"
|
|
info_msg "try to enable debug mode ..."
|
|
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
cd ${SEARXNG_SRC}
|
|
sed -i -e "s/debug: false/debug: true/g" "$SEARXNG_SETTINGS_PATH"
|
|
EOF
|
|
uWSGI_restart "$SEARXNG_UWSGI_APP"
|
|
}
|
|
|
|
searxng.instance.debug.off() {
|
|
info_msg "try to disable debug mode ..."
|
|
tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
|
|
cd ${SEARXNG_SRC}
|
|
sed -i -e "s/debug: true/debug: false/g" "$SEARXNG_SETTINGS_PATH"
|
|
EOF
|
|
uWSGI_restart "$SEARXNG_UWSGI_APP"
|
|
}
|
|
|
|
searxng.instance.inspect() {
|
|
rst_title "Inspect SearXNG instance"
|
|
echo
|
|
|
|
searxng.instance.self.call _searxng.instance.inspect
|
|
|
|
local _debug_on
|
|
if ask_yn "Enable SearXNG debug mode?"; then
|
|
searxng.instance.debug.on
|
|
_debug_on=1
|
|
fi
|
|
echo
|
|
|
|
case $DIST_ID-$DIST_VERS in
|
|
ubuntu-* | debian-*)
|
|
# For uWSGI debian uses the LSB init process; for each configuration
|
|
# file new uWSGI daemon instance is started with additional option.
|
|
service uwsgi status "${SERVICE_NAME}"
|
|
;;
|
|
arch-*)
|
|
systemctl --no-pager -l status "uwsgi@${SERVICE_NAME%.*}"
|
|
;;
|
|
fedora-*)
|
|
systemctl --no-pager -l status uwsgi
|
|
;;
|
|
esac
|
|
|
|
echo -e "// 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/${SERVICE_NAME%.*}.log" ;;
|
|
arch-*) journalctl -f -u "uwsgi@${SERVICE_NAME%.*}" ;;
|
|
fedora-*) journalctl -f -u uwsgi ;;
|
|
esac
|
|
done
|
|
|
|
if [[ $_debug_on == 1 ]]; then
|
|
searxng.instance.debug.off
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
_searxng.instance.inspect() {
|
|
searxng.instance.env
|
|
|
|
MSG="${_Green}[${_BCyan}CTRL-C${_Green}] to stop or [${_BCyan}KEY${_Green}] to continue${_creset}"
|
|
|
|
if ! searxng.uwsgi.available; then
|
|
err_msg "SearXNG's uWSGI app not available"
|
|
wait_key
|
|
fi
|
|
if ! service_is_available "${SEARXNG_URL}"; then
|
|
err_msg "Public service at ${SEARXNG_URL} is not available!"
|
|
wait_key
|
|
fi
|
|
}
|
|
|
|
searxng.doc.rst() {
|
|
|
|
local APACHE_SITES_AVAILABLE="/etc/apache2/sites-available"
|
|
local NGINX_APPS_AVAILABLE="/etc/nginx/default.apps-available"
|
|
|
|
local debian="${SEARXNG_PACKAGES_debian}"
|
|
local arch="${SEARXNG_PACKAGES_arch}"
|
|
local fedora="${SEARXNG_PACKAGES_fedora}"
|
|
local debian_build="${SEARXNG_BUILD_PACKAGES_debian}"
|
|
local arch_build="${SEARXNG_BUILD_PACKAGES_arch}"
|
|
local fedora_build="${SEARXNG_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/.$//')"
|
|
|
|
if [[ ${SEARXNG_UWSGI_USE_SOCKET} == true ]]; then
|
|
uwsgi_variant=':socket'
|
|
else
|
|
uwsgi_variant=':socket'
|
|
fi
|
|
|
|
eval "echo \"$(<"${REPO_ROOT}/docs/build-templates/searxng.rst")\""
|
|
|
|
# I use ubuntu-20.04 here to demonstrate that versions are also supported,
|
|
# normally 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 searxng uwsgi-description $DIST_NAME"
|
|
|
|
case $DIST_ID-$DIST_VERS in
|
|
ubuntu-* | debian-*)
|
|
cat <<EOF
|
|
|
|
.. code:: bash
|
|
|
|
# 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}/${SEARXNG_UWSGI_APP}
|
|
enable: sudo -H ln -s ${uWSGI_APPS_AVAILABLE}/${SEARXNG_UWSGI_APP} ${uWSGI_APPS_ENABLED}/
|
|
start: sudo -H service uwsgi start ${SEARXNG_UWSGI_APP%.*}
|
|
restart: sudo -H service uwsgi restart ${SEARXNG_UWSGI_APP%.*}
|
|
stop: sudo -H service uwsgi stop ${SEARXNG_UWSGI_APP%.*}
|
|
disable: sudo -H rm ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
|
|
|
|
EOF
|
|
;;
|
|
arch-*)
|
|
cat <<EOF
|
|
|
|
.. code:: bash
|
|
|
|
# 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}/${SEARXNG_UWSGI_APP}
|
|
enable: sudo -H systemctl enable uwsgi@${SEARXNG_UWSGI_APP%.*}
|
|
start: sudo -H systemctl start uwsgi@${SEARXNG_UWSGI_APP%.*}
|
|
restart: sudo -H systemctl restart uwsgi@${SEARXNG_UWSGI_APP%.*}
|
|
stop: sudo -H systemctl stop uwsgi@${SEARXNG_UWSGI_APP%.*}
|
|
disable: sudo -H systemctl disable uwsgi@${SEARXNG_UWSGI_APP%.*}
|
|
|
|
EOF
|
|
;;
|
|
fedora-* | centos-7)
|
|
cat <<EOF
|
|
|
|
.. code:: bash
|
|
|
|
# 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}/${SEARXNG_UWSGI_APP}
|
|
restart: sudo -H touch ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
|
|
disable: sudo -H rm ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
|
|
|
|
EOF
|
|
;;
|
|
esac
|
|
echo -e ".. END searxng uwsgi-description $DIST_NAME"
|
|
|
|
local _show_cursor="" # prevent from prefix_stdout's trailing show-cursor
|
|
|
|
echo -e "\n.. START searxng uwsgi-appini $DIST_NAME"
|
|
echo ".. code:: bash"
|
|
echo
|
|
eval "echo \"$(<"${TEMPLATES}/${uWSGI_APPS_AVAILABLE}/${SEARXNG_UWSGI_APP}${uwsgi_variant}")\"" | prefix_stdout " "
|
|
echo -e "\n.. END searxng uwsgi-appini $DIST_NAME"
|
|
|
|
echo -e "\n.. START nginx socket"
|
|
echo ".. code:: nginx"
|
|
echo
|
|
eval "echo \"$(<"${TEMPLATES}/${NGINX_APPS_AVAILABLE}/${NGINX_SEARXNG_SITE}:socket")\"" | prefix_stdout " "
|
|
echo -e "\n.. END nginx socket"
|
|
|
|
echo -e "\n.. START nginx http"
|
|
echo ".. code:: nginx"
|
|
echo
|
|
eval "echo \"$(<"${TEMPLATES}/${NGINX_APPS_AVAILABLE}/${NGINX_SEARXNG_SITE}")\"" | prefix_stdout " "
|
|
echo -e "\n.. END nginx http"
|
|
|
|
echo -e "\n.. START apache socket"
|
|
echo ".. code:: apache"
|
|
echo
|
|
eval "echo \"$(<"${TEMPLATES}/${APACHE_SITES_AVAILABLE}/${APACHE_SEARXNG_SITE}:socket")\"" | prefix_stdout " "
|
|
echo -e "\n.. END apache socket"
|
|
|
|
echo -e "\n.. START apache http"
|
|
echo ".. code:: apache"
|
|
echo
|
|
eval "echo \"$(<"${TEMPLATES}/${APACHE_SITES_AVAILABLE}/${APACHE_SEARXNG_SITE}")\"" | prefix_stdout " "
|
|
echo -e "\n.. END apache http"
|
|
)
|
|
done
|
|
|
|
}
|
|
|
|
# ----------------------------------------------------------------------------
|
|
main "$@"
|
|
# ----------------------------------------------------------------------------
|